cmd/hub/aws/s3.go (124 lines of code) (raw):

// Copyright (c) 2022 EPAM Systems, Inc. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package aws import ( "bytes" "fmt" "io" "log" "net/url" "os" "time" awsaws "github.com/aws/aws-sdk-go/aws" awss3 "github.com/aws/aws-sdk-go/service/s3" "github.com/epam/hubctl/cmd/hub/config" ) var ( bucketRegion = make(map[string]string) regionS3 = make(map[string]*awss3.S3) ) func awsBucketS3(bucket string) (*awss3.S3, error) { region, err := awsBucketRegion(bucket) if err != nil { return nil, err } return awsS3(region) } func awsBucketRegion(bucket string) (string, error) { if region, exist := bucketRegion[bucket]; exist { return region, nil } s3, err := awsS3(config.AwsRegion) if err != nil { return "", err } location, err := s3.GetBucketLocation( &awss3.GetBucketLocationInput{ Bucket: &bucket, }) if err != nil { return "", fmt.Errorf("Unable to determine AWS bucket `%s` region: %v", bucket, err) } region := "us-east-1" if location.LocationConstraint != nil && *location.LocationConstraint != "" { region = *location.LocationConstraint } if config.Debug { log.Printf("S3 bucket `%s` region is %s", bucket, region) } bucketRegion[bucket] = region return region, nil } func awsS3(region string) (*awss3.S3, error) { session, err := Session(region, "S3") if err != nil { return nil, err } s3 := awss3.New(session) regionS3[region] = s3 return s3, nil } func StatS3(s3path string) (int64, time.Time, error) { location, err := url.Parse(s3path) if err != nil { return 0, time.Time{}, err } s3, err := awsBucketS3(location.Host) if err != nil { return 0, time.Time{}, err } head, err := s3.HeadObject( &awss3.HeadObjectInput{ Bucket: &location.Host, Key: &location.Path, }) if err != nil { if IsNotFound(err) { return 0, time.Time{}, os.ErrNotExist } return 0, time.Time{}, fmt.Errorf("Failed to HEAD S3 object `%s`: %v\n\t%s", s3path, err, optionsHelp) } return *head.ContentLength, *head.LastModified, nil } func ReadS3(s3path string) ([]byte, error) { location, err := url.Parse(s3path) if err != nil { return nil, err } s3, err := awsBucketS3(location.Host) if err != nil { return nil, err } obj, err := s3.GetObject( &awss3.GetObjectInput{ Bucket: &location.Host, Key: &location.Path, }) if err != nil { return nil, fmt.Errorf("Failed to GET S3 object `%s`: %v\n\t%s", s3path, err, optionsHelp) } data, err := io.ReadAll(obj.Body) if err != nil { return nil, fmt.Errorf("Failed to read S3 object `%s`: %v", s3path, err) } obj.Body.Close() return data, nil } func WriteS3(s3path string, body []byte) error { location, err := url.Parse(s3path) if err != nil { return err } s3, err := awsBucketS3(location.Host) if err != nil { return err } _, err = s3.PutObject( &awss3.PutObjectInput{ Body: awsaws.ReadSeekCloser(bytes.NewReader(body)), Bucket: &location.Host, Key: &location.Path, }) if err != nil { return fmt.Errorf("Failed to PUT S3 object `%s`: %v\n\t%s", s3path, err, optionsHelp) } return nil }