Skip to content

Commit

Permalink
Refactoring SDK's code generation patterns (aws#298)
Browse files Browse the repository at this point in the history
Updates the SDK's code generation pattern with several improvements to improve discoverability, and consistency in client naming.

* Standardizing of the service model's ServiceID for the name of the
service client's package.

* Adds an operation `Response` type that is in addition from the
operation's `Output` parameters. This prevents collisions between SDK
response metadata, marshaling methods, and modeled output parameters.

* Refactor service client package's client name to be named Client
instead of the service's short name. Removes the stuttering of client
package and type, (e.g. s3.S3 becomes s3.Client)

* Fix service endpoint lookups use the the service's modeled EndpointID
instead of inconsistent service name.

* Generate API operations into their own file instead of all operations
and parameter types being generated into a single file. This improves
readability of individual source files for documentation reference.
Non-input/output types are still generated into a single file. This change also fixes several occurrences of incorrectly generated API operation input/output type names.

* Removes aws/endpoints Service identifiers from endpoint list. These
were not actually service identifiers, but EndpointsID. In addition the
values modeled by the services were unstable, and could change causing
breaking changes in the SDK's aws/endpoints package. The service
client package's `EndpointsID` const should be used instead.

* Move Paginate method from the initialized Request type into its own
construct via the New<RequestType>Paginator function to create the
request paginator. (e.g. req.Paginate becomes NewListObjectsPaginator(req))

Fix aws#294 aws#282 aws#275
  • Loading branch information
jasdel authored May 24, 2019
1 parent 1f1e9be commit e6b1343
Show file tree
Hide file tree
Showing 7,511 changed files with 1,362,876 additions and 1,304,998 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
2 changes: 2 additions & 0 deletions aws/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
// Metadata wraps immutable data from the Client structure.
type Metadata struct {
ServiceName string
ServiceID string
EndpointsID string
APIVersion string

Endpoint string
Expand Down
162 changes: 0 additions & 162 deletions aws/ec2metadata/api.go

This file was deleted.

113 changes: 113 additions & 0 deletions aws/ec2metadata/api_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Package ec2metadata provides the client for making API calls to the
// EC2 Instance Metadata service.
//
// This package's client can be disabled completely by setting the environment
// variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to
// true instructs the SDK to disable the EC2 Metadata client. The client cannot
// be used while the environemnt variable is set to true, (case insensitive).
package ec2metadata

import (
"bytes"
"errors"
"io"
"net/http"
"os"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/awserr"
"github.com/aws/aws-sdk-go-v2/aws/defaults"
)

const disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED"

// A Client is an EC2 Instance Metadata service Client.
type Client struct {
*aws.Client
}

// New creates a new instance of the Client client with a Config.
// This client is safe to use across multiple goroutines.
//
// Example:
// // Create a Client client from just a config.
// svc := ec2metadata.New(cfg)
func New(config aws.Config) *Client {
svc := &Client{
Client: aws.NewClient(
config,
aws.Metadata{
ServiceName: "EC2 Instance Metadata",
ServiceID: "EC2InstanceMetadata",
EndpointsID: "ec2metadata",
APIVersion: "latest",
},
),
}

svc.Handlers.Unmarshal.PushBack(unmarshalHandler)
svc.Handlers.UnmarshalError.PushBack(unmarshalError)
svc.Handlers.Validate.Clear()
svc.Handlers.Validate.PushBack(validateEndpointHandler)

// Disable the EC2 Instance Metadata service if the environment variable is
// set. This shortcirctes the service's functionality to always fail to
// send requests.
if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" {
svc.Handlers.Send.SwapNamed(aws.NamedHandler{
Name: defaults.SendHandler.Name,
Fn: func(r *aws.Request) {
r.HTTPResponse = &http.Response{
Header: http.Header{},
}
r.Error = awserr.New(
aws.ErrCodeRequestCanceled,
"EC2 IMDS access disabled via "+disableServiceEnvVar+" env var",
nil)
},
})
}

return svc
}

func httpClientZero(c *http.Client) bool {
return c == nil || (c.Transport == nil && c.CheckRedirect == nil && c.Jar == nil && c.Timeout == 0)
}

type metadataOutput struct {
Content string
}

func unmarshalHandler(r *aws.Request) {
defer r.HTTPResponse.Body.Close()
b := &bytes.Buffer{}
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err)
return
}

if data, ok := r.Data.(*metadataOutput); ok {
data.Content = b.String()
}
}

func unmarshalError(r *aws.Request) {
defer r.HTTPResponse.Body.Close()
b := &bytes.Buffer{}
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err)
return
}

// Response body format is not consistent between metadata endpoints.
// Grab the error message as a string and include that as the source error
r.Error = awserr.New("EC2MetadataError", "failed to make Client request", errors.New(b.String()))
}

func validateEndpointHandler(r *aws.Request) {
if r.Metadata.Endpoint == "" {
r.Error = aws.ErrMissingEndpoint
}
}
Loading

0 comments on commit e6b1343

Please sign in to comment.