Skip to content

Commit

Permalink
Presigned URL generation for Neptune and DocDB CopyDBClusterSnapshot …
Browse files Browse the repository at this point in the history
…& CreateDBCluster (#3782)
  • Loading branch information
skmcgrail committed Feb 17, 2021
1 parent c30a7b2 commit 39a0852
Show file tree
Hide file tree
Showing 9 changed files with 695 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
### SDK Features

### SDK Enhancements
* `service/neptune`: Support for PreSignedUrl generation for CopyDBClusterSnapshot and CreateDBCluster operations. ([#3782](https://github.com/aws/aws-sdk-go/pull/3782))
* `service/docdb`: Support for PreSignedUrl generation for CopyDBClusterSnapshot and CreateDBCluster operations. ([#3782](https://github.com/aws/aws-sdk-go/pull/3782))

### SDK Bugs
33 changes: 30 additions & 3 deletions private/model/api/customization_passes.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func (a *API) customizationPasses() error {
"s3control": s3ControlCustomizations,
"cloudfront": cloudfrontCustomizations,
"rds": rdsCustomizations,
"neptune": neptuneCustomizations,
"docdb": docdbCustomizations,

// Disable endpoint resolving for services that require customer
// to provide endpoint them selves.
Expand Down Expand Up @@ -327,7 +329,34 @@ func rdsCustomizations(a *API) error {
"CreateDBClusterInput",
"StartDBInstanceAutomatedBackupsReplicationInput",
}
for _, input := range inputs {
generatePresignedURL(a, inputs)
return nil
}

// neptuneCustomizations are customization for the service/neptune. This adds
// non-modeled fields used for presigning.
func neptuneCustomizations(a *API) error {
inputs := []string{
"CopyDBClusterSnapshotInput",
"CreateDBClusterInput",
}
generatePresignedURL(a, inputs)
return nil
}

// neptuneCustomizations are customization for the service/neptune. This adds
// non-modeled fields used for presigning.
func docdbCustomizations(a *API) error {
inputs := []string{
"CopyDBClusterSnapshotInput",
"CreateDBClusterInput",
}
generatePresignedURL(a, inputs)
return nil
}

func generatePresignedURL(a *API, inputShapes []string) {
for _, input := range inputShapes {
if ref, ok := a.Shapes[input]; ok {
ref.MemberRefs["SourceRegion"] = &ShapeRef{
Documentation: docstring(`SourceRegion is the source region where the resource exists. This is not sent over the wire and is only used for presigning. This value should always have the same region as the source ARN.`),
Expand All @@ -342,8 +371,6 @@ func rdsCustomizations(a *API) error {
}
}
}

return nil
}

func disableEndpointResolving(a *API) error {
Expand Down
40 changes: 40 additions & 0 deletions service/docdb/api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

107 changes: 107 additions & 0 deletions service/docdb/customizations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package docdb

import (
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/request"
)

func init() {
ops := []string{
opCopyDBClusterSnapshot,
opCreateDBCluster,
}
initRequest = func(r *request.Request) {
for _, operation := range ops {
if r.Operation.Name == operation {
r.Handlers.Build.PushFront(fillPresignedURL)
}
}
}
}

func fillPresignedURL(r *request.Request) {
fns := map[string]func(r *request.Request){
opCopyDBClusterSnapshot: copyDBClusterSnapshotPresign,
opCreateDBCluster: createDBClusterPresign,
}
if !r.ParamsFilled() {
return
}
if f, ok := fns[r.Operation.Name]; ok {
f(r)
}
}

func copyDBClusterSnapshotPresign(r *request.Request) {
originParams := r.Params.(*CopyDBClusterSnapshotInput)

if originParams.SourceRegion == nil || originParams.PreSignedUrl != nil || originParams.DestinationRegion != nil {
return
}

originParams.DestinationRegion = r.Config.Region
// preSignedUrl is not required for instances in the same region.
if *originParams.SourceRegion == *originParams.DestinationRegion {
return
}

newParams := awsutil.CopyOf(r.Params).(*CopyDBClusterSnapshotInput)
originParams.PreSignedUrl = presignURL(r, originParams.SourceRegion, newParams)
}

func createDBClusterPresign(r *request.Request) {
originParams := r.Params.(*CreateDBClusterInput)

if originParams.SourceRegion == nil || originParams.PreSignedUrl != nil || originParams.DestinationRegion != nil {
return
}

originParams.DestinationRegion = r.Config.Region
// preSignedUrl is not required for instances in the same region.
if *originParams.SourceRegion == *originParams.DestinationRegion {
return
}

newParams := awsutil.CopyOf(r.Params).(*CreateDBClusterInput)
originParams.PreSignedUrl = presignURL(r, originParams.SourceRegion, newParams)
}

// presignURL will presign the request by using SoureRegion to sign with. SourceRegion is not
// sent to the service, and is only used to not have the SDKs parsing ARNs.
func presignURL(r *request.Request, sourceRegion *string, newParams interface{}) *string {
cfg := r.Config.Copy(aws.NewConfig().
WithEndpoint("").
WithRegion(aws.StringValue(sourceRegion)))

clientInfo := r.ClientInfo
resolved, err := r.Config.EndpointResolver.EndpointFor(
EndpointsID, 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 nil
}

clientInfo.Endpoint = resolved.URL
clientInfo.SigningRegion = resolved.SigningRegion

// Presign a request with modified params
req := request.New(*cfg, clientInfo, r.Handlers, r.Retryer, r.Operation, newParams, r.Data)
req.Operation.HTTPMethod = "GET"
uri, 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 nil
}

// We have our URL, set it on params
return &uri
}
Loading

0 comments on commit 39a0852

Please sign in to comment.