]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame_incremental - vendor/github.com/aws/aws-sdk-go/aws/session/session.go
Merge branch 'fix_read_test' of github.com:alexandreFre/terraform-provider-statuscake
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / aws / session / session.go
... / ...
CommitLineData
1package session
2
3import (
4 "crypto/tls"
5 "crypto/x509"
6 "fmt"
7 "io"
8 "io/ioutil"
9 "net/http"
10 "os"
11
12 "github.com/aws/aws-sdk-go/aws"
13 "github.com/aws/aws-sdk-go/aws/awserr"
14 "github.com/aws/aws-sdk-go/aws/client"
15 "github.com/aws/aws-sdk-go/aws/corehandlers"
16 "github.com/aws/aws-sdk-go/aws/credentials"
17 "github.com/aws/aws-sdk-go/aws/credentials/processcreds"
18 "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
19 "github.com/aws/aws-sdk-go/aws/csm"
20 "github.com/aws/aws-sdk-go/aws/defaults"
21 "github.com/aws/aws-sdk-go/aws/endpoints"
22 "github.com/aws/aws-sdk-go/aws/request"
23 "github.com/aws/aws-sdk-go/internal/shareddefaults"
24)
25
26const (
27 // ErrCodeSharedConfig represents an error that occurs in the shared
28 // configuration logic
29 ErrCodeSharedConfig = "SharedConfigErr"
30)
31
32// ErrSharedConfigSourceCollision will be returned if a section contains both
33// source_profile and credential_source
34var ErrSharedConfigSourceCollision = awserr.New(ErrCodeSharedConfig, "only source profile or credential source can be specified, not both", nil)
35
36// ErrSharedConfigECSContainerEnvVarEmpty will be returned if the environment
37// variables are empty and Environment was set as the credential source
38var ErrSharedConfigECSContainerEnvVarEmpty = awserr.New(ErrCodeSharedConfig, "EcsContainer was specified as the credential_source, but 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' was not set", nil)
39
40// ErrSharedConfigInvalidCredSource will be returned if an invalid credential source was provided
41var ErrSharedConfigInvalidCredSource = awserr.New(ErrCodeSharedConfig, "credential source values must be EcsContainer, Ec2InstanceMetadata, or Environment", nil)
42
43// A Session provides a central location to create service clients from and
44// store configurations and request handlers for those services.
45//
46// Sessions are safe to create service clients concurrently, but it is not safe
47// to mutate the Session concurrently.
48//
49// The Session satisfies the service client's client.ConfigProvider.
50type Session struct {
51 Config *aws.Config
52 Handlers request.Handlers
53}
54
55// New creates a new instance of the handlers merging in the provided configs
56// on top of the SDK's default configurations. Once the Session is created it
57// can be mutated to modify the Config or Handlers. The Session is safe to be
58// read concurrently, but it should not be written to concurrently.
59//
60// If the AWS_SDK_LOAD_CONFIG environment is set to a truthy value, the New
61// method could now encounter an error when loading the configuration. When
62// The environment variable is set, and an error occurs, New will return a
63// session that will fail all requests reporting the error that occurred while
64// loading the session. Use NewSession to get the error when creating the
65// session.
66//
67// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
68// the shared config file (~/.aws/config) will also be loaded, in addition to
69// the shared credentials file (~/.aws/credentials). Values set in both the
70// shared config, and shared credentials will be taken from the shared
71// credentials file.
72//
73// Deprecated: Use NewSession functions to create sessions instead. NewSession
74// has the same functionality as New except an error can be returned when the
75// func is called instead of waiting to receive an error until a request is made.
76func New(cfgs ...*aws.Config) *Session {
77 // load initial config from environment
78 envCfg := loadEnvConfig()
79
80 if envCfg.EnableSharedConfig {
81 var cfg aws.Config
82 cfg.MergeIn(cfgs...)
83 s, err := NewSessionWithOptions(Options{
84 Config: cfg,
85 SharedConfigState: SharedConfigEnable,
86 })
87 if err != nil {
88 // Old session.New expected all errors to be discovered when
89 // a request is made, and would report the errors then. This
90 // needs to be replicated if an error occurs while creating
91 // the session.
92 msg := "failed to create session with AWS_SDK_LOAD_CONFIG enabled. " +
93 "Use session.NewSession to handle errors occurring during session creation."
94
95 // Session creation failed, need to report the error and prevent
96 // any requests from succeeding.
97 s = &Session{Config: defaults.Config()}
98 s.Config.MergeIn(cfgs...)
99 s.Config.Logger.Log("ERROR:", msg, "Error:", err)
100 s.Handlers.Validate.PushBack(func(r *request.Request) {
101 r.Error = err
102 })
103 }
104
105 return s
106 }
107
108 s := deprecatedNewSession(cfgs...)
109 if envCfg.CSMEnabled {
110 enableCSM(&s.Handlers, envCfg.CSMClientID, envCfg.CSMPort, s.Config.Logger)
111 }
112
113 return s
114}
115
116// NewSession returns a new Session created from SDK defaults, config files,
117// environment, and user provided config files. Once the Session is created
118// it can be mutated to modify the Config or Handlers. The Session is safe to
119// be read concurrently, but it should not be written to concurrently.
120//
121// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
122// the shared config file (~/.aws/config) will also be loaded in addition to
123// the shared credentials file (~/.aws/credentials). Values set in both the
124// shared config, and shared credentials will be taken from the shared
125// credentials file. Enabling the Shared Config will also allow the Session
126// to be built with retrieving credentials with AssumeRole set in the config.
127//
128// See the NewSessionWithOptions func for information on how to override or
129// control through code how the Session will be created. Such as specifying the
130// config profile, and controlling if shared config is enabled or not.
131func NewSession(cfgs ...*aws.Config) (*Session, error) {
132 opts := Options{}
133 opts.Config.MergeIn(cfgs...)
134
135 return NewSessionWithOptions(opts)
136}
137
138// SharedConfigState provides the ability to optionally override the state
139// of the session's creation based on the shared config being enabled or
140// disabled.
141type SharedConfigState int
142
143const (
144 // SharedConfigStateFromEnv does not override any state of the
145 // AWS_SDK_LOAD_CONFIG env var. It is the default value of the
146 // SharedConfigState type.
147 SharedConfigStateFromEnv SharedConfigState = iota
148
149 // SharedConfigDisable overrides the AWS_SDK_LOAD_CONFIG env var value
150 // and disables the shared config functionality.
151 SharedConfigDisable
152
153 // SharedConfigEnable overrides the AWS_SDK_LOAD_CONFIG env var value
154 // and enables the shared config functionality.
155 SharedConfigEnable
156)
157
158// Options provides the means to control how a Session is created and what
159// configuration values will be loaded.
160//
161type Options struct {
162 // Provides config values for the SDK to use when creating service clients
163 // and making API requests to services. Any value set in with this field
164 // will override the associated value provided by the SDK defaults,
165 // environment or config files where relevant.
166 //
167 // If not set, configuration values from from SDK defaults, environment,
168 // config will be used.
169 Config aws.Config
170
171 // Overrides the config profile the Session should be created from. If not
172 // set the value of the environment variable will be loaded (AWS_PROFILE,
173 // or AWS_DEFAULT_PROFILE if the Shared Config is enabled).
174 //
175 // If not set and environment variables are not set the "default"
176 // (DefaultSharedConfigProfile) will be used as the profile to load the
177 // session config from.
178 Profile string
179
180 // Instructs how the Session will be created based on the AWS_SDK_LOAD_CONFIG
181 // environment variable. By default a Session will be created using the
182 // value provided by the AWS_SDK_LOAD_CONFIG environment variable.
183 //
184 // Setting this value to SharedConfigEnable or SharedConfigDisable
185 // will allow you to override the AWS_SDK_LOAD_CONFIG environment variable
186 // and enable or disable the shared config functionality.
187 SharedConfigState SharedConfigState
188
189 // Ordered list of files the session will load configuration from.
190 // It will override environment variable AWS_SHARED_CREDENTIALS_FILE, AWS_CONFIG_FILE.
191 SharedConfigFiles []string
192
193 // When the SDK's shared config is configured to assume a role with MFA
194 // this option is required in order to provide the mechanism that will
195 // retrieve the MFA token. There is no default value for this field. If
196 // it is not set an error will be returned when creating the session.
197 //
198 // This token provider will be called when ever the assumed role's
199 // credentials need to be refreshed. Within the context of service clients
200 // all sharing the same session the SDK will ensure calls to the token
201 // provider are atomic. When sharing a token provider across multiple
202 // sessions additional synchronization logic is needed to ensure the
203 // token providers do not introduce race conditions. It is recommend to
204 // share the session where possible.
205 //
206 // stscreds.StdinTokenProvider is a basic implementation that will prompt
207 // from stdin for the MFA token code.
208 //
209 // This field is only used if the shared configuration is enabled, and
210 // the config enables assume role wit MFA via the mfa_serial field.
211 AssumeRoleTokenProvider func() (string, error)
212
213 // Reader for a custom Credentials Authority (CA) bundle in PEM format that
214 // the SDK will use instead of the default system's root CA bundle. Use this
215 // only if you want to replace the CA bundle the SDK uses for TLS requests.
216 //
217 // Enabling this option will attempt to merge the Transport into the SDK's HTTP
218 // client. If the client's Transport is not a http.Transport an error will be
219 // returned. If the Transport's TLS config is set this option will cause the SDK
220 // to overwrite the Transport's TLS config's RootCAs value. If the CA
221 // bundle reader contains multiple certificates all of them will be loaded.
222 //
223 // The Session option CustomCABundle is also available when creating sessions
224 // to also enable this feature. CustomCABundle session option field has priority
225 // over the AWS_CA_BUNDLE environment variable, and will be used if both are set.
226 CustomCABundle io.Reader
227}
228
229// NewSessionWithOptions returns a new Session created from SDK defaults, config files,
230// environment, and user provided config files. This func uses the Options
231// values to configure how the Session is created.
232//
233// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
234// the shared config file (~/.aws/config) will also be loaded in addition to
235// the shared credentials file (~/.aws/credentials). Values set in both the
236// shared config, and shared credentials will be taken from the shared
237// credentials file. Enabling the Shared Config will also allow the Session
238// to be built with retrieving credentials with AssumeRole set in the config.
239//
240// // Equivalent to session.New
241// sess := session.Must(session.NewSessionWithOptions(session.Options{}))
242//
243// // Specify profile to load for the session's config
244// sess := session.Must(session.NewSessionWithOptions(session.Options{
245// Profile: "profile_name",
246// }))
247//
248// // Specify profile for config and region for requests
249// sess := session.Must(session.NewSessionWithOptions(session.Options{
250// Config: aws.Config{Region: aws.String("us-east-1")},
251// Profile: "profile_name",
252// }))
253//
254// // Force enable Shared Config support
255// sess := session.Must(session.NewSessionWithOptions(session.Options{
256// SharedConfigState: session.SharedConfigEnable,
257// }))
258func NewSessionWithOptions(opts Options) (*Session, error) {
259 var envCfg envConfig
260 if opts.SharedConfigState == SharedConfigEnable {
261 envCfg = loadSharedEnvConfig()
262 } else {
263 envCfg = loadEnvConfig()
264 }
265
266 if len(opts.Profile) > 0 {
267 envCfg.Profile = opts.Profile
268 }
269
270 switch opts.SharedConfigState {
271 case SharedConfigDisable:
272 envCfg.EnableSharedConfig = false
273 case SharedConfigEnable:
274 envCfg.EnableSharedConfig = true
275 }
276
277 // Only use AWS_CA_BUNDLE if session option is not provided.
278 if len(envCfg.CustomCABundle) != 0 && opts.CustomCABundle == nil {
279 f, err := os.Open(envCfg.CustomCABundle)
280 if err != nil {
281 return nil, awserr.New("LoadCustomCABundleError",
282 "failed to open custom CA bundle PEM file", err)
283 }
284 defer f.Close()
285 opts.CustomCABundle = f
286 }
287
288 return newSession(opts, envCfg, &opts.Config)
289}
290
291// Must is a helper function to ensure the Session is valid and there was no
292// error when calling a NewSession function.
293//
294// This helper is intended to be used in variable initialization to load the
295// Session and configuration at startup. Such as:
296//
297// var sess = session.Must(session.NewSession())
298func Must(sess *Session, err error) *Session {
299 if err != nil {
300 panic(err)
301 }
302
303 return sess
304}
305
306func deprecatedNewSession(cfgs ...*aws.Config) *Session {
307 cfg := defaults.Config()
308 handlers := defaults.Handlers()
309
310 // Apply the passed in configs so the configuration can be applied to the
311 // default credential chain
312 cfg.MergeIn(cfgs...)
313 if cfg.EndpointResolver == nil {
314 // An endpoint resolver is required for a session to be able to provide
315 // endpoints for service client configurations.
316 cfg.EndpointResolver = endpoints.DefaultResolver()
317 }
318 cfg.Credentials = defaults.CredChain(cfg, handlers)
319
320 // Reapply any passed in configs to override credentials if set
321 cfg.MergeIn(cfgs...)
322
323 s := &Session{
324 Config: cfg,
325 Handlers: handlers,
326 }
327
328 initHandlers(s)
329 return s
330}
331
332func enableCSM(handlers *request.Handlers, clientID string, port string, logger aws.Logger) {
333 logger.Log("Enabling CSM")
334 if len(port) == 0 {
335 port = csm.DefaultPort
336 }
337
338 r, err := csm.Start(clientID, "127.0.0.1:"+port)
339 if err != nil {
340 return
341 }
342 r.InjectHandlers(handlers)
343}
344
345func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
346 cfg := defaults.Config()
347 handlers := defaults.Handlers()
348
349 // Get a merged version of the user provided config to determine if
350 // credentials were.
351 userCfg := &aws.Config{}
352 userCfg.MergeIn(cfgs...)
353
354 // Ordered config files will be loaded in with later files overwriting
355 // previous config file values.
356 var cfgFiles []string
357 if opts.SharedConfigFiles != nil {
358 cfgFiles = opts.SharedConfigFiles
359 } else {
360 cfgFiles = []string{envCfg.SharedConfigFile, envCfg.SharedCredentialsFile}
361 if !envCfg.EnableSharedConfig {
362 // The shared config file (~/.aws/config) is only loaded if instructed
363 // to load via the envConfig.EnableSharedConfig (AWS_SDK_LOAD_CONFIG).
364 cfgFiles = cfgFiles[1:]
365 }
366 }
367
368 // Load additional config from file(s)
369 sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles)
370 if err != nil {
371 return nil, err
372 }
373
374 if err := mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers, opts); err != nil {
375 return nil, err
376 }
377
378 s := &Session{
379 Config: cfg,
380 Handlers: handlers,
381 }
382
383 initHandlers(s)
384 if envCfg.CSMEnabled {
385 enableCSM(&s.Handlers, envCfg.CSMClientID, envCfg.CSMPort, s.Config.Logger)
386 }
387
388 // Setup HTTP client with custom cert bundle if enabled
389 if opts.CustomCABundle != nil {
390 if err := loadCustomCABundle(s, opts.CustomCABundle); err != nil {
391 return nil, err
392 }
393 }
394
395 return s, nil
396}
397
398func loadCustomCABundle(s *Session, bundle io.Reader) error {
399 var t *http.Transport
400 switch v := s.Config.HTTPClient.Transport.(type) {
401 case *http.Transport:
402 t = v
403 default:
404 if s.Config.HTTPClient.Transport != nil {
405 return awserr.New("LoadCustomCABundleError",
406 "unable to load custom CA bundle, HTTPClient's transport unsupported type", nil)
407 }
408 }
409 if t == nil {
410 // Nil transport implies `http.DefaultTransport` should be used. Since
411 // the SDK cannot modify, nor copy the `DefaultTransport` specifying
412 // the values the next closest behavior.
413 t = getCABundleTransport()
414 }
415
416 p, err := loadCertPool(bundle)
417 if err != nil {
418 return err
419 }
420 if t.TLSClientConfig == nil {
421 t.TLSClientConfig = &tls.Config{}
422 }
423 t.TLSClientConfig.RootCAs = p
424
425 s.Config.HTTPClient.Transport = t
426
427 return nil
428}
429
430func loadCertPool(r io.Reader) (*x509.CertPool, error) {
431 b, err := ioutil.ReadAll(r)
432 if err != nil {
433 return nil, awserr.New("LoadCustomCABundleError",
434 "failed to read custom CA bundle PEM file", err)
435 }
436
437 p := x509.NewCertPool()
438 if !p.AppendCertsFromPEM(b) {
439 return nil, awserr.New("LoadCustomCABundleError",
440 "failed to load custom CA bundle PEM file", err)
441 }
442
443 return p, nil
444}
445
446func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers, sessOpts Options) error {
447 // Merge in user provided configuration
448 cfg.MergeIn(userCfg)
449
450 // Region if not already set by user
451 if len(aws.StringValue(cfg.Region)) == 0 {
452 if len(envCfg.Region) > 0 {
453 cfg.WithRegion(envCfg.Region)
454 } else if envCfg.EnableSharedConfig && len(sharedCfg.Region) > 0 {
455 cfg.WithRegion(sharedCfg.Region)
456 }
457 }
458
459 if cfg.EnableEndpointDiscovery == nil {
460 if envCfg.EnableEndpointDiscovery != nil {
461 cfg.WithEndpointDiscovery(*envCfg.EnableEndpointDiscovery)
462 } else if envCfg.EnableSharedConfig && sharedCfg.EnableEndpointDiscovery != nil {
463 cfg.WithEndpointDiscovery(*sharedCfg.EnableEndpointDiscovery)
464 }
465 }
466
467 // Configure credentials if not already set
468 if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
469
470 // inspect the profile to see if a credential source has been specified.
471 if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.CredentialSource) > 0 {
472
473 // if both credential_source and source_profile have been set, return an error
474 // as this is undefined behavior.
475 if len(sharedCfg.AssumeRole.SourceProfile) > 0 {
476 return ErrSharedConfigSourceCollision
477 }
478
479 // valid credential source values
480 const (
481 credSourceEc2Metadata = "Ec2InstanceMetadata"
482 credSourceEnvironment = "Environment"
483 credSourceECSContainer = "EcsContainer"
484 )
485
486 switch sharedCfg.AssumeRole.CredentialSource {
487 case credSourceEc2Metadata:
488 cfgCp := *cfg
489 p := defaults.RemoteCredProvider(cfgCp, handlers)
490 cfgCp.Credentials = credentials.NewCredentials(p)
491
492 if len(sharedCfg.AssumeRole.MFASerial) > 0 && sessOpts.AssumeRoleTokenProvider == nil {
493 // AssumeRole Token provider is required if doing Assume Role
494 // with MFA.
495 return AssumeRoleTokenProviderNotSetError{}
496 }
497
498 cfg.Credentials = assumeRoleCredentials(cfgCp, handlers, sharedCfg, sessOpts)
499 case credSourceEnvironment:
500 cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
501 envCfg.Creds,
502 )
503 case credSourceECSContainer:
504 if len(os.Getenv(shareddefaults.ECSCredsProviderEnvVar)) == 0 {
505 return ErrSharedConfigECSContainerEnvVarEmpty
506 }
507
508 cfgCp := *cfg
509 p := defaults.RemoteCredProvider(cfgCp, handlers)
510 creds := credentials.NewCredentials(p)
511
512 cfg.Credentials = creds
513 default:
514 return ErrSharedConfigInvalidCredSource
515 }
516
517 return nil
518 }
519
520 if len(envCfg.Creds.AccessKeyID) > 0 {
521 cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
522 envCfg.Creds,
523 )
524 } else if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.RoleARN) > 0 && sharedCfg.AssumeRoleSource != nil {
525 cfgCp := *cfg
526 cfgCp.Credentials = credentials.NewStaticCredentialsFromCreds(
527 sharedCfg.AssumeRoleSource.Creds,
528 )
529
530 if len(sharedCfg.AssumeRole.MFASerial) > 0 && sessOpts.AssumeRoleTokenProvider == nil {
531 // AssumeRole Token provider is required if doing Assume Role
532 // with MFA.
533 return AssumeRoleTokenProviderNotSetError{}
534 }
535
536 cfg.Credentials = assumeRoleCredentials(cfgCp, handlers, sharedCfg, sessOpts)
537 } else if len(sharedCfg.Creds.AccessKeyID) > 0 {
538 cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
539 sharedCfg.Creds,
540 )
541 } else if len(sharedCfg.CredentialProcess) > 0 {
542 cfg.Credentials = processcreds.NewCredentials(
543 sharedCfg.CredentialProcess,
544 )
545 } else {
546 // Fallback to default credentials provider, include mock errors
547 // for the credential chain so user can identify why credentials
548 // failed to be retrieved.
549 cfg.Credentials = credentials.NewCredentials(&credentials.ChainProvider{
550 VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
551 Providers: []credentials.Provider{
552 &credProviderError{Err: awserr.New("EnvAccessKeyNotFound", "failed to find credentials in the environment.", nil)},
553 &credProviderError{Err: awserr.New("SharedCredsLoad", fmt.Sprintf("failed to load profile, %s.", envCfg.Profile), nil)},
554 defaults.RemoteCredProvider(*cfg, handlers),
555 },
556 })
557 }
558 }
559
560 return nil
561}
562
563func assumeRoleCredentials(cfg aws.Config, handlers request.Handlers, sharedCfg sharedConfig, sessOpts Options) *credentials.Credentials {
564 return stscreds.NewCredentials(
565 &Session{
566 Config: &cfg,
567 Handlers: handlers.Copy(),
568 },
569 sharedCfg.AssumeRole.RoleARN,
570 func(opt *stscreds.AssumeRoleProvider) {
571 opt.RoleSessionName = sharedCfg.AssumeRole.RoleSessionName
572
573 // Assume role with external ID
574 if len(sharedCfg.AssumeRole.ExternalID) > 0 {
575 opt.ExternalID = aws.String(sharedCfg.AssumeRole.ExternalID)
576 }
577
578 // Assume role with MFA
579 if len(sharedCfg.AssumeRole.MFASerial) > 0 {
580 opt.SerialNumber = aws.String(sharedCfg.AssumeRole.MFASerial)
581 opt.TokenProvider = sessOpts.AssumeRoleTokenProvider
582 }
583 },
584 )
585}
586
587// AssumeRoleTokenProviderNotSetError is an error returned when creating a session when the
588// MFAToken option is not set when shared config is configured load assume a
589// role with an MFA token.
590type AssumeRoleTokenProviderNotSetError struct{}
591
592// Code is the short id of the error.
593func (e AssumeRoleTokenProviderNotSetError) Code() string {
594 return "AssumeRoleTokenProviderNotSetError"
595}
596
597// Message is the description of the error
598func (e AssumeRoleTokenProviderNotSetError) Message() string {
599 return fmt.Sprintf("assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.")
600}
601
602// OrigErr is the underlying error that caused the failure.
603func (e AssumeRoleTokenProviderNotSetError) OrigErr() error {
604 return nil
605}
606
607// Error satisfies the error interface.
608func (e AssumeRoleTokenProviderNotSetError) Error() string {
609 return awserr.SprintError(e.Code(), e.Message(), "", nil)
610}
611
612type credProviderError struct {
613 Err error
614}
615
616var emptyCreds = credentials.Value{}
617
618func (c credProviderError) Retrieve() (credentials.Value, error) {
619 return credentials.Value{}, c.Err
620}
621func (c credProviderError) IsExpired() bool {
622 return true
623}
624
625func initHandlers(s *Session) {
626 // Add the Validate parameter handler if it is not disabled.
627 s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
628 if !aws.BoolValue(s.Config.DisableParamValidation) {
629 s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
630 }
631}
632
633// Copy creates and returns a copy of the current Session, coping the config
634// and handlers. If any additional configs are provided they will be merged
635// on top of the Session's copied config.
636//
637// // Create a copy of the current Session, configured for the us-west-2 region.
638// sess.Copy(&aws.Config{Region: aws.String("us-west-2")})
639func (s *Session) Copy(cfgs ...*aws.Config) *Session {
640 newSession := &Session{
641 Config: s.Config.Copy(cfgs...),
642 Handlers: s.Handlers.Copy(),
643 }
644
645 initHandlers(newSession)
646
647 return newSession
648}
649
650// ClientConfig satisfies the client.ConfigProvider interface and is used to
651// configure the service client instances. Passing the Session to the service
652// client's constructor (New) will use this method to configure the client.
653func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
654 // Backwards compatibility, the error will be eaten if user calls ClientConfig
655 // directly. All SDK services will use ClientconfigWithError.
656 cfg, _ := s.clientConfigWithErr(serviceName, cfgs...)
657
658 return cfg
659}
660
661func (s *Session) clientConfigWithErr(serviceName string, cfgs ...*aws.Config) (client.Config, error) {
662 s = s.Copy(cfgs...)
663
664 var resolved endpoints.ResolvedEndpoint
665 var err error
666
667 region := aws.StringValue(s.Config.Region)
668
669 if endpoint := aws.StringValue(s.Config.Endpoint); len(endpoint) != 0 {
670 resolved.URL = endpoints.AddScheme(endpoint, aws.BoolValue(s.Config.DisableSSL))
671 resolved.SigningRegion = region
672 } else {
673 resolved, err = s.Config.EndpointResolver.EndpointFor(
674 serviceName, region,
675 func(opt *endpoints.Options) {
676 opt.DisableSSL = aws.BoolValue(s.Config.DisableSSL)
677 opt.UseDualStack = aws.BoolValue(s.Config.UseDualStack)
678
679 // Support the condition where the service is modeled but its
680 // endpoint metadata is not available.
681 opt.ResolveUnknownService = true
682 },
683 )
684 }
685
686 return client.Config{
687 Config: s.Config,
688 Handlers: s.Handlers,
689 Endpoint: resolved.URL,
690 SigningRegion: resolved.SigningRegion,
691 SigningNameDerived: resolved.SigningNameDerived,
692 SigningName: resolved.SigningName,
693 }, err
694}
695
696// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception
697// that the EndpointResolver will not be used to resolve the endpoint. The only
698// endpoint set must come from the aws.Config.Endpoint field.
699func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Config {
700 s = s.Copy(cfgs...)
701
702 var resolved endpoints.ResolvedEndpoint
703
704 region := aws.StringValue(s.Config.Region)
705
706 if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 {
707 resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL))
708 resolved.SigningRegion = region
709 }
710
711 return client.Config{
712 Config: s.Config,
713 Handlers: s.Handlers,
714 Endpoint: resolved.URL,
715 SigningRegion: resolved.SigningRegion,
716 SigningNameDerived: resolved.SigningNameDerived,
717 SigningName: resolved.SigningName,
718 }
719}