src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

client.go (4707B)


      1 package client
      2 
      3 import (
      4 	"context"
      5 	"fmt"
      6 	"net/http"
      7 	"time"
      8 
      9 	"github.com/aws/aws-sdk-go-v2/aws"
     10 	"github.com/aws/aws-sdk-go-v2/aws/middleware"
     11 	"github.com/aws/aws-sdk-go-v2/aws/retry"
     12 	awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
     13 	"github.com/aws/smithy-go"
     14 	smithymiddleware "github.com/aws/smithy-go/middleware"
     15 	smithyhttp "github.com/aws/smithy-go/transport/http"
     16 )
     17 
     18 // ServiceID is the client identifer
     19 const ServiceID = "endpoint-credentials"
     20 
     21 // HTTPClient is a client for sending HTTP requests
     22 type HTTPClient interface {
     23 	Do(*http.Request) (*http.Response, error)
     24 }
     25 
     26 // Options is the endpoint client configurable options
     27 type Options struct {
     28 	// The endpoint to retrieve credentials from
     29 	Endpoint string
     30 
     31 	// The HTTP client to invoke API calls with. Defaults to client's default HTTP
     32 	// implementation if nil.
     33 	HTTPClient HTTPClient
     34 
     35 	// Retryer guides how HTTP requests should be retried in case of recoverable
     36 	// failures. When nil the API client will use a default retryer.
     37 	Retryer aws.Retryer
     38 
     39 	// Set of options to modify how the credentials operation is invoked.
     40 	APIOptions []func(*smithymiddleware.Stack) error
     41 }
     42 
     43 // Copy creates a copy of the API options.
     44 func (o Options) Copy() Options {
     45 	to := o
     46 	to.APIOptions = make([]func(*smithymiddleware.Stack) error, len(o.APIOptions))
     47 	copy(to.APIOptions, o.APIOptions)
     48 	return to
     49 }
     50 
     51 // Client is an client for retrieving AWS credentials from an endpoint
     52 type Client struct {
     53 	options Options
     54 }
     55 
     56 // New constructs a new Client from the given options
     57 func New(options Options, optFns ...func(*Options)) *Client {
     58 	options = options.Copy()
     59 
     60 	if options.HTTPClient == nil {
     61 		options.HTTPClient = awshttp.NewBuildableClient()
     62 	}
     63 
     64 	if options.Retryer == nil {
     65 		// Amazon-owned implementations of this endpoint are known to sometimes
     66 		// return plaintext responses (i.e. no Code) like normal, add a few
     67 		// additional status codes
     68 		options.Retryer = retry.NewStandard(func(o *retry.StandardOptions) {
     69 			o.Retryables = append(o.Retryables, retry.RetryableHTTPStatusCode{
     70 				Codes: map[int]struct{}{
     71 					http.StatusTooManyRequests: {},
     72 				},
     73 			})
     74 		})
     75 	}
     76 
     77 	for _, fn := range optFns {
     78 		fn(&options)
     79 	}
     80 
     81 	client := &Client{
     82 		options: options,
     83 	}
     84 
     85 	return client
     86 }
     87 
     88 // GetCredentialsInput is the input to send with the endpoint service to receive credentials.
     89 type GetCredentialsInput struct {
     90 	AuthorizationToken string
     91 }
     92 
     93 // GetCredentials retrieves credentials from credential endpoint
     94 func (c *Client) GetCredentials(ctx context.Context, params *GetCredentialsInput, optFns ...func(*Options)) (*GetCredentialsOutput, error) {
     95 	stack := smithymiddleware.NewStack("GetCredentials", smithyhttp.NewStackRequest)
     96 	options := c.options.Copy()
     97 	for _, fn := range optFns {
     98 		fn(&options)
     99 	}
    100 
    101 	stack.Serialize.Add(&serializeOpGetCredential{}, smithymiddleware.After)
    102 	stack.Build.Add(&buildEndpoint{Endpoint: options.Endpoint}, smithymiddleware.After)
    103 	stack.Deserialize.Add(&deserializeOpGetCredential{}, smithymiddleware.After)
    104 	addProtocolFinalizerMiddlewares(stack, options, "GetCredentials")
    105 	retry.AddRetryMiddlewares(stack, retry.AddRetryMiddlewaresOptions{Retryer: options.Retryer})
    106 	middleware.AddSDKAgentKey(middleware.FeatureMetadata, ServiceID)
    107 
    108 	for _, fn := range options.APIOptions {
    109 		if err := fn(stack); err != nil {
    110 			return nil, err
    111 		}
    112 	}
    113 
    114 	handler := smithymiddleware.DecorateHandler(smithyhttp.NewClientHandler(options.HTTPClient), stack)
    115 	result, _, err := handler.Handle(ctx, params)
    116 	if err != nil {
    117 		return nil, err
    118 	}
    119 
    120 	return result.(*GetCredentialsOutput), err
    121 }
    122 
    123 // GetCredentialsOutput is the response from the credential endpoint
    124 type GetCredentialsOutput struct {
    125 	Expiration      *time.Time
    126 	AccessKeyID     string
    127 	SecretAccessKey string
    128 	Token           string
    129 	AccountID       string
    130 }
    131 
    132 // EndpointError is an error returned from the endpoint service
    133 type EndpointError struct {
    134 	Code       string            `json:"code"`
    135 	Message    string            `json:"message"`
    136 	Fault      smithy.ErrorFault `json:"-"`
    137 	statusCode int               `json:"-"`
    138 }
    139 
    140 // Error is the error mesage string
    141 func (e *EndpointError) Error() string {
    142 	return fmt.Sprintf("%s: %s", e.Code, e.Message)
    143 }
    144 
    145 // ErrorCode is the error code returned by the endpoint
    146 func (e *EndpointError) ErrorCode() string {
    147 	return e.Code
    148 }
    149 
    150 // ErrorMessage is the error message returned by the endpoint
    151 func (e *EndpointError) ErrorMessage() string {
    152 	return e.Message
    153 }
    154 
    155 // ErrorFault indicates error fault classification
    156 func (e *EndpointError) ErrorFault() smithy.ErrorFault {
    157 	return e.Fault
    158 }
    159 
    160 // HTTPStatusCode implements retry.HTTPStatusCode.
    161 func (e *EndpointError) HTTPStatusCode() int {
    162 	return e.statusCode
    163 }