package ec2 import ( "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awsutil" "github.com/aws/aws-sdk-go/aws/client" "github.com/aws/aws-sdk-go/aws/endpoints" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/internal/sdkrand" ) type retryer struct { client.DefaultRetryer } func (d retryer) RetryRules(r *request.Request) time.Duration { switch r.Operation.Name { case opModifyNetworkInterfaceAttribute: fallthrough case opAssignPrivateIpAddresses: return customRetryRule(r) default: return d.DefaultRetryer.RetryRules(r) } } func customRetryRule(r *request.Request) time.Duration { retryTimes := []time.Duration{ time.Second, 3 * time.Second, 5 * time.Second, } count := r.RetryCount if count >= len(retryTimes) { count = len(retryTimes) - 1 } minTime := int(retryTimes[count]) return time.Duration(sdkrand.SeededRand.Intn(minTime) + minTime) } func setCustomRetryer(c *client.Client) { maxRetries := aws.IntValue(c.Config.MaxRetries) if c.Config.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries { maxRetries = 3 } c.Retryer = retryer{ DefaultRetryer: client.DefaultRetryer{ NumMaxRetries: maxRetries, }, } } func init() { initClient = func(c *client.Client) { if c.Config.Retryer == nil { // Only override the retryer with a custom one if the config // does not already contain a retryer setCustomRetryer(c) } } initRequest = func(r *request.Request) { if r.Operation.Name == opCopySnapshot { // fill the PresignedURL parameter r.Handlers.Build.PushFront(fillPresignedURL) } } } func fillPresignedURL(r *request.Request) { if !r.ParamsFilled() { return } origParams := r.Params.(*CopySnapshotInput) // Stop if PresignedURL/DestinationRegion is set if origParams.PresignedUrl != nil || origParams.DestinationRegion != nil { return } origParams.DestinationRegion = r.Config.Region newParams := awsutil.CopyOf(r.Params).(*CopySnapshotInput) // Create a new request based on the existing request. We will use this to // presign the CopySnapshot request against the source region. cfg := r.Config.Copy(aws.NewConfig(). WithEndpoint(""). WithRegion(aws.StringValue(origParams.SourceRegion))) clientInfo := r.ClientInfo resolved, err := r.Config.EndpointResolver.EndpointFor( clientInfo.ServiceName, aws.StringValue(cfg.Region), func(opt *endpoints.Options) { opt.DisableSSL = aws.BoolValue(cfg.DisableSSL) opt.UseDualStack = aws.BoolValue(cfg.UseDualStack) }, ) if err != nil { r.Error = err return } clientInfo.Endpoint = resolved.URL clientInfo.SigningRegion = resolved.SigningRegion // Presign a CopySnapshot request with modified params req := request.New(*cfg, clientInfo, r.Handlers, r.Retryer, r.Operation, newParams, r.Data) url, err := req.Presign(5 * time.Minute) // 5 minutes should be enough. if err != nil { // bubble error back up to original request r.Error = err return } // We have our URL, set it on params origParams.PresignedUrl = &url }