diff --git a/batch/batch.go b/batch/batch.go index 2cc29fcbe204370130aef3fbc19ddbefa20b5064..7bc147de7c24ceabc0771c04fbeb5c6f91581392 100644 --- a/batch/batch.go +++ b/batch/batch.go @@ -1,17 +1,19 @@ package batch import ( + "context" "encoding/json" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/batch" + "io" + "time" + + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/batch" + "github.com/aws/aws-sdk-go-v2/service/batch/types" "github.com/go-resty/resty/v2" "github.com/google/uuid" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/logs" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/s3" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/utils" - "io" - "time" ) const ( @@ -50,14 +52,12 @@ func SubmitJob(batchJob BatchJob) error { return nil } - options := session.Options{ - Config: aws.Config{ - Region: utils.ValueToPointer("af-south-1"), - }, + cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("af-south-1")) + if err != nil { + return err } - sess, err := session.NewSessionWithOptions(options) - batchClient := batch.New(sess) + batchClient := batch.NewFromConfig(cfg) if batchJob.Name == nil { id := uuid.New() @@ -70,12 +70,12 @@ func SubmitJob(batchJob BatchJob) error { return err } - command := []*string{ - utils.ValueToPointer(binaryPath), - batchJob.Name, + command := []string{ + binaryPath, + utils.PointerToValue(batchJob.Name), } - environmentOverwrite := []*batch.KeyValuePair{{ + environmentOverwrite := []types.KeyValuePair{{ Name: utils.ValueToPointer("BATCH_MESSAGE_TYPE"), Value: utils.ValueToPointer(string(BatchJobMessageTypeS3)), }, @@ -85,12 +85,12 @@ func SubmitJob(batchJob BatchJob) error { JobDefinition: utils.ValueToPointer(batchJob.FullJobDefinition), JobName: batchJob.Name, JobQueue: utils.ValueToPointer(batchJob.FullJobQueue), - ContainerOverrides: &batch.ContainerOverrides{ + ContainerOverrides: &types.ContainerOverrides{ Command: command, Environment: environmentOverwrite, }, } - _, err = batchClient.SubmitJob(input) + _, err = batchClient.SubmitJob(context.TODO(), input) if err != nil { return err } @@ -104,7 +104,7 @@ func uploadMessageToS3(batchJob BatchJob) error { } // Upload message - _, err = s3.GetSession(batchJob.IsDebug).UploadWithSettingsRevised(jobBytes, batchJob.MessagesBucketName, s3.S3UploadSettings{ + _, err = s3.GetClient(batchJob.IsDebug).UploadWithSettingsRevised(jobBytes, batchJob.MessagesBucketName, s3.S3UploadSettings{ FileName: utils.PointerToValue(batchJob.Name), }) if err != nil { @@ -116,7 +116,7 @@ func uploadMessageToS3(batchJob BatchJob) error { func RetrieveMessageFromS3(filename string, messagesBucketName string, isDebug bool) ([]byte, error) { // get the file contents - rawObject, err := s3.GetSession(isDebug).GetObject(messagesBucketName, filename, isDebug) + rawObject, err := s3.GetClient(isDebug).GetObject(messagesBucketName, filename, isDebug) if err != nil { return []byte{}, err } diff --git a/errors/errors.go b/errors/errors.go index 0eae331099ed9dd70d372bd1dce4f895aa2eda38..e483e8b0f49775247c059f8047f82dba5405a5fe 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -1,8 +1,10 @@ package errors import ( + "errors" "fmt" - "github.com/aws/aws-sdk-go/aws/awserr" + + "github.com/aws/smithy-go" pkg_errors "github.com/pkg/errors" ) @@ -127,8 +129,9 @@ func AWSErrorExceptionCode(err error) string { return "" } - if awsError, ok := err.(awserr.Error); ok { - return awsError.Code() + var apiErr smithy.APIError + if errors.As(err, &apiErr) { + return apiErr.ErrorCode() } return "" } @@ -138,8 +141,9 @@ func AWSErrorWithoutExceptionCode(err error) error { return nil } - if awsError, ok := err.(awserr.Error); ok { - return Error(awsError.Message()) + var apiErr smithy.APIError + if errors.As(err, &apiErr) { + return Error(apiErr.ErrorMessage()) } return err } @@ -154,3 +158,7 @@ type Description struct { type stackTracer interface { StackTrace() pkg_errors.StackTrace } + +func As(err error, target any) bool { + return errors.As(err, target) +} diff --git a/go.mod b/go.mod index 3078df486d1002222294654ddc48ae996090ae55..4713e000e70dc236794b7cfef22b8ae8953eb5ea 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,16 @@ require ( github.com/MindscapeHQ/raygun4go v1.1.1 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/aws/aws-lambda-go v1.26.0 - github.com/aws/aws-sdk-go v1.44.180 + github.com/aws/aws-sdk-go-v2 v1.27.1 + github.com/aws/aws-sdk-go-v2/config v1.27.10 + github.com/aws/aws-sdk-go-v2/credentials v1.17.10 + github.com/aws/aws-sdk-go-v2/service/apigatewaymanagementapi v1.19.9 + github.com/aws/aws-sdk-go-v2/service/batch v1.36.1 + github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6 + github.com/aws/aws-sdk-go-v2/service/sqs v1.31.4 github.com/aws/aws-secretsmanager-caching-go v1.1.0 + github.com/aws/smithy-go v1.20.2 github.com/dimuska139/go-email-normalizer/v2 v2.0.0 github.com/dlsniper/debugger v0.6.0 github.com/go-pg/pg/v10 v10.10.6 @@ -33,6 +41,20 @@ require ( ) require ( + github.com/aws/aws-sdk-go v1.44.180 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.20.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/go-errors/errors v1.4.1 // indirect diff --git a/go.sum b/go.sum index 23b6fdeeddde3ebd4f5f365881ddec3accbb5707..8bb29d35362e77708cc7f003da98953688d48343 100644 --- a/go.sum +++ b/go.sum @@ -12,19 +12,63 @@ github.com/aws/aws-sdk-go v1.19.23/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi github.com/aws/aws-sdk-go v1.44.180 h1:VLZuAHI9fa/3WME5JjpVjcPCNfpGHVMiHx8sLHWhMgI= github.com/aws/aws-sdk-go v1.44.180/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.27.1 h1:xypCL2owhog46iFxBKKpBcw+bPTX/RJzwNj8uSilENw= +github.com/aws/aws-sdk-go-v2 v1.27.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg= github.com/aws/aws-sdk-go-v2/config v1.18.8/go.mod h1:5XCmmyutmzzgkpk/6NYTjeWb6lgo9N170m1j6pQkIBs= +github.com/aws/aws-sdk-go-v2/config v1.27.10 h1:PS+65jThT0T/snC5WjyfHHyUgG+eBoupSDV+f838cro= +github.com/aws/aws-sdk-go-v2/config v1.27.10/go.mod h1:BePM7Vo4OBpHreKRUMuDXX+/+JWP38FLkzl5m27/Jjs= github.com/aws/aws-sdk-go-v2/credentials v1.13.8/go.mod h1:lVa4OHbvgjVot4gmh1uouF1ubgexSCN92P6CJQpT0t8= +github.com/aws/aws-sdk-go-v2/credentials v1.17.10 h1:qDZ3EA2lv1KangvQB6y258OssCHD0xvaGiEDkG4X/10= +github.com/aws/aws-sdk-go-v2/credentials v1.17.10/go.mod h1:6t3sucOaYDwDssHQa0ojH1RpmVmF5/jArkye1b2FKMI= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21/go.mod h1:ugwW57Z5Z48bpvUyZuaPy4Kv+vEfJWnIrky7RmkBvJg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.8 h1:RnLB7p6aaFMRfyQkD6ckxR7myCC9SABIqSz4czYUUbU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.8/go.mod h1:XH7dQJd+56wEbP1I4e4Duo+QhSMxNArE8VP7NuUOTeM= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.8 h1:jzApk2f58L9yW9q1GEab3BMMFWUkkiZhyrRUtbwUbKU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.8/go.mod h1:WqO+FftfO3tGePUtQxPXM6iODVfqMwsVMgTbG/ZXIdQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28/go.mod h1:yRZVr/iT0AqyHeep00SZ4YfBAKojXz08w3XMBscdi0c= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5 h1:81KE7vaZzrl7yHBYHVEzYB8sypz11NMOZ40YlWvPxsU= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5/go.mod h1:LIt2rg7Mcgn09Ygbdh/RdIm0rQ+3BNkbP1gyVMFtRK0= +github.com/aws/aws-sdk-go-v2/service/apigatewaymanagementapi v1.19.9 h1:X1A2bnzBrB5uu+DzRTfDBwl+VsH7fCJmQgnGIk3BkKY= +github.com/aws/aws-sdk-go-v2/service/apigatewaymanagementapi v1.19.9/go.mod h1:f7D1hvCXZ4hEWk1tVgUOJp6QN6poeDMqVqPw4B/sglE= +github.com/aws/aws-sdk-go-v2/service/batch v1.36.1 h1:OY9+Dt4FkK6q2VHKAB8zY4nEKOhkziVOtxCPnS94leM= +github.com/aws/aws-sdk-go-v2/service/batch v1.36.1/go.mod h1:JuPGVm7DzXD73vZBQsZwlDzoJeZewN08swLBGiU47K8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7 h1:ZMeFZ5yk+Ek+jNr1+uwCd2tG89t6oTS5yVWpa6yy2es= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7/go.mod h1:mxV05U+4JiHqIpGqqYXOHLPKUC6bDXC44bsUhNjOEwY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21/go.mod h1:lRToEJsn+DRA9lW4O9L9+/3hjTkUzlzyzHqn8MTds5k= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 h1:f9RyWNtS8oH7cZlbn+/JNPpjUk5+5fLd5lM9M0i49Ys= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5/go.mod h1:h5CoMZV2VF297/VLhRhO1WF+XYWOzXo+4HsObA4HjBQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1 h1:6cnno47Me9bRykw9AEv9zkXE+5or7jz8TsskTTccbgc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1/go.mod h1:qmdkIIAC+GCLASF7R2whgNrJADz0QZPX+Seiw/i4S3o= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6 h1:TIOEjw0i2yyhmhRry3Oeu9YtiiHWISZ6j/irS1W3gX4= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6/go.mod h1:3Ba++UwWd154xtP4FRX5pUK3Gt4up5sDHCve6kVfE+g= +github.com/aws/aws-sdk-go-v2/service/sqs v1.31.4 h1:mE2ysZMEeQ3ulHWs4mmc4fZEhOfeY1o6QXAfDqjbSgw= +github.com/aws/aws-sdk-go-v2/service/sqs v1.31.4/go.mod h1:lCN2yKnj+Sp9F6UzpoPPTir+tSaC9Jwf6LcmTqnXFZw= github.com/aws/aws-sdk-go-v2/service/sso v1.12.0/go.mod h1:wo/B7uUm/7zw/dWhBJ4FXuw1sySU5lyIhVg1Bu2yL9A= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.4 h1:WzFol5Cd+yDxPAdnzTA5LmpHYSWinhmSj4rQChV0ee8= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.4/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.0/go.mod h1:TZSH7xLO7+phDtViY/KUp9WGCJMQkLJ/VpgkTFd5gh8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak= github.com/aws/aws-sdk-go-v2/service/sts v1.18.0/go.mod h1:+lGbb3+1ugwKrNTWcf2RT05Xmp543B06zDFTwiTLp7I= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw= github.com/aws/aws-secretsmanager-caching-go v1.1.0 h1:vcV94XGJ9KouXKYBTMqgrBw96Tae8JKLmoUZ5SbaXNo= github.com/aws/aws-secretsmanager-caching-go v1.1.0/go.mod h1:wahQpJP1dZKMqjGFAjGCqilHkTlN0zReGWocPLbXmxg= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= diff --git a/handler_utils/request.go b/handler_utils/request.go index ac13d59ee7dacbb6d98c2110c7f13d9bc91a5240..ef101c40b64023109ad7da2603f4dad2509117b4 100644 --- a/handler_utils/request.go +++ b/handler_utils/request.go @@ -3,15 +3,19 @@ package handler_utils import ( "bytes" "context" - "github.com/aws/aws-sdk-go/aws/credentials" - v4 "github.com/aws/aws-sdk-go/aws/signer/v4" - "github.com/go-resty/resty/v2" + "crypto/sha256" + "encoding/hex" "io" "net/http" "os" "strings" "time" + "github.com/aws/aws-sdk-go-v2/aws" + v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/go-resty/resty/v2" + "github.com/aws/aws-lambda-go/lambdacontext" ) @@ -69,9 +73,29 @@ func SignAWSRestyClient(client *resty.Client, accessKeyID, secretAccessKey strin // SignAWSRequest wraps and executes http.NewRequest and adds a sig version 4 signature for AWS API Gateway func SignAWSHttpRequest(request *http.Request, accessKeyID, secretAccessKey string, bodySeeker io.ReadSeeker) error { + credsCache := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, "")) + creds, err := credsCache.Retrieve(request.Context()) + if err != nil { + return err + } + + payload, err := io.ReadAll(request.Body) + if err != nil { + return err + } + payloadHash := sha256.Sum256(payload) + hexEncodedPayloadHash := hex.EncodeToString(payloadHash[:]) + // Use AWS SDK to sign the request for API gateway, i.e. execute-api, and the current region - _, err := v4.NewSigner(credentials.NewStaticCredentials(accessKeyID, secretAccessKey, "")). - Sign(request, bodySeeker, "execute-api", os.Getenv("AWS_REGION"), time.Now()) + err = v4.NewSigner(). + SignHTTP(request.Context(), + creds, + request, + hexEncodedPayloadHash, + "execute-api", + os.Getenv("AWS_REGION"), + time.Now(), + ) if err != nil { return err } diff --git a/handler_utils/sqs.go b/handler_utils/sqs.go index a77f1d8841b75202e41e7af02bce205d838dd804..f34bbfb0ccef4d9ca30c1e0fc5fc7aa8ed02d08f 100644 --- a/handler_utils/sqs.go +++ b/handler_utils/sqs.go @@ -30,13 +30,13 @@ func ValidateSQSEndpoints(endpoints map[string]interface{}) (map[string]interfac return endpoints, nil } -func GetRecord(s3Session *s3.SessionWithHelpers, bucket string, message events.SQSMessage, recordType reflect.Type) (interface{}, error) { +func GetRecord(s3Client *s3.ClientWithHelpers, bucket string, message events.SQSMessage, recordType reflect.Type) (interface{}, error) { recordValuePtr := reflect.New(recordType) // Check if message body should be retrieved from S3 if messageAttribute, ok := message.MessageAttributes[sqs.SQSMessageOnS3Key]; ok && messageAttribute.StringValue != nil && *messageAttribute.StringValue == "true" { - messageBytes, err := sqs.RetrieveMessageFromS3(s3Session, bucket, message.Body) + messageBytes, err := sqs.RetrieveMessageFromS3(s3Client, bucket, message.Body) if err != nil { return nil, errors.Wrapf(err, "failed to get sqs message body from s3") } diff --git a/oauth/oauth.go b/oauth/oauth.go index d0c4e1d085c93e16eb26f564e073e07ddd50251c..a0e9fff37d4d5e42abb9306eb911ee18feba08ed 100644 --- a/oauth/oauth.go +++ b/oauth/oauth.go @@ -1,13 +1,14 @@ package oauth import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/google/uuid" - "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/encryption" "net/url" "strconv" "strings" "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/google/uuid" + "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/encryption" ) type Oauth1 struct { diff --git a/s3/s3.go b/s3/s3.go index 7d41422739e0f2d4049e7de7964be89c9aca821b..509549a60f8f2764034748f7c1cd6ac908639b40 100644 --- a/s3/s3.go +++ b/s3/s3.go @@ -2,23 +2,26 @@ package s3 import ( "bytes" + "context" "encoding/binary" "fmt" - "github.com/aws/aws-sdk-go/aws/credentials" - "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/secrets_manager" "net/url" "os" "path" "strings" "time" - "github.com/aws/aws-sdk-go/aws/awserr" - "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/secrets_manager" - "github.com/aws/aws-sdk-go/aws/session" + std_errors "errors" + + "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/google/uuid" ) @@ -82,14 +85,14 @@ const ( ) var ( - sessions = map[string]*SessionWithHelpers{} + clients = map[string]*ClientWithHelpers{} ) -type SessionWithHelpers struct { - S3Session *s3.S3 +type ClientWithHelpers struct { + S3Client *s3.Client } -func GetSession(isDebug bool, region ...string) *SessionWithHelpers { +func GetClient(isDebug bool, region ...string) *ClientWithHelpers { s3Region := os.Getenv("AWS_REGION") // Set custom region @@ -97,46 +100,41 @@ func GetSession(isDebug bool, region ...string) *SessionWithHelpers { s3Region = region[0] } - // Check if session exists for region, if it does return it - if s3Session, ok := sessions[s3Region]; ok { - return s3Session + // Check if client exists for region, if it does return it + if s3Client, ok := clients[s3Region]; ok { + return s3Client } - // Setup session - s3Credentials := GetS3SessionCredentials(isDebug) - options := session.Options{ - Config: aws.Config{ - Region: aws.String(s3Region), - Credentials: s3Credentials, - }, - } - - sess, err := session.NewSessionWithOptions(options) + cfg, err := config.LoadDefaultConfig(context.TODO(), + config.WithRegion(s3Region), + config.WithCredentialsProvider(GetS3CredentialsProvider(isDebug)), + ) if err != nil { return nil } - s3Session := NewSession(sess) - sessions[s3Region] = s3Session - return s3Session + s3Client := NewClient(cfg) + + clients[s3Region] = s3Client + return s3Client } -func GetS3SessionCredentials(isDebug bool) *credentials.Credentials { +func GetS3CredentialsProvider(isDebug bool) credentials.StaticCredentialsProvider { secretID := os.Getenv("S3_SECRET_ID") - s3Credentials, err := secrets_manager.GetS3UploadCredentials(secretID, isDebug) + s3CredentialsProvider, err := secrets_manager.GetS3UploadCredentialsProvider(secretID, isDebug) if err != nil { - return nil + return credentials.StaticCredentialsProvider{} } - return s3Credentials + return s3CredentialsProvider } -func NewSession(session *session.Session) *SessionWithHelpers { - return &SessionWithHelpers{ - S3Session: s3.New(session), +func NewClient(cfg aws.Config) *ClientWithHelpers { + return &ClientWithHelpers{ + S3Client: s3.NewFromConfig(cfg), } } -func (s SessionWithHelpers) Upload(data []byte, bucket, fileName string, metadata *map[string]*string) (*s3.PutObjectOutput, error) { +func (s ClientWithHelpers) Upload(data []byte, bucket, fileName string, metadata *map[string]string) (*s3.PutObjectOutput, error) { mimeType := getTypeForFilename(fileName) putInput := &s3.PutObjectInput{ Bucket: aws.String(bucket), @@ -149,7 +147,7 @@ func (s SessionWithHelpers) Upload(data []byte, bucket, fileName string, metadat putInput.Metadata = *metadata } - response, err := s.S3Session.PutObject(putInput) + response, err := s.S3Client.PutObject(context.TODO(), putInput) if err != nil { return nil, err } @@ -157,7 +155,7 @@ func (s SessionWithHelpers) Upload(data []byte, bucket, fileName string, metadat return response, nil } -func (s SessionWithHelpers) UploadWithSettings(data []byte, bucket, fileName string, settings S3UploadSettings) (string, error) { +func (s ClientWithHelpers) UploadWithSettings(data []byte, bucket, fileName string, settings S3UploadSettings) (string, error) { if settings.MimeType == "" { settings.MimeType = getTypeForFilename(fileName) } @@ -175,7 +173,7 @@ func (s SessionWithHelpers) UploadWithSettings(data []byte, bucket, fileName str putInput.Expires = &expiry } - _, err := s.S3Session.PutObject(putInput) + _, err := s.S3Client.PutObject(context.TODO(), putInput) if err != nil { return "", err } @@ -201,7 +199,7 @@ func (s SessionWithHelpers) UploadWithSettings(data []byte, bucket, fileName str } // UploadWithSettingsRevised can be renamed to UploadWithSettings once original function has been deprecated. -func (s SessionWithHelpers) UploadWithSettingsRevised(data []byte, bucket string, settings S3UploadSettings) (S3UploadResponse, error) { +func (s ClientWithHelpers) UploadWithSettingsRevised(data []byte, bucket string, settings S3UploadSettings) (S3UploadResponse, error) { var fullFileName, uploadUrl string uuidString := "" @@ -244,7 +242,7 @@ func (s SessionWithHelpers) UploadWithSettingsRevised(data []byte, bucket string putInput.Expires = &expiry } - _, err := s.S3Session.PutObject(putInput) + _, err := s.S3Client.PutObject(context.TODO(), putInput) if err != nil { return S3UploadResponse{}, err } @@ -283,7 +281,7 @@ func (s SessionWithHelpers) UploadWithSettingsRevised(data []byte, bucket string return response, nil } -func (s SessionWithHelpers) UploadWith1DayExpiry(data []byte, bucket, fileName string, mimeType MIMEType, shouldDownloadInsteadOfOpen bool) (string, error) { +func (s ClientWithHelpers) UploadWith1DayExpiry(data []byte, bucket, fileName string, mimeType MIMEType, shouldDownloadInsteadOfOpen bool) (string, error) { if mimeType == "" { mimeType = getTypeForFilename(fileName) } @@ -303,7 +301,16 @@ func (s SessionWithHelpers) UploadWith1DayExpiry(data []byte, bucket, fileName s } // GetSignedDownloadURL gets a signed download URL for the duration. If scv is nil, a new session will be created. -func (s SessionWithHelpers) GetSignedDownloadURL(bucket string, fileName string, duration time.Duration, headers ...map[string]string) (string, error) { +func (s ClientWithHelpers) GetSignedDownloadURL(bucket string, fileName string, duration time.Duration, headers ...map[string]string) (string, error) { + fileExists, err := s.FileExists(bucket, fileName) + if err != nil { + return "", err + } + + if !fileExists { + return "", errors.Error("File does not exist") + } + getInput := &s3.GetObjectInput{ Bucket: aws.String(bucket), Key: aws.String(fileName), @@ -315,33 +322,38 @@ func (s SessionWithHelpers) GetSignedDownloadURL(bucket string, fileName string, } } - getRequest, _ := s.S3Session.GetObjectRequest(getInput) + presignClient := s3.NewPresignClient(s.S3Client) + getRequest, err := presignClient.PresignGetObject(context.TODO(), getInput, func(po *s3.PresignOptions) { + po.Expires = duration + }) - fileExists, err := s.FileExists(bucket, fileName) - if err != nil { - return "", err - } + return getRequest.URL, err +} - if !fileExists { - return "", errors.Error("File does not exist") +// GetSignedUploadURL gets a signed upload URL for the duration. If scv is nil, a new session will be created. +func (s ClientWithHelpers) GetSignedUploadURL(bucket string, fileName string, duration time.Duration) (string, error) { + putInput := &s3.PutObjectInput{ + Bucket: aws.String(bucket), + Key: aws.String(fileName), } - return getRequest.Presign(duration) + presignClient := s3.NewPresignClient(s.S3Client) + putRequest, err := presignClient.PresignPutObject(context.TODO(), putInput, func(po *s3.PresignOptions) { + po.Expires = duration + }) + + return putRequest.URL, err } -func (s SessionWithHelpers) FileExists(bucket string, fileName string) (bool, error) { - _, err := s.S3Session.HeadObject(&s3.HeadObjectInput{ +func (s ClientWithHelpers) FileExists(bucket string, fileName string) (bool, error) { + _, err := s.S3Client.HeadObject(context.TODO(), &s3.HeadObjectInput{ Bucket: aws.String(bucket), Key: aws.String(fileName), }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case "NotFound": // s3.ErrCodeNoSuchKey does not work, aws is missing this error code so we hardwire a string - return false, nil - default: - return false, err - } + var notFoundErr *types.NotFound + if std_errors.As(err, ¬FoundErr) { + return false, nil } return false, err } @@ -349,7 +361,7 @@ func (s SessionWithHelpers) FileExists(bucket string, fileName string) (bool, er } // UploadWithFileExtension will upload a file to S3 and return a standard S3UploadResponse. -func (s SessionWithHelpers) UploadWithFileExtension(data []byte, bucket, filePrefix, fileExt string, mimeType MIMEType) (*S3UploadResponse, error) { +func (s ClientWithHelpers) UploadWithFileExtension(data []byte, bucket, filePrefix, fileExt string, mimeType MIMEType) (*S3UploadResponse, error) { fileName := fmt.Sprintf("%s_%s.%s", filePrefix, uuid.New().String(), fileExt) duration := 24 * time.Hour @@ -391,24 +403,24 @@ func getTypeForFilename(f string) MIMEType { return MIMETypeDefault } -func (s SessionWithHelpers) GetObject(bucket string, fileName string, isDebug bool) (*s3.GetObjectOutput, error) { +func (s ClientWithHelpers) GetObject(bucket string, fileName string, isDebug bool) (*s3.GetObjectOutput, error) { getInput := &s3.GetObjectInput{ Bucket: aws.String(bucket), Key: aws.String(fileName), } - getObjectOutput, err := s.S3Session.GetObject(getInput) + getObjectOutput, err := s.S3Client.GetObject(context.TODO(), getInput) if err != nil { return nil, err } return getObjectOutput, nil } -func (s SessionWithHelpers) GetObjectMetadata(bucket string, fileName string, isDebug bool) (map[string]*string, error) { +func (s ClientWithHelpers) GetObjectMetadata(bucket string, fileName string, isDebug bool) (map[string]string, error) { headObjectInput := &s3.HeadObjectInput{ Bucket: aws.String(bucket), Key: aws.String(fileName), } - headObjectOutput, err := s.S3Session.HeadObject(headObjectInput) + headObjectOutput, err := s.S3Client.HeadObject(context.TODO(), headObjectInput) if err != nil { return nil, err } @@ -416,7 +428,7 @@ func (s SessionWithHelpers) GetObjectMetadata(bucket string, fileName string, is } // MoveObjectBucketToBucket - Move object from one S3 bucket to another -func (s SessionWithHelpers) MoveObjectBucketToBucket(sourceBucket string, destinationBucket string, sourceFileName string, destinationFileName string, settings S3UploadSettings) error { +func (s ClientWithHelpers) MoveObjectBucketToBucket(sourceBucket string, destinationBucket string, sourceFileName string, destinationFileName string, settings S3UploadSettings) error { err := s.CopyObjectBucketToBucket(sourceBucket, destinationBucket, sourceFileName, destinationFileName, settings) if err != nil { @@ -432,7 +444,7 @@ func (s SessionWithHelpers) MoveObjectBucketToBucket(sourceBucket string, destin } // CopyObjectBucketToBucket - Copy an object from one S3 bucket to another -func (s SessionWithHelpers) CopyObjectBucketToBucket(sourceBucket string, destinationBucket string, sourceFileName string, destinationFilename string, settings S3UploadSettings) error { +func (s ClientWithHelpers) CopyObjectBucketToBucket(sourceBucket string, destinationBucket string, sourceFileName string, destinationFilename string, settings S3UploadSettings) error { // copy the file copySource := url.QueryEscape(sourceBucket + "/" + sourceFileName) copyObjectInput := &s3.CopyObjectInput{ @@ -446,13 +458,14 @@ func (s SessionWithHelpers) CopyObjectBucketToBucket(sourceBucket string, destin copyObjectInput.Expires = &expiry } - _, err := s.S3Session.CopyObject(copyObjectInput) + _, err := s.S3Client.CopyObject(context.TODO(), copyObjectInput) if err != nil { return err } // wait to see if the file copied successfully - err = s.S3Session.WaitUntilObjectExists(&s3.HeadObjectInput{Bucket: aws.String(destinationBucket), Key: aws.String(destinationFilename)}) + waiter := s3.NewObjectExistsWaiter(s.S3Client) + err = waiter.Wait(context.TODO(), &s3.HeadObjectInput{Bucket: aws.String(destinationBucket), Key: aws.String(destinationFilename)}, 5*time.Minute) if err != nil { return err } @@ -461,22 +474,20 @@ func (s SessionWithHelpers) CopyObjectBucketToBucket(sourceBucket string, destin } // DeleteObjectFromBucket - Delete an object from an S3 bucket -func (s SessionWithHelpers) DeleteObjectFromBucket(bucket string, fileName string) error { +func (s ClientWithHelpers) DeleteObjectFromBucket(bucket string, fileName string) error { // delete the file deleteObjectInput := &s3.DeleteObjectInput{ Bucket: aws.String(bucket), Key: aws.String(fileName), } - _, err := s.S3Session.DeleteObject(deleteObjectInput) + _, err := s.S3Client.DeleteObject(context.TODO(), deleteObjectInput) if err != nil { return err } // wait to see if the file deleted successfully - err = s.S3Session.WaitUntilObjectNotExists(&s3.HeadObjectInput{ - Bucket: aws.String(bucket), // the bucket we are deleting from - Key: aws.String(fileName), // the filename we are deleting - }) + waiter := s3.NewObjectNotExistsWaiter(s.S3Client) + err = waiter.Wait(context.TODO(), &s3.HeadObjectInput{Bucket: aws.String(bucket), Key: aws.String(fileName)}, 5*time.Minute) if err != nil { return err } diff --git a/secrets_manager/secrets_manager.go b/secrets_manager/secrets_manager.go index 85f4bdaedcc12191cb60d6c393fe0a13515618a3..0f41ef0db3b570e45172508a6dc34c44a86a9929 100644 --- a/secrets_manager/secrets_manager.go +++ b/secrets_manager/secrets_manager.go @@ -1,19 +1,21 @@ package secrets_manager import ( + "context" "encoding/base64" "encoding/json" - credentials2 "github.com/aws/aws-sdk-go/aws/credentials" + "errors" "os" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/logs" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/struct_utils" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/secretsmanager" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/secretsmanager" "github.com/aws/aws-secretsmanager-caching-go/secretcache" + "github.com/aws/smithy-go" ) type DatabaseCredentials struct { @@ -26,17 +28,12 @@ type DatabaseCredentials struct { ReadOnlyHost string `json:"aurora_read_only_host"` } -type S3UploadCredentials struct { - AccessKeyID string `json:"accessKeyID"` - SecretKey string `json:"secretKey"` -} - var ( secretCache, _ = secretcache.New() secretManagerRegion = "af-south-1" ) -var secretManagerSession *secretsmanager.SecretsManager +var secretManagerClient *secretsmanager.Client func GetDatabaseCredentials(secretID string, isDebug bool) (DatabaseCredentials, error) { secret, _ := GetSecret(secretID, isDebug) @@ -48,54 +45,60 @@ func GetDatabaseCredentials(secretID string, isDebug bool) (DatabaseCredentials, return credentials, nil } -func GetS3UploadCredentials(secretID string, isDebug bool) (*credentials2.Credentials, error) { +func GetS3UploadCredentialsProvider(secretID string, isDebug bool) (credentials.StaticCredentialsProvider, error) { secret, _ := GetSecret(secretID, isDebug) - var credentials S3UploadCredentials - err := struct_utils.UnmarshalJSON([]byte(secret), &credentials) + var secretValue map[string]string + err := struct_utils.UnmarshalJSON([]byte(secret), &secretValue) if err != nil { - return nil, err + return credentials.StaticCredentialsProvider{}, err + } + + accessKeyID, ok := secretValue["AccessKeyID"] + if !ok { + return credentials.StaticCredentialsProvider{}, err } - return credentials2.NewStaticCredentials(credentials.AccessKeyID, credentials.SecretKey, ""), nil + + secretKey, ok := secretValue["SecretKey"] + if !ok { + return credentials.StaticCredentialsProvider{}, err + } + + return credentials.NewStaticCredentialsProvider(accessKeyID, secretKey, ""), nil } -// getSecretManagerSession Instantiates a new Secrets Manager client session -func getSecretManagerSession(isDebug bool) (err error) { - // If a session already exists, use it - if secretManagerSession != nil { +func instantiateSecretManagerClient(isDebug bool) (err error) { + // If a client already exists, use it + if secretManagerClient != nil { return nil } - awsSession, err := session.NewSession() + cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { return err } // Get local config if isDebug && os.Getenv("ENVIRONMENT") != "" { - awsSession, err = session.NewSessionWithOptions(session.Options{ - Config: aws.Config{ - Region: aws.String("af-south-1"), - CredentialsChainVerboseErrors: aws.Bool(true), - }, - }) + cfg, err = config.LoadDefaultConfig(context.TODO(), + config.WithRegion(secretManagerRegion), + ) if err != nil { return err } } - // Create a Secrets Manager client session - secretManagerSession = secretsmanager.New(awsSession, aws.NewConfig().WithRegion(secretManagerRegion)) + // Create a Secrets Manager client + secretManagerClient = secretsmanager.NewFromConfig(cfg) return nil } // logError Logs any errors returned by the Secrets Manager client func logError(err error) { - if aerr, ok := err.(awserr.Error); ok { - logs.Info(aerr.Code()+" %s", aerr.Error()) + var apiErr smithy.APIError + if errors.As(err, &apiErr) { + logs.Info(apiErr.ErrorCode()+" %s", apiErr.ErrorMessage()) } else { - // Print the error, cast err to awserr.Error to get the Code and - // Message from an error. logs.Info(err.Error()) } } @@ -108,7 +111,7 @@ func GetSecret(secretID string, isDebug bool) (string, string) { } // Create a Secrets Manager client - err := getSecretManagerSession(isDebug) + err := instantiateSecretManagerClient(isDebug) if err != nil { logs.Info("Could not create client: %+v", err) return "", "" @@ -120,7 +123,7 @@ func GetSecret(secretID string, isDebug bool) (string, string) { VersionStage: aws.String("AWSCURRENT"), // VersionStage defaults to AWSCURRENT if unspecified } - result, err := secretManagerSession.GetSecretValue(input) + result, err := secretManagerClient.GetSecretValue(context.TODO(), input) if err != nil { logError(err) return "", "" @@ -147,7 +150,7 @@ func GetSecret(secretID string, isDebug bool) (string, string) { // CreateSecret Creates a JSON marshaled "string secret" (can be expanded to cater for binary secrets should the need arise) func CreateSecret(secretID string, secret any, isDebug bool) (awsSecretID string, err error) { // Create a Secrets Manager client - err = getSecretManagerSession(isDebug) + err = instantiateSecretManagerClient(isDebug) if err != nil { logs.Info("Could not create client: %+v", err) return "", err @@ -164,18 +167,18 @@ func CreateSecret(secretID string, secret any, isDebug bool) (awsSecretID string SecretString: aws.String(string(secretStr)), } - result, err := secretManagerSession.CreateSecret(input) + result, err := secretManagerClient.CreateSecret(context.TODO(), input) if err != nil { logError(err) return "", err } - return aws.StringValue(result.Name), nil + return aws.ToString(result.Name), nil } func DeleteSecret(secretID string, forceWithoutRecovery bool, isDebug bool) error { // Create a Secrets Manager client - err := getSecretManagerSession(isDebug) + err := instantiateSecretManagerClient(isDebug) if err != nil { logs.Info("Could not create client: %+v", err) return err @@ -187,7 +190,7 @@ func DeleteSecret(secretID string, forceWithoutRecovery bool, isDebug bool) erro ForceDeleteWithoutRecovery: aws.Bool(forceWithoutRecovery), } - _, err = secretManagerSession.DeleteSecret(input) + _, err = secretManagerClient.DeleteSecret(context.TODO(), input) if err != nil { logError(err) return err @@ -199,7 +202,7 @@ func DeleteSecret(secretID string, forceWithoutRecovery bool, isDebug bool) erro // UpdateSecret Updates an exising secret func UpdateSecret(secretID string, secret any, isDebug bool) error { // Create a Secrets Manager client - err := getSecretManagerSession(isDebug) + err := instantiateSecretManagerClient(isDebug) if err != nil { logs.Info("Could not create client: %+v", err) return err @@ -216,7 +219,7 @@ func UpdateSecret(secretID string, secret any, isDebug bool) error { SecretString: aws.String(string(secretStr)), } - _, err = secretManagerSession.UpdateSecret(input) + _, err = secretManagerClient.UpdateSecret(context.TODO(), input) if err != nil { logError(err) return err diff --git a/sqs/sqs.go b/sqs/sqs.go index cf452f77eb080211a46efb69f9983e2b1bc7a933..0d0259ff033a771a50034fe9cca477a5cc87eb3d 100644 --- a/sqs/sqs.go +++ b/sqs/sqs.go @@ -3,21 +3,25 @@ package sqs /*Package sqs provides a simple interface to send messages to AWS SQS*/ import ( + "context" "encoding/json" "fmt" + "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/utils" + "io" + "time" + "github.com/google/uuid" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/s3" - "io/ioutil" - "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/sqs" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/sqs" + "github.com/aws/aws-sdk-go-v2/service/sqs/types" "github.com/go-resty/resty/v2" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/logs" ) -var sqsClient *sqs.SQS +var sqsClient *sqs.Client const SQSMessageOnS3Key = "message-on-s3" @@ -26,7 +30,7 @@ type Messenger struct { QueueName string QueueURL string Region string - S3Session *s3.SessionWithHelpers + S3Client *s3.ClientWithHelpers S3BucketName string MessageGroupID *string DelaySeconds *int64 @@ -37,20 +41,14 @@ type Messenger struct { // awsRegion - region that the queue was created // awsQueue - name of the queue // Note: Calling code needs SQS IAM permissions -func NewSQSClient(awsRegion string) (*sqs.SQS, error) { - // Make an AWS session - sess, err := session.NewSessionWithOptions(session.Options{ - Config: aws.Config{ - Region: aws.String(awsRegion), - }, - }) - +func NewSQSClient(awsRegion string) (*sqs.Client, error) { + cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(awsRegion)) if err != nil { return nil, err } - // Create SQS service - sqsClient = sqs.New(sess) + sqsClient := sqs.NewFromConfig(cfg) + return sqsClient, err } @@ -58,10 +56,10 @@ func NewSQSClient(awsRegion string) (*sqs.SQS, error) { // headers - string message attributes of the SQS message (see AWS SQS documentation) // body - body of the SQS message (see AWS SQS documentation) func (m *Messenger) SendSQSMessage(headers map[string]string, body string, currentRequestID *string, sqsType string) (string, error) { - msgAttrs := make(map[string]*sqs.MessageAttributeValue) + msgAttrs := make(map[string]types.MessageAttributeValue) for key, val := range headers { - msgAttrs[key] = &sqs.MessageAttributeValue{ + msgAttrs[key] = types.MessageAttributeValue{ DataType: aws.String("String"), StringValue: aws.String(val), } @@ -69,31 +67,35 @@ func (m *Messenger) SendSQSMessage(headers map[string]string, body string, curre // Add request ID if currentRequestID != nil { - msgAttrs[m.RequestIDHeaderKey] = &sqs.MessageAttributeValue{ + msgAttrs[m.RequestIDHeaderKey] = types.MessageAttributeValue{ DataType: aws.String("String"), StringValue: aws.String(*currentRequestID), } } - msgAttrs["type"] = &sqs.MessageAttributeValue{ + msgAttrs["type"] = types.MessageAttributeValue{ DataType: aws.String("String"), StringValue: aws.String(sqsType), } // SQS has max of 15 minutes delay // https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html - if m.DelaySeconds != nil && aws.Int64Value(m.DelaySeconds) > 900 { - m.DelaySeconds = aws.Int64(900) + var delaySeconds int32 + if m.DelaySeconds != nil { + if *m.DelaySeconds > 900 { + m.DelaySeconds = utils.ValueToPointer(int64(900)) + } + delaySeconds = int32(*m.DelaySeconds) } var res *sqs.SendMessageOutput var err error - res, err = sqsClient.SendMessage(&sqs.SendMessageInput{ + res, err = sqsClient.SendMessage(context.TODO(), &sqs.SendMessageInput{ MessageAttributes: msgAttrs, MessageBody: aws.String(body), QueueUrl: &m.QueueURL, MessageGroupId: m.MessageGroupID, - DelaySeconds: m.DelaySeconds, + DelaySeconds: delaySeconds, }) if err != nil { @@ -147,7 +149,7 @@ func SendSQSMessage(msgr Messenger, objectToSend interface{}, currentRequestID * filename := fmt.Sprintf("%v-%v", sqsType, id.String()) logs.Info("SQS S3 %s", filename) - err := uploadMessageToS3(msgr.S3Session, msgr.S3BucketName, filename, jsonBytes) + err := uploadMessageToS3(msgr.S3Client, msgr.S3BucketName, filename, jsonBytes) if err != nil { return err } @@ -165,10 +167,10 @@ func SendSQSMessage(msgr Messenger, objectToSend interface{}, currentRequestID * return nil } -func uploadMessageToS3(session *s3.SessionWithHelpers, bucket string, name string, messageBytes []byte) error { +func uploadMessageToS3(client *s3.ClientWithHelpers, bucket string, name string, messageBytes []byte) error { // Upload message expiry := 24 * 7 * time.Hour // 3 days - _, err := session.UploadWithSettings(messageBytes, bucket, name, s3.S3UploadSettings{ + _, err := client.UploadWithSettings(messageBytes, bucket, name, s3.S3UploadSettings{ ExpiryDuration: &expiry, }) if err != nil { @@ -178,16 +180,16 @@ func uploadMessageToS3(session *s3.SessionWithHelpers, bucket string, name strin return nil } -func RetrieveMessageFromS3(session *s3.SessionWithHelpers, bucket string, filename string) ([]byte, error) { +func RetrieveMessageFromS3(client *s3.ClientWithHelpers, bucket string, filename string) ([]byte, error) { // get the file contents - rawObject, err := session.GetObject(bucket, filename, false) + rawObject, err := client.GetObject(bucket, filename, false) if err != nil { return []byte{}, err } // Read the message var bodyBytes []byte - bodyBytes, err = ioutil.ReadAll(rawObject.Body) + bodyBytes, err = io.ReadAll(rawObject.Body) if err != nil { logs.ErrorWithMsg("Could not read file", err) return []byte{}, err diff --git a/websocket_utils/websocket_utils.go b/websocket_utils/websocket_utils.go index 3a77890ddbeb692af6d7008741ce98c55afa838f..dc27a36db516bd3405685d96b3302725c9fd96a3 100644 --- a/websocket_utils/websocket_utils.go +++ b/websocket_utils/websocket_utils.go @@ -1,25 +1,31 @@ package websocket_utils import ( + "context" "fmt" "github.com/aws/aws-lambda-go/events" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/apigatewaymanagementapi" - "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/apigatewaymanagementapi" + "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/logs" "gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/utils" "os" ) var ( - sessions = map[string]*APIGateWaySessionWithHelpers{} + sessions = map[string]*APIGateWayClientWithHelpers{} ) -type APIGateWaySessionWithHelpers struct { - APIGatewaySession *apigatewaymanagementapi.ApiGatewayManagementApi +type APIGateWayClientWithHelpers struct { + APIGatewayClient *apigatewaymanagementapi.Client } -func GetSession(region ...string) *APIGateWaySessionWithHelpers { +func GetClient(req *events.APIGatewayWebsocketProxyRequest, region ...string) *APIGateWayClientWithHelpers { + if req == nil { + logs.ErrorMsg("APIGatewayWebsocketProxyRequest is nil") + return nil + } + s3Region := os.Getenv("AWS_REGION") // Set custom region @@ -33,34 +39,29 @@ func GetSession(region ...string) *APIGateWaySessionWithHelpers { } // Setup session - options := session.Options{ - Config: aws.Config{ - Region: utils.ValueToPointer(s3Region), - }, - } - sess, err := session.NewSessionWithOptions(options) + cfg, err := config.LoadDefaultConfig(context.TODO(), + config.WithRegion(s3Region), + ) if err != nil { return nil } - apiGatewaySession := NewSession(sess) + + apiGatewaySession := NewClient(req, cfg) sessions[s3Region] = apiGatewaySession return apiGatewaySession } -func NewSession(session *session.Session) *APIGateWaySessionWithHelpers { - return &APIGateWaySessionWithHelpers{ - APIGatewaySession: apigatewaymanagementapi.New(session), +func NewClient(req *events.APIGatewayWebsocketProxyRequest, config aws.Config) *APIGateWayClientWithHelpers { + return &APIGateWayClientWithHelpers{ + APIGatewayClient: apigatewaymanagementapi.NewFromConfig(config, func(o *apigatewaymanagementapi.Options) { + o.BaseEndpoint = utils.ValueToPointer(fmt.Sprintf("https://%s/%s", req.RequestContext.DomainName, req.RequestContext.Stage)) + }), } } -func (s APIGateWaySessionWithHelpers) PostToConnectionIDs(data []byte, req *events.APIGatewayWebsocketProxyRequest, connectionIDs []string) error { - if req == nil { - return errors.Error("websocket request is nil") - } - +func (s APIGateWayClientWithHelpers) PostToConnectionIDs(data []byte, connectionIDs []string) error { for _, connectionID := range connectionIDs { - s.APIGatewaySession.Endpoint = fmt.Sprintf("https://%s/%s", req.RequestContext.DomainName, req.RequestContext.Stage) - _, err := s.APIGatewaySession.PostToConnection(&apigatewaymanagementapi.PostToConnectionInput{ + _, err := s.APIGatewayClient.PostToConnection(context.TODO(), &apigatewaymanagementapi.PostToConnectionInput{ ConnectionId: &connectionID, Data: data, })