src

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

client.go (4788B)


      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 	smithyhttp.AddErrorCloseResponseBodyMiddleware(stack)
    108 	smithyhttp.AddCloseResponseBodyMiddleware(stack)
    109 
    110 	for _, fn := range options.APIOptions {
    111 		if err := fn(stack); err != nil {
    112 			return nil, err
    113 		}
    114 	}
    115 
    116 	handler := smithymiddleware.DecorateHandler(smithyhttp.NewClientHandler(options.HTTPClient), stack)
    117 	result, _, err := handler.Handle(ctx, params)
    118 	if err != nil {
    119 		return nil, err
    120 	}
    121 
    122 	return result.(*GetCredentialsOutput), err
    123 }
    124 
    125 // GetCredentialsOutput is the response from the credential endpoint
    126 type GetCredentialsOutput struct {
    127 	Expiration      *time.Time
    128 	AccessKeyID     string
    129 	SecretAccessKey string
    130 	Token           string
    131 }
    132 
    133 // EndpointError is an error returned from the endpoint service
    134 type EndpointError struct {
    135 	Code       string            `json:"code"`
    136 	Message    string            `json:"message"`
    137 	Fault      smithy.ErrorFault `json:"-"`
    138 	statusCode int               `json:"-"`
    139 }
    140 
    141 // Error is the error mesage string
    142 func (e *EndpointError) Error() string {
    143 	return fmt.Sprintf("%s: %s", e.Code, e.Message)
    144 }
    145 
    146 // ErrorCode is the error code returned by the endpoint
    147 func (e *EndpointError) ErrorCode() string {
    148 	return e.Code
    149 }
    150 
    151 // ErrorMessage is the error message returned by the endpoint
    152 func (e *EndpointError) ErrorMessage() string {
    153 	return e.Message
    154 }
    155 
    156 // ErrorFault indicates error fault classification
    157 func (e *EndpointError) ErrorFault() smithy.ErrorFault {
    158 	return e.Fault
    159 }
    160 
    161 // HTTPStatusCode implements retry.HTTPStatusCode.
    162 func (e *EndpointError) HTTPStatusCode() int {
    163 	return e.statusCode
    164 }