1
2
3 package ecrpublic
4
5 import (
6 "context"
7 "fmt"
8 "github.com/aws/aws-sdk-go-v2/aws"
9 "github.com/aws/aws-sdk-go-v2/aws/defaults"
10 awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
11 "github.com/aws/aws-sdk-go-v2/aws/retry"
12 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
13 awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
14 internalConfig "github.com/aws/aws-sdk-go-v2/internal/configsources"
15 smithy "github.com/aws/smithy-go"
16 smithydocument "github.com/aws/smithy-go/document"
17 "github.com/aws/smithy-go/logging"
18 "github.com/aws/smithy-go/middleware"
19 smithyhttp "github.com/aws/smithy-go/transport/http"
20 "net"
21 "net/http"
22 "time"
23 )
24
25 const ServiceID = "ECR PUBLIC"
26 const ServiceAPIVersion = "2020-10-30"
27
28
29
30 type Client struct {
31 options Options
32 }
33
34
35
36
37 func New(options Options, optFns ...func(*Options)) *Client {
38 options = options.Copy()
39
40 resolveDefaultLogger(&options)
41
42 setResolvedDefaultsMode(&options)
43
44 resolveRetryer(&options)
45
46 resolveHTTPClient(&options)
47
48 resolveHTTPSignerV4(&options)
49
50 for _, fn := range optFns {
51 fn(&options)
52 }
53
54 client := &Client{
55 options: options,
56 }
57
58 return client
59 }
60
61 type Options struct {
62
63
64
65 APIOptions []func(*middleware.Stack) error
66
67
68 AppID string
69
70
71
72
73 BaseEndpoint *string
74
75
76 ClientLogMode aws.ClientLogMode
77
78
79 Credentials aws.CredentialsProvider
80
81
82
83 DefaultsMode aws.DefaultsMode
84
85
86 EndpointOptions EndpointResolverOptions
87
88
89
90
91
92
93
94
95 EndpointResolver EndpointResolver
96
97
98
99 EndpointResolverV2 EndpointResolverV2
100
101
102 HTTPSignerV4 HTTPSignerV4
103
104
105 Logger logging.Logger
106
107
108 Region string
109
110
111
112
113
114
115
116
117
118
119 RetryMaxAttempts int
120
121
122
123
124
125
126 RetryMode aws.RetryMode
127
128
129
130
131
132 Retryer aws.Retryer
133
134
135
136
137
138 RuntimeEnvironment aws.RuntimeEnvironment
139
140
141
142
143
144 resolvedDefaultsMode aws.DefaultsMode
145
146
147
148 HTTPClient HTTPClient
149 }
150
151
152
153 func WithAPIOptions(optFns ...func(*middleware.Stack) error) func(*Options) {
154 return func(o *Options) {
155 o.APIOptions = append(o.APIOptions, optFns...)
156 }
157 }
158
159
160
161
162
163
164 func WithEndpointResolver(v EndpointResolver) func(*Options) {
165 return func(o *Options) {
166 o.EndpointResolver = v
167 }
168 }
169
170
171
172 func WithEndpointResolverV2(v EndpointResolverV2) func(*Options) {
173 return func(o *Options) {
174 o.EndpointResolverV2 = v
175 }
176 }
177
178 type HTTPClient interface {
179 Do(*http.Request) (*http.Response, error)
180 }
181
182
183 func (o Options) Copy() Options {
184 to := o
185 to.APIOptions = make([]func(*middleware.Stack) error, len(o.APIOptions))
186 copy(to.APIOptions, o.APIOptions)
187
188 return to
189 }
190 func (c *Client) invokeOperation(ctx context.Context, opID string, params interface{}, optFns []func(*Options), stackFns ...func(*middleware.Stack, Options) error) (result interface{}, metadata middleware.Metadata, err error) {
191 ctx = middleware.ClearStackValues(ctx)
192 stack := middleware.NewStack(opID, smithyhttp.NewStackRequest)
193 options := c.options.Copy()
194 resolveEndpointResolverV2(&options)
195
196 for _, fn := range optFns {
197 fn(&options)
198 }
199
200 finalizeRetryMaxAttemptOptions(&options, *c)
201
202 finalizeClientEndpointResolverOptions(&options)
203
204 for _, fn := range stackFns {
205 if err := fn(stack, options); err != nil {
206 return nil, metadata, err
207 }
208 }
209
210 for _, fn := range options.APIOptions {
211 if err := fn(stack); err != nil {
212 return nil, metadata, err
213 }
214 }
215
216 handler := middleware.DecorateHandler(smithyhttp.NewClientHandler(options.HTTPClient), stack)
217 result, metadata, err = handler.Handle(ctx, params)
218 if err != nil {
219 err = &smithy.OperationError{
220 ServiceID: ServiceID,
221 OperationName: opID,
222 Err: err,
223 }
224 }
225 return result, metadata, err
226 }
227
228 type noSmithyDocumentSerde = smithydocument.NoSerde
229
230 type legacyEndpointContextSetter struct {
231 LegacyResolver EndpointResolver
232 }
233
234 func (*legacyEndpointContextSetter) ID() string {
235 return "legacyEndpointContextSetter"
236 }
237
238 func (m *legacyEndpointContextSetter) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) (
239 out middleware.InitializeOutput, metadata middleware.Metadata, err error,
240 ) {
241 if m.LegacyResolver != nil {
242 ctx = awsmiddleware.SetRequiresLegacyEndpoints(ctx, true)
243 }
244
245 return next.HandleInitialize(ctx, in)
246
247 }
248 func addlegacyEndpointContextSetter(stack *middleware.Stack, o Options) error {
249 return stack.Initialize.Add(&legacyEndpointContextSetter{
250 LegacyResolver: o.EndpointResolver,
251 }, middleware.Before)
252 }
253
254 func resolveDefaultLogger(o *Options) {
255 if o.Logger != nil {
256 return
257 }
258 o.Logger = logging.Nop{}
259 }
260
261 func addSetLoggerMiddleware(stack *middleware.Stack, o Options) error {
262 return middleware.AddSetLoggerMiddleware(stack, o.Logger)
263 }
264
265 func setResolvedDefaultsMode(o *Options) {
266 if len(o.resolvedDefaultsMode) > 0 {
267 return
268 }
269
270 var mode aws.DefaultsMode
271 mode.SetFromString(string(o.DefaultsMode))
272
273 if mode == aws.DefaultsModeAuto {
274 mode = defaults.ResolveDefaultsModeAuto(o.Region, o.RuntimeEnvironment)
275 }
276
277 o.resolvedDefaultsMode = mode
278 }
279
280
281 func NewFromConfig(cfg aws.Config, optFns ...func(*Options)) *Client {
282 opts := Options{
283 Region: cfg.Region,
284 DefaultsMode: cfg.DefaultsMode,
285 RuntimeEnvironment: cfg.RuntimeEnvironment,
286 HTTPClient: cfg.HTTPClient,
287 Credentials: cfg.Credentials,
288 APIOptions: cfg.APIOptions,
289 Logger: cfg.Logger,
290 ClientLogMode: cfg.ClientLogMode,
291 AppID: cfg.AppID,
292 }
293 resolveAWSRetryerProvider(cfg, &opts)
294 resolveAWSRetryMaxAttempts(cfg, &opts)
295 resolveAWSRetryMode(cfg, &opts)
296 resolveAWSEndpointResolver(cfg, &opts)
297 resolveUseDualStackEndpoint(cfg, &opts)
298 resolveUseFIPSEndpoint(cfg, &opts)
299 return New(opts, optFns...)
300 }
301
302 func resolveHTTPClient(o *Options) {
303 var buildable *awshttp.BuildableClient
304
305 if o.HTTPClient != nil {
306 var ok bool
307 buildable, ok = o.HTTPClient.(*awshttp.BuildableClient)
308 if !ok {
309 return
310 }
311 } else {
312 buildable = awshttp.NewBuildableClient()
313 }
314
315 modeConfig, err := defaults.GetModeConfiguration(o.resolvedDefaultsMode)
316 if err == nil {
317 buildable = buildable.WithDialerOptions(func(dialer *net.Dialer) {
318 if dialerTimeout, ok := modeConfig.GetConnectTimeout(); ok {
319 dialer.Timeout = dialerTimeout
320 }
321 })
322
323 buildable = buildable.WithTransportOptions(func(transport *http.Transport) {
324 if tlsHandshakeTimeout, ok := modeConfig.GetTLSNegotiationTimeout(); ok {
325 transport.TLSHandshakeTimeout = tlsHandshakeTimeout
326 }
327 })
328 }
329
330 o.HTTPClient = buildable
331 }
332
333 func resolveRetryer(o *Options) {
334 if o.Retryer != nil {
335 return
336 }
337
338 if len(o.RetryMode) == 0 {
339 modeConfig, err := defaults.GetModeConfiguration(o.resolvedDefaultsMode)
340 if err == nil {
341 o.RetryMode = modeConfig.RetryMode
342 }
343 }
344 if len(o.RetryMode) == 0 {
345 o.RetryMode = aws.RetryModeStandard
346 }
347
348 var standardOptions []func(*retry.StandardOptions)
349 if v := o.RetryMaxAttempts; v != 0 {
350 standardOptions = append(standardOptions, func(so *retry.StandardOptions) {
351 so.MaxAttempts = v
352 })
353 }
354
355 switch o.RetryMode {
356 case aws.RetryModeAdaptive:
357 var adaptiveOptions []func(*retry.AdaptiveModeOptions)
358 if len(standardOptions) != 0 {
359 adaptiveOptions = append(adaptiveOptions, func(ao *retry.AdaptiveModeOptions) {
360 ao.StandardOptions = append(ao.StandardOptions, standardOptions...)
361 })
362 }
363 o.Retryer = retry.NewAdaptiveMode(adaptiveOptions...)
364
365 default:
366 o.Retryer = retry.NewStandard(standardOptions...)
367 }
368 }
369
370 func resolveAWSRetryerProvider(cfg aws.Config, o *Options) {
371 if cfg.Retryer == nil {
372 return
373 }
374 o.Retryer = cfg.Retryer()
375 }
376
377 func resolveAWSRetryMode(cfg aws.Config, o *Options) {
378 if len(cfg.RetryMode) == 0 {
379 return
380 }
381 o.RetryMode = cfg.RetryMode
382 }
383 func resolveAWSRetryMaxAttempts(cfg aws.Config, o *Options) {
384 if cfg.RetryMaxAttempts == 0 {
385 return
386 }
387 o.RetryMaxAttempts = cfg.RetryMaxAttempts
388 }
389
390 func finalizeRetryMaxAttemptOptions(o *Options, client Client) {
391 if v := o.RetryMaxAttempts; v == 0 || v == client.options.RetryMaxAttempts {
392 return
393 }
394
395 o.Retryer = retry.AddWithMaxAttempts(o.Retryer, o.RetryMaxAttempts)
396 }
397
398 func resolveAWSEndpointResolver(cfg aws.Config, o *Options) {
399 if cfg.EndpointResolver == nil && cfg.EndpointResolverWithOptions == nil {
400 return
401 }
402 o.EndpointResolver = withEndpointResolver(cfg.EndpointResolver, cfg.EndpointResolverWithOptions)
403 }
404
405 func addClientUserAgent(stack *middleware.Stack, options Options) error {
406 if err := awsmiddleware.AddSDKAgentKeyValue(awsmiddleware.APIMetadata, "ecrpublic", goModuleVersion)(stack); err != nil {
407 return err
408 }
409
410 if len(options.AppID) > 0 {
411 return awsmiddleware.AddSDKAgentKey(awsmiddleware.ApplicationIdentifier, options.AppID)(stack)
412 }
413
414 return nil
415 }
416
417 func addHTTPSignerV4Middleware(stack *middleware.Stack, o Options) error {
418 mw := v4.NewSignHTTPRequestMiddleware(v4.SignHTTPRequestMiddlewareOptions{
419 CredentialsProvider: o.Credentials,
420 Signer: o.HTTPSignerV4,
421 LogSigning: o.ClientLogMode.IsSigning(),
422 })
423 return stack.Finalize.Add(mw, middleware.After)
424 }
425
426 type HTTPSignerV4 interface {
427 SignHTTP(ctx context.Context, credentials aws.Credentials, r *http.Request, payloadHash string, service string, region string, signingTime time.Time, optFns ...func(*v4.SignerOptions)) error
428 }
429
430 func resolveHTTPSignerV4(o *Options) {
431 if o.HTTPSignerV4 != nil {
432 return
433 }
434 o.HTTPSignerV4 = newDefaultV4Signer(*o)
435 }
436
437 func newDefaultV4Signer(o Options) *v4.Signer {
438 return v4.NewSigner(func(so *v4.SignerOptions) {
439 so.Logger = o.Logger
440 so.LogSigning = o.ClientLogMode.IsSigning()
441 })
442 }
443
444 func addRetryMiddlewares(stack *middleware.Stack, o Options) error {
445 mo := retry.AddRetryMiddlewaresOptions{
446 Retryer: o.Retryer,
447 LogRetryAttempts: o.ClientLogMode.IsRetries(),
448 }
449 return retry.AddRetryMiddlewares(stack, mo)
450 }
451
452
453 func resolveUseDualStackEndpoint(cfg aws.Config, o *Options) error {
454 if len(cfg.ConfigSources) == 0 {
455 return nil
456 }
457 value, found, err := internalConfig.ResolveUseDualStackEndpoint(context.Background(), cfg.ConfigSources)
458 if err != nil {
459 return err
460 }
461 if found {
462 o.EndpointOptions.UseDualStackEndpoint = value
463 }
464 return nil
465 }
466
467
468 func resolveUseFIPSEndpoint(cfg aws.Config, o *Options) error {
469 if len(cfg.ConfigSources) == 0 {
470 return nil
471 }
472 value, found, err := internalConfig.ResolveUseFIPSEndpoint(context.Background(), cfg.ConfigSources)
473 if err != nil {
474 return err
475 }
476 if found {
477 o.EndpointOptions.UseFIPSEndpoint = value
478 }
479 return nil
480 }
481
482 func addRequestIDRetrieverMiddleware(stack *middleware.Stack) error {
483 return awsmiddleware.AddRequestIDRetrieverMiddleware(stack)
484 }
485
486 func addResponseErrorMiddleware(stack *middleware.Stack) error {
487 return awshttp.AddResponseErrorMiddleware(stack)
488 }
489
490 func addRequestResponseLogging(stack *middleware.Stack, o Options) error {
491 return stack.Deserialize.Add(&smithyhttp.RequestResponseLogger{
492 LogRequest: o.ClientLogMode.IsRequest(),
493 LogRequestWithBody: o.ClientLogMode.IsRequestWithBody(),
494 LogResponse: o.ClientLogMode.IsResponse(),
495 LogResponseWithBody: o.ClientLogMode.IsResponseWithBody(),
496 }, middleware.After)
497 }
498
499 type endpointDisableHTTPSMiddleware struct {
500 EndpointDisableHTTPS bool
501 }
502
503 func (*endpointDisableHTTPSMiddleware) ID() string {
504 return "endpointDisableHTTPSMiddleware"
505 }
506
507 func (m *endpointDisableHTTPSMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) (
508 out middleware.SerializeOutput, metadata middleware.Metadata, err error,
509 ) {
510 req, ok := in.Request.(*smithyhttp.Request)
511 if !ok {
512 return out, metadata, fmt.Errorf("unknown transport type %T", in.Request)
513 }
514
515 if m.EndpointDisableHTTPS && !smithyhttp.GetHostnameImmutable(ctx) {
516 req.URL.Scheme = "http"
517 }
518
519 return next.HandleSerialize(ctx, in)
520
521 }
522 func addendpointDisableHTTPSMiddleware(stack *middleware.Stack, o Options) error {
523 return stack.Serialize.Insert(&endpointDisableHTTPSMiddleware{
524 EndpointDisableHTTPS: o.EndpointOptions.DisableHTTPS,
525 }, "OperationSerializer", middleware.Before)
526 }
527
View as plain text