TUN-3375: Upgrade coredns and prometheus dependencies
This commit is contained in:
parent
7acea1ac99
commit
741cd66c9e
71
go.mod
71
go.mod
|
@ -1,22 +1,19 @@
|
||||||
module github.com/cloudflare/cloudflared
|
module github.com/cloudflare/cloudflared
|
||||||
|
|
||||||
go 1.12
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/go-sumtype v0.0.0-20190304192233-fcb4a6205bdc // indirect
|
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3
|
github.com/DATA-DOG/go-sqlmock v1.3.3
|
||||||
github.com/acmacalister/skittles v0.0.0-20160609003031-7423546701e1
|
github.com/acmacalister/skittles v0.0.0-20160609003031-7423546701e1
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.25.8
|
github.com/aws/aws-sdk-go v1.34.19
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
|
||||||
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 // indirect
|
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 // indirect
|
||||||
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93
|
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93
|
||||||
github.com/cloudflare/cfssl v0.0.0-20141119014638-2f7f44e802e2 // indirect
|
|
||||||
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc
|
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc
|
||||||
github.com/coredns/coredns v1.2.0
|
github.com/coredns/coredns v1.7.0
|
||||||
github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73
|
github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73
|
||||||
github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a
|
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||||
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0
|
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0
|
||||||
github.com/equinox-io/equinox v1.2.0
|
github.com/equinox-io/equinox v1.2.0
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
|
||||||
|
@ -24,57 +21,45 @@ require (
|
||||||
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434
|
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
|
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
github.com/frankban/quicktest v1.10.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.4.9
|
github.com/fsnotify/fsnotify v1.4.9
|
||||||
github.com/getsentry/raven-go v0.0.0-20180517221441-ed7bcb39ff10
|
github.com/getsentry/raven-go v0.0.0-20180517221441-ed7bcb39ff10
|
||||||
github.com/gliderlabs/ssh v0.0.0-20191009160644-63518b5243e0
|
github.com/gliderlabs/ssh v0.0.0-20191009160644-63518b5243e0
|
||||||
github.com/go-sql-driver/mysql v1.4.1
|
github.com/go-sql-driver/mysql v1.5.0
|
||||||
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/go-cmp v0.5.2 // indirect
|
||||||
|
github.com/google/uuid v1.1.2
|
||||||
github.com/gorilla/mux v1.7.3
|
github.com/gorilla/mux v1.7.3
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/kshvakov/clickhouse v1.3.11
|
github.com/kshvakov/clickhouse v1.3.11
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/lib/pq v1.2.0
|
github.com/lib/pq v1.2.0
|
||||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.10 // indirect
|
|
||||||
github.com/mattn/go-sqlite3 v1.11.0
|
github.com/mattn/go-sqlite3 v1.11.0
|
||||||
github.com/mholt/caddy v0.0.0-20180807230124-d3b731e9255b // indirect
|
github.com/miekg/dns v1.1.31
|
||||||
github.com/miekg/dns v1.1.27
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/opentracing/opentracing-go v1.1.0 // indirect
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
github.com/philhofer/fwd v1.0.0 // indirect
|
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||||
github.com/prometheus/client_golang v1.0.0
|
github.com/prometheus/client_golang v1.7.1
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect
|
github.com/prometheus/common v0.13.0 // indirect
|
||||||
github.com/prometheus/common v0.7.0 // indirect
|
github.com/stretchr/testify v1.6.0
|
||||||
github.com/prometheus/procfs v0.0.5 // indirect
|
|
||||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
|
|
||||||
github.com/stretchr/testify v1.3.0
|
|
||||||
github.com/tinylib/msgp v1.1.0 // indirect
|
|
||||||
github.com/urfave/cli/v2 v2.2.0
|
github.com/urfave/cli/v2 v2.2.0
|
||||||
github.com/xo/dburl v0.0.0-20191005012637-293c3298d6c0
|
github.com/xo/dburl v0.0.0-20191005012637-293c3298d6c0
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344
|
golang.org/x/net v0.0.0-20200904194848-62affa334b73
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
|
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
|
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009
|
||||||
golang.org/x/text v0.3.3 // indirect
|
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d // indirect
|
||||||
google.golang.org/appengine v1.5.0 // indirect
|
google.golang.org/grpc v1.32.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20191007204434-a023cd5227bd // indirect
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||||
google.golang.org/grpc v1.24.0 // indirect
|
|
||||||
gopkg.in/coreos/go-oidc.v2 v2.1.0
|
gopkg.in/coreos/go-oidc.v2 v2.1.0
|
||||||
gopkg.in/square/go-jose.v2 v2.4.0 // indirect
|
gopkg.in/square/go-jose.v2 v2.4.0 // indirect
|
||||||
gopkg.in/urfave/cli.v2 v2.0.0-20180128181224-d604b6ffeee8 // indirect
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
gopkg.in/yaml.v2 v2.2.4
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
||||||
zombiezen.com/go/capnproto2 v2.18.0+incompatible
|
zombiezen.com/go/capnproto2 v2.18.0+incompatible
|
||||||
)
|
)
|
||||||
|
|
||||||
// ../../go/pkg/mod/github.com/coredns/coredns@v1.2.0/plugin/metrics/metrics.go:40:49: too many arguments in call to prometheus.NewProcessCollector
|
|
||||||
// have (int, string)
|
|
||||||
// want (prometheus.ProcessCollectorOpts)
|
|
||||||
replace github.com/prometheus/client_golang => github.com/prometheus/client_golang v0.9.0-pre1
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/coredns/coredns/plugin"
|
"github.com/coredns/coredns/plugin"
|
||||||
|
"github.com/coredns/coredns/plugin/metrics"
|
||||||
"github.com/coredns/coredns/plugin/metrics/vars"
|
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||||
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||||||
"github.com/coredns/coredns/plugin/pkg/rcode"
|
"github.com/coredns/coredns/plugin/pkg/rcode"
|
||||||
|
@ -27,7 +28,6 @@ func NewMetricsPlugin(next plugin.Handler) *MetricsPlugin {
|
||||||
prometheus.MustRegister(vars.RequestDuration)
|
prometheus.MustRegister(vars.RequestDuration)
|
||||||
prometheus.MustRegister(vars.RequestSize)
|
prometheus.MustRegister(vars.RequestSize)
|
||||||
prometheus.MustRegister(vars.RequestDo)
|
prometheus.MustRegister(vars.RequestDo)
|
||||||
prometheus.MustRegister(vars.RequestType)
|
|
||||||
prometheus.MustRegister(vars.ResponseSize)
|
prometheus.MustRegister(vars.ResponseSize)
|
||||||
prometheus.MustRegister(vars.ResponseRcode)
|
prometheus.MustRegister(vars.ResponseRcode)
|
||||||
})
|
})
|
||||||
|
@ -42,7 +42,8 @@ func (p MetricsPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dn
|
||||||
status, err := plugin.NextOrFailure(p.Name(), p.Next, ctx, rw, r)
|
status, err := plugin.NextOrFailure(p.Name(), p.Next, ctx, rw, r)
|
||||||
|
|
||||||
// Update built-in metrics
|
// Update built-in metrics
|
||||||
vars.Report(ctx, state, ".", rcode.ToString(rw.Rcode), rw.Len, rw.Start)
|
server := metrics.WithServer(ctx)
|
||||||
|
vars.Report(server, state, ".", rcode.ToString(rw.Rcode), rw.Len, rw.Start)
|
||||||
|
|
||||||
return status, err
|
return status, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ var (
|
||||||
|
|
||||||
// ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB
|
// ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB
|
||||||
// and KiB are both 1024.
|
// and KiB are both 1024.
|
||||||
|
// However "kB", which is the correct SI spelling of 1000 Bytes, is rejected.
|
||||||
func ParseBase2Bytes(s string) (Base2Bytes, error) {
|
func ParseBase2Bytes(s string) (Base2Bytes, error) {
|
||||||
n, err := ParseUnit(s, bytesUnitMap)
|
n, err := ParseUnit(s, bytesUnitMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -68,12 +69,13 @@ func ParseMetricBytes(s string) (MetricBytes, error) {
|
||||||
return MetricBytes(n), err
|
return MetricBytes(n), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: represents 1000B as uppercase "KB", while SI standard requires "kB".
|
||||||
func (m MetricBytes) String() string {
|
func (m MetricBytes) String() string {
|
||||||
return ToString(int64(m), 1000, "B", "B")
|
return ToString(int64(m), 1000, "B", "B")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseStrictBytes supports both iB and B suffixes for base 2 and metric,
|
// ParseStrictBytes supports both iB and B suffixes for base 2 and metric,
|
||||||
// respectively. That is, KiB represents 1024 and KB represents 1000.
|
// respectively. That is, KiB represents 1024 and kB, KB represent 1000.
|
||||||
func ParseStrictBytes(s string) (int64, error) {
|
func ParseStrictBytes(s string) (int64, error) {
|
||||||
n, err := ParseUnit(s, bytesUnitMap)
|
n, err := ParseUnit(s, bytesUnitMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
module github.com/alecthomas/units
|
module github.com/alecthomas/units
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.4.0
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
@ -14,13 +14,37 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 {
|
func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 {
|
||||||
return map[string]float64{
|
res := map[string]float64{
|
||||||
shortSuffix: 1,
|
shortSuffix: 1,
|
||||||
"K" + suffix: float64(scale),
|
// see below for "k" / "K"
|
||||||
"M" + suffix: float64(scale * scale),
|
"M" + suffix: float64(scale * scale),
|
||||||
"G" + suffix: float64(scale * scale * scale),
|
"G" + suffix: float64(scale * scale * scale),
|
||||||
"T" + suffix: float64(scale * scale * scale * scale),
|
"T" + suffix: float64(scale * scale * scale * scale),
|
||||||
"P" + suffix: float64(scale * scale * scale * scale * scale),
|
"P" + suffix: float64(scale * scale * scale * scale * scale),
|
||||||
"E" + suffix: float64(scale * scale * scale * scale * scale * scale),
|
"E" + suffix: float64(scale * scale * scale * scale * scale * scale),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Standard SI prefixes use lowercase "k" for kilo = 1000.
|
||||||
|
// For compatibility, and to be fool-proof, we accept both "k" and "K" in metric mode.
|
||||||
|
//
|
||||||
|
// However, official binary prefixes are always capitalized - "KiB" -
|
||||||
|
// and we specifically never parse "kB" as 1024B because:
|
||||||
|
//
|
||||||
|
// (1) people pedantic enough to use lowercase according to SI unlikely to abuse "k" to mean 1024 :-)
|
||||||
|
//
|
||||||
|
// (2) Use of capital K for 1024 was an informal tradition predating IEC prefixes:
|
||||||
|
// "The binary meaning of the kilobyte for 1024 bytes typically uses the symbol KB, with an
|
||||||
|
// uppercase letter K."
|
||||||
|
// -- https://en.wikipedia.org/wiki/Kilobyte#Base_2_(1024_bytes)
|
||||||
|
// "Capitalization of the letter K became the de facto standard for binary notation, although this
|
||||||
|
// could not be extended to higher powers, and use of the lowercase k did persist.[13][14][15]"
|
||||||
|
// -- https://en.wikipedia.org/wiki/Binary_prefix#History
|
||||||
|
// See also the extensive https://en.wikipedia.org/wiki/Timeline_of_binary_prefixes.
|
||||||
|
if scale == 1024 {
|
||||||
|
res["K"+suffix] = float64(scale)
|
||||||
|
} else {
|
||||||
|
res["k"+suffix] = float64(scale)
|
||||||
|
res["K"+suffix] = float64(scale)
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
// Package arn provides a parser for interacting with Amazon Resource Names.
|
||||||
|
package arn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
arnDelimiter = ":"
|
||||||
|
arnSections = 6
|
||||||
|
arnPrefix = "arn:"
|
||||||
|
|
||||||
|
// zero-indexed
|
||||||
|
sectionPartition = 1
|
||||||
|
sectionService = 2
|
||||||
|
sectionRegion = 3
|
||||||
|
sectionAccountID = 4
|
||||||
|
sectionResource = 5
|
||||||
|
|
||||||
|
// errors
|
||||||
|
invalidPrefix = "arn: invalid prefix"
|
||||||
|
invalidSections = "arn: not enough sections"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ARN captures the individual fields of an Amazon Resource Name.
|
||||||
|
// See http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html for more information.
|
||||||
|
type ARN struct {
|
||||||
|
// The partition that the resource is in. For standard AWS regions, the partition is "aws". If you have resources in
|
||||||
|
// other partitions, the partition is "aws-partitionname". For example, the partition for resources in the China
|
||||||
|
// (Beijing) region is "aws-cn".
|
||||||
|
Partition string
|
||||||
|
|
||||||
|
// The service namespace that identifies the AWS product (for example, Amazon S3, IAM, or Amazon RDS). For a list of
|
||||||
|
// namespaces, see
|
||||||
|
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces.
|
||||||
|
Service string
|
||||||
|
|
||||||
|
// The region the resource resides in. Note that the ARNs for some resources do not require a region, so this
|
||||||
|
// component might be omitted.
|
||||||
|
Region string
|
||||||
|
|
||||||
|
// The ID of the AWS account that owns the resource, without the hyphens. For example, 123456789012. Note that the
|
||||||
|
// ARNs for some resources don't require an account number, so this component might be omitted.
|
||||||
|
AccountID string
|
||||||
|
|
||||||
|
// The content of this part of the ARN varies by service. It often includes an indicator of the type of resource —
|
||||||
|
// for example, an IAM user or Amazon RDS database - followed by a slash (/) or a colon (:), followed by the
|
||||||
|
// resource name itself. Some services allows paths for resource names, as described in
|
||||||
|
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-paths.
|
||||||
|
Resource string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses an ARN into its constituent parts.
|
||||||
|
//
|
||||||
|
// Some example ARNs:
|
||||||
|
// arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment
|
||||||
|
// arn:aws:iam::123456789012:user/David
|
||||||
|
// arn:aws:rds:eu-west-1:123456789012:db:mysql-db
|
||||||
|
// arn:aws:s3:::my_corporate_bucket/exampleobject.png
|
||||||
|
func Parse(arn string) (ARN, error) {
|
||||||
|
if !strings.HasPrefix(arn, arnPrefix) {
|
||||||
|
return ARN{}, errors.New(invalidPrefix)
|
||||||
|
}
|
||||||
|
sections := strings.SplitN(arn, arnDelimiter, arnSections)
|
||||||
|
if len(sections) != arnSections {
|
||||||
|
return ARN{}, errors.New(invalidSections)
|
||||||
|
}
|
||||||
|
return ARN{
|
||||||
|
Partition: sections[sectionPartition],
|
||||||
|
Service: sections[sectionService],
|
||||||
|
Region: sections[sectionRegion],
|
||||||
|
AccountID: sections[sectionAccountID],
|
||||||
|
Resource: sections[sectionResource],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsARN returns whether the given string is an ARN by looking for
|
||||||
|
// whether the string starts with "arn:" and contains the correct number
|
||||||
|
// of sections delimited by colons(:).
|
||||||
|
func IsARN(arn string) bool {
|
||||||
|
return strings.HasPrefix(arn, arnPrefix) && strings.Count(arn, ":") >= arnSections-1
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the canonical representation of the ARN
|
||||||
|
func (arn ARN) String() string {
|
||||||
|
return arnPrefix +
|
||||||
|
arn.Partition + arnDelimiter +
|
||||||
|
arn.Service + arnDelimiter +
|
||||||
|
arn.Region + arnDelimiter +
|
||||||
|
arn.AccountID + arnDelimiter +
|
||||||
|
arn.Resource
|
||||||
|
}
|
|
@ -70,7 +70,7 @@ func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTer
|
||||||
value = value.FieldByNameFunc(func(name string) bool {
|
value = value.FieldByNameFunc(func(name string) bool {
|
||||||
if c == name {
|
if c == name {
|
||||||
return true
|
return true
|
||||||
} else if !caseSensitive && strings.ToLower(name) == strings.ToLower(c) {
|
} else if !caseSensitive && strings.EqualFold(name, c) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Config *aws.Config
|
Config *aws.Config
|
||||||
Handlers request.Handlers
|
Handlers request.Handlers
|
||||||
|
PartitionID string
|
||||||
Endpoint string
|
Endpoint string
|
||||||
SigningRegion string
|
SigningRegion string
|
||||||
SigningName string
|
SigningName string
|
||||||
|
|
|
@ -5,6 +5,7 @@ type ClientInfo struct {
|
||||||
ServiceName string
|
ServiceName string
|
||||||
ServiceID string
|
ServiceID string
|
||||||
APIVersion string
|
APIVersion string
|
||||||
|
PartitionID string
|
||||||
Endpoint string
|
Endpoint string
|
||||||
SigningName string
|
SigningName string
|
||||||
SigningRegion string
|
SigningRegion string
|
||||||
|
|
|
@ -43,7 +43,7 @@ type Config struct {
|
||||||
|
|
||||||
// An optional endpoint URL (hostname only or fully qualified URI)
|
// An optional endpoint URL (hostname only or fully qualified URI)
|
||||||
// that overrides the default generated endpoint for a client. Set this
|
// that overrides the default generated endpoint for a client. Set this
|
||||||
// to `""` to use the default generated endpoint.
|
// to `nil` or the value to `""` to use the default generated endpoint.
|
||||||
//
|
//
|
||||||
// Note: You must still provide a `Region` value when specifying an
|
// Note: You must still provide a `Region` value when specifying an
|
||||||
// endpoint for a client.
|
// endpoint for a client.
|
||||||
|
@ -138,7 +138,7 @@ type Config struct {
|
||||||
// `ExpectContinueTimeout` for information on adjusting the continue wait
|
// `ExpectContinueTimeout` for information on adjusting the continue wait
|
||||||
// timeout. https://golang.org/pkg/net/http/#Transport
|
// timeout. https://golang.org/pkg/net/http/#Transport
|
||||||
//
|
//
|
||||||
// You should use this flag to disble 100-Continue if you experience issues
|
// You should use this flag to disable 100-Continue if you experience issues
|
||||||
// with proxies or third party S3 compatible services.
|
// with proxies or third party S3 compatible services.
|
||||||
S3Disable100Continue *bool
|
S3Disable100Continue *bool
|
||||||
|
|
||||||
|
@ -161,6 +161,17 @@ type Config struct {
|
||||||
// on GetObject API calls.
|
// on GetObject API calls.
|
||||||
S3DisableContentMD5Validation *bool
|
S3DisableContentMD5Validation *bool
|
||||||
|
|
||||||
|
// Set this to `true` to have the S3 service client to use the region specified
|
||||||
|
// in the ARN, when an ARN is provided as an argument to a bucket parameter.
|
||||||
|
S3UseARNRegion *bool
|
||||||
|
|
||||||
|
// Set this to `true` to enable the SDK to unmarshal API response header maps to
|
||||||
|
// normalized lower case map keys.
|
||||||
|
//
|
||||||
|
// For example S3's X-Amz-Meta prefixed header will be unmarshaled to lower case
|
||||||
|
// Metadata member's map keys. The value of the header in the map is unaffected.
|
||||||
|
LowerCaseHeaderMaps *bool
|
||||||
|
|
||||||
// Set this to `true` to disable the EC2Metadata client from overriding the
|
// Set this to `true` to disable the EC2Metadata client from overriding the
|
||||||
// default http.Client's Timeout. This is helpful if you do not want the
|
// default http.Client's Timeout. This is helpful if you do not want the
|
||||||
// EC2Metadata client to create a new http.Client. This options is only
|
// EC2Metadata client to create a new http.Client. This options is only
|
||||||
|
@ -172,7 +183,7 @@ type Config struct {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// sess := session.Must(session.NewSession(aws.NewConfig()
|
// sess := session.Must(session.NewSession(aws.NewConfig()
|
||||||
// .WithEC2MetadataDiableTimeoutOverride(true)))
|
// .WithEC2MetadataDisableTimeoutOverride(true)))
|
||||||
//
|
//
|
||||||
// svc := s3.New(sess)
|
// svc := s3.New(sess)
|
||||||
//
|
//
|
||||||
|
@ -183,7 +194,7 @@ type Config struct {
|
||||||
// both IPv4 and IPv6 addressing.
|
// both IPv4 and IPv6 addressing.
|
||||||
//
|
//
|
||||||
// Setting this for a service which does not support dual stack will fail
|
// Setting this for a service which does not support dual stack will fail
|
||||||
// to make requets. It is not recommended to set this value on the session
|
// to make requests. It is not recommended to set this value on the session
|
||||||
// as it will apply to all service clients created with the session. Even
|
// as it will apply to all service clients created with the session. Even
|
||||||
// services which don't support dual stack endpoints.
|
// services which don't support dual stack endpoints.
|
||||||
//
|
//
|
||||||
|
@ -227,6 +238,7 @@ type Config struct {
|
||||||
|
|
||||||
// EnableEndpointDiscovery will allow for endpoint discovery on operations that
|
// EnableEndpointDiscovery will allow for endpoint discovery on operations that
|
||||||
// have the definition in its model. By default, endpoint discovery is off.
|
// have the definition in its model. By default, endpoint discovery is off.
|
||||||
|
// To use EndpointDiscovery, Endpoint should be unset or set to an empty string.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// sess := session.Must(session.NewSession(&aws.Config{
|
// sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
@ -246,6 +258,12 @@ type Config struct {
|
||||||
// Disabling this feature is useful when you want to use local endpoints
|
// Disabling this feature is useful when you want to use local endpoints
|
||||||
// for testing that do not support the modeled host prefix pattern.
|
// for testing that do not support the modeled host prefix pattern.
|
||||||
DisableEndpointHostPrefix *bool
|
DisableEndpointHostPrefix *bool
|
||||||
|
|
||||||
|
// STSRegionalEndpoint will enable regional or legacy endpoint resolving
|
||||||
|
STSRegionalEndpoint endpoints.STSRegionalEndpoint
|
||||||
|
|
||||||
|
// S3UsEast1RegionalEndpoint will enable regional or legacy endpoint resolving
|
||||||
|
S3UsEast1RegionalEndpoint endpoints.S3UsEast1RegionalEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfig returns a new Config pointer that can be chained with builder
|
// NewConfig returns a new Config pointer that can be chained with builder
|
||||||
|
@ -379,6 +397,13 @@ func (c *Config) WithS3DisableContentMD5Validation(enable bool) *Config {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithS3UseARNRegion sets a config S3UseARNRegion value and
|
||||||
|
// returning a Config pointer for chaining
|
||||||
|
func (c *Config) WithS3UseARNRegion(enable bool) *Config {
|
||||||
|
c.S3UseARNRegion = &enable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// WithUseDualStack sets a config UseDualStack value returning a Config
|
// WithUseDualStack sets a config UseDualStack value returning a Config
|
||||||
// pointer for chaining.
|
// pointer for chaining.
|
||||||
func (c *Config) WithUseDualStack(enable bool) *Config {
|
func (c *Config) WithUseDualStack(enable bool) *Config {
|
||||||
|
@ -420,6 +445,20 @@ func (c *Config) MergeIn(cfgs ...*Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithSTSRegionalEndpoint will set whether or not to use regional endpoint flag
|
||||||
|
// when resolving the endpoint for a service
|
||||||
|
func (c *Config) WithSTSRegionalEndpoint(sre endpoints.STSRegionalEndpoint) *Config {
|
||||||
|
c.STSRegionalEndpoint = sre
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3UsEast1RegionalEndpoint will set whether or not to use regional endpoint flag
|
||||||
|
// when resolving the endpoint for a service
|
||||||
|
func (c *Config) WithS3UsEast1RegionalEndpoint(sre endpoints.S3UsEast1RegionalEndpoint) *Config {
|
||||||
|
c.S3UsEast1RegionalEndpoint = sre
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
func mergeInConfig(dst *Config, other *Config) {
|
func mergeInConfig(dst *Config, other *Config) {
|
||||||
if other == nil {
|
if other == nil {
|
||||||
return
|
return
|
||||||
|
@ -493,6 +532,10 @@ func mergeInConfig(dst *Config, other *Config) {
|
||||||
dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation
|
dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if other.S3UseARNRegion != nil {
|
||||||
|
dst.S3UseARNRegion = other.S3UseARNRegion
|
||||||
|
}
|
||||||
|
|
||||||
if other.UseDualStack != nil {
|
if other.UseDualStack != nil {
|
||||||
dst.UseDualStack = other.UseDualStack
|
dst.UseDualStack = other.UseDualStack
|
||||||
}
|
}
|
||||||
|
@ -520,6 +563,14 @@ func mergeInConfig(dst *Config, other *Config) {
|
||||||
if other.DisableEndpointHostPrefix != nil {
|
if other.DisableEndpointHostPrefix != nil {
|
||||||
dst.DisableEndpointHostPrefix = other.DisableEndpointHostPrefix
|
dst.DisableEndpointHostPrefix = other.DisableEndpointHostPrefix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if other.STSRegionalEndpoint != endpoints.UnsetSTSEndpoint {
|
||||||
|
dst.STSRegionalEndpoint = other.STSRegionalEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3UsEast1RegionalEndpoint != endpoints.UnsetS3UsEast1Endpoint {
|
||||||
|
dst.S3UsEast1RegionalEndpoint = other.S3UsEast1RegionalEndpoint
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy will return a shallow copy of the Config object. If any additional
|
// Copy will return a shallow copy of the Config object. If any additional
|
||||||
|
|
|
@ -2,42 +2,8 @@
|
||||||
|
|
||||||
package aws
|
package aws
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/internal/context"
|
||||||
// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to
|
|
||||||
// provide a 1.6 and 1.5 safe version of context that is compatible with Go
|
|
||||||
// 1.7's Context.
|
|
||||||
//
|
|
||||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
|
||||||
// struct{}, since vars of this type must have distinct addresses.
|
|
||||||
type emptyCtx int
|
|
||||||
|
|
||||||
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*emptyCtx) Done() <-chan struct{} {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*emptyCtx) Err() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*emptyCtx) Value(key interface{}) interface{} {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *emptyCtx) String() string {
|
|
||||||
switch e {
|
|
||||||
case backgroundCtx:
|
|
||||||
return "aws.BackgroundContext"
|
|
||||||
}
|
|
||||||
return "unknown empty Context"
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
backgroundCtx = new(emptyCtx)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BackgroundContext returns a context that will never be canceled, has no
|
// BackgroundContext returns a context that will never be canceled, has no
|
||||||
|
@ -52,5 +18,5 @@ var (
|
||||||
//
|
//
|
||||||
// See https://golang.org/pkg/context for more information on Contexts.
|
// See https://golang.org/pkg/context for more information on Contexts.
|
||||||
func BackgroundContext() Context {
|
func BackgroundContext() Context {
|
||||||
return backgroundCtx
|
return context.BackgroundCtx
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ func handleSendError(r *request.Request, err error) {
|
||||||
}
|
}
|
||||||
// Catch all request errors, and let the default retrier determine
|
// Catch all request errors, and let the default retrier determine
|
||||||
// if the error is retryable.
|
// if the error is retryable.
|
||||||
r.Error = awserr.New("RequestError", "send request failed", err)
|
r.Error = awserr.New(request.ErrCodeRequestError, "send request failed", err)
|
||||||
|
|
||||||
// Override the error with a context canceled error, if that was canceled.
|
// Override the error with a context canceled error, if that was canceled.
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
@ -225,6 +225,8 @@ var ValidateEndpointHandler = request.NamedHandler{Name: "core.ValidateEndpointH
|
||||||
if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" {
|
if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" {
|
||||||
r.Error = aws.ErrMissingRegion
|
r.Error = aws.ErrMissingRegion
|
||||||
} else if r.ClientInfo.Endpoint == "" {
|
} else if r.ClientInfo.Endpoint == "" {
|
||||||
|
// Was any endpoint provided by the user, or one was derived by the
|
||||||
|
// SDK's endpoint resolver?
|
||||||
r.Error = aws.ErrMissingEndpoint
|
r.Error = aws.ErrMissingEndpoint
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
22
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_background_go1.5.go
generated
vendored
Normal file
22
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_background_go1.5.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/internal/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// backgroundContext returns a context that will never be canceled, has no
|
||||||
|
// values, and no deadline. This context is used by the SDK to provide
|
||||||
|
// backwards compatibility with non-context API operations and functionality.
|
||||||
|
//
|
||||||
|
// Go 1.6 and before:
|
||||||
|
// This context function is equivalent to context.Background in the Go stdlib.
|
||||||
|
//
|
||||||
|
// Go 1.7 and later:
|
||||||
|
// The context returned will be the value returned by context.Background()
|
||||||
|
//
|
||||||
|
// See https://golang.org/pkg/context for more information on Contexts.
|
||||||
|
func backgroundContext() Context {
|
||||||
|
return context.BackgroundCtx
|
||||||
|
}
|
20
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_background_go1.7.go
generated
vendored
Normal file
20
vendor/github.com/aws/aws-sdk-go/aws/credentials/context_background_go1.7.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// backgroundContext returns a context that will never be canceled, has no
|
||||||
|
// values, and no deadline. This context is used by the SDK to provide
|
||||||
|
// backwards compatibility with non-context API operations and functionality.
|
||||||
|
//
|
||||||
|
// Go 1.6 and before:
|
||||||
|
// This context function is equivalent to context.Background in the Go stdlib.
|
||||||
|
//
|
||||||
|
// Go 1.7 and later:
|
||||||
|
// The context returned will be the value returned by context.Background()
|
||||||
|
//
|
||||||
|
// See https://golang.org/pkg/context for more information on Contexts.
|
||||||
|
func backgroundContext() Context {
|
||||||
|
return context.Background()
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Context is an copy of the Go v1.7 stdlib's context.Context interface.
|
||||||
|
// It is represented as a SDK interface to enable you to use the "WithContext"
|
||||||
|
// API methods with Go v1.6 and a Context type such as golang.org/x/net/context.
|
||||||
|
//
|
||||||
|
// This type, aws.Context, and context.Context are equivalent.
|
||||||
|
//
|
||||||
|
// See https://golang.org/pkg/context on how to use contexts.
|
||||||
|
type Context interface {
|
||||||
|
// Deadline returns the time when work done on behalf of this context
|
||||||
|
// should be canceled. Deadline returns ok==false when no deadline is
|
||||||
|
// set. Successive calls to Deadline return the same results.
|
||||||
|
Deadline() (deadline time.Time, ok bool)
|
||||||
|
|
||||||
|
// Done returns a channel that's closed when work done on behalf of this
|
||||||
|
// context should be canceled. Done may return nil if this context can
|
||||||
|
// never be canceled. Successive calls to Done return the same value.
|
||||||
|
Done() <-chan struct{}
|
||||||
|
|
||||||
|
// Err returns a non-nil error value after Done is closed. Err returns
|
||||||
|
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||||
|
// context's deadline passed. No other values for Err are defined.
|
||||||
|
// After Done is closed, successive calls to Err return the same value.
|
||||||
|
Err() error
|
||||||
|
|
||||||
|
// Value returns the value associated with this context for key, or nil
|
||||||
|
// if no value is associated with key. Successive calls to Value with
|
||||||
|
// the same key returns the same result.
|
||||||
|
//
|
||||||
|
// Use context values only for request-scoped data that transits
|
||||||
|
// processes and API boundaries, not for passing optional parameters to
|
||||||
|
// functions.
|
||||||
|
Value(key interface{}) interface{}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// Context is an alias of the Go stdlib's context.Context interface.
|
||||||
|
// It can be used within the SDK's API operation "WithContext" methods.
|
||||||
|
//
|
||||||
|
// This type, aws.Context, and context.Context are equivalent.
|
||||||
|
//
|
||||||
|
// See https://golang.org/pkg/context on how to use contexts.
|
||||||
|
type Context = context.Context
|
|
@ -50,10 +50,11 @@ package credentials
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/sync/singleflight"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AnonymousCredentials is an empty Credential object that can be used as
|
// AnonymousCredentials is an empty Credential object that can be used as
|
||||||
|
@ -106,6 +107,13 @@ type Provider interface {
|
||||||
IsExpired() bool
|
IsExpired() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProviderWithContext is a Provider that can retrieve credentials with a Context
|
||||||
|
type ProviderWithContext interface {
|
||||||
|
Provider
|
||||||
|
|
||||||
|
RetrieveWithContext(Context) (Value, error)
|
||||||
|
}
|
||||||
|
|
||||||
// An Expirer is an interface that Providers can implement to expose the expiration
|
// An Expirer is an interface that Providers can implement to expose the expiration
|
||||||
// time, if known. If the Provider cannot accurately provide this info,
|
// time, if known. If the Provider cannot accurately provide this info,
|
||||||
// it should not implement this interface.
|
// it should not implement this interface.
|
||||||
|
@ -197,20 +205,68 @@ func (e *Expiry) ExpiresAt() time.Time {
|
||||||
// first instance of the credentials Value. All calls to Get() after that
|
// first instance of the credentials Value. All calls to Get() after that
|
||||||
// will return the cached credentials Value until IsExpired() returns true.
|
// will return the cached credentials Value until IsExpired() returns true.
|
||||||
type Credentials struct {
|
type Credentials struct {
|
||||||
creds Value
|
creds atomic.Value
|
||||||
forceRefresh bool
|
sf singleflight.Group
|
||||||
|
|
||||||
m sync.RWMutex
|
|
||||||
|
|
||||||
provider Provider
|
provider Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCredentials returns a pointer to a new Credentials with the provider set.
|
// NewCredentials returns a pointer to a new Credentials with the provider set.
|
||||||
func NewCredentials(provider Provider) *Credentials {
|
func NewCredentials(provider Provider) *Credentials {
|
||||||
return &Credentials{
|
c := &Credentials{
|
||||||
provider: provider,
|
provider: provider,
|
||||||
forceRefresh: true,
|
|
||||||
}
|
}
|
||||||
|
c.creds.Store(Value{})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWithContext returns the credentials value, or error if the credentials
|
||||||
|
// Value failed to be retrieved. Will return early if the passed in context is
|
||||||
|
// canceled.
|
||||||
|
//
|
||||||
|
// Will return the cached credentials Value if it has not expired. If the
|
||||||
|
// credentials Value has expired the Provider's Retrieve() will be called
|
||||||
|
// to refresh the credentials.
|
||||||
|
//
|
||||||
|
// If Credentials.Expire() was called the credentials Value will be force
|
||||||
|
// expired, and the next call to Get() will cause them to be refreshed.
|
||||||
|
//
|
||||||
|
// Passed in Context is equivalent to aws.Context, and context.Context.
|
||||||
|
func (c *Credentials) GetWithContext(ctx Context) (Value, error) {
|
||||||
|
if curCreds := c.creds.Load(); !c.isExpired(curCreds) {
|
||||||
|
return curCreds.(Value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot pass context down to the actual retrieve, because the first
|
||||||
|
// context would cancel the whole group when there is not direct
|
||||||
|
// association of items in the group.
|
||||||
|
resCh := c.sf.DoChan("", func() (interface{}, error) {
|
||||||
|
return c.singleRetrieve(&suppressedContext{ctx})
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case res := <-resCh:
|
||||||
|
return res.Val.(Value), res.Err
|
||||||
|
case <-ctx.Done():
|
||||||
|
return Value{}, awserr.New("RequestCanceled",
|
||||||
|
"request context canceled", ctx.Err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Credentials) singleRetrieve(ctx Context) (creds interface{}, err error) {
|
||||||
|
if curCreds := c.creds.Load(); !c.isExpired(curCreds) {
|
||||||
|
return curCreds.(Value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if p, ok := c.provider.(ProviderWithContext); ok {
|
||||||
|
creds, err = p.RetrieveWithContext(ctx)
|
||||||
|
} else {
|
||||||
|
creds, err = c.provider.Retrieve()
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
c.creds.Store(creds)
|
||||||
|
}
|
||||||
|
|
||||||
|
return creds, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the credentials value, or error if the credentials Value failed
|
// Get returns the credentials value, or error if the credentials Value failed
|
||||||
|
@ -223,30 +279,7 @@ func NewCredentials(provider Provider) *Credentials {
|
||||||
// If Credentials.Expire() was called the credentials Value will be force
|
// If Credentials.Expire() was called the credentials Value will be force
|
||||||
// expired, and the next call to Get() will cause them to be refreshed.
|
// expired, and the next call to Get() will cause them to be refreshed.
|
||||||
func (c *Credentials) Get() (Value, error) {
|
func (c *Credentials) Get() (Value, error) {
|
||||||
// Check the cached credentials first with just the read lock.
|
return c.GetWithContext(backgroundContext())
|
||||||
c.m.RLock()
|
|
||||||
if !c.isExpired() {
|
|
||||||
creds := c.creds
|
|
||||||
c.m.RUnlock()
|
|
||||||
return creds, nil
|
|
||||||
}
|
|
||||||
c.m.RUnlock()
|
|
||||||
|
|
||||||
// Credentials are expired need to retrieve the credentials taking the full
|
|
||||||
// lock.
|
|
||||||
c.m.Lock()
|
|
||||||
defer c.m.Unlock()
|
|
||||||
|
|
||||||
if c.isExpired() {
|
|
||||||
creds, err := c.provider.Retrieve()
|
|
||||||
if err != nil {
|
|
||||||
return Value{}, err
|
|
||||||
}
|
|
||||||
c.creds = creds
|
|
||||||
c.forceRefresh = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.creds, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expire expires the credentials and forces them to be retrieved on the
|
// Expire expires the credentials and forces them to be retrieved on the
|
||||||
|
@ -255,10 +288,7 @@ func (c *Credentials) Get() (Value, error) {
|
||||||
// This will override the Provider's expired state, and force Credentials
|
// This will override the Provider's expired state, and force Credentials
|
||||||
// to call the Provider's Retrieve().
|
// to call the Provider's Retrieve().
|
||||||
func (c *Credentials) Expire() {
|
func (c *Credentials) Expire() {
|
||||||
c.m.Lock()
|
c.creds.Store(Value{})
|
||||||
defer c.m.Unlock()
|
|
||||||
|
|
||||||
c.forceRefresh = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsExpired returns if the credentials are no longer valid, and need
|
// IsExpired returns if the credentials are no longer valid, and need
|
||||||
|
@ -267,33 +297,43 @@ func (c *Credentials) Expire() {
|
||||||
// If the Credentials were forced to be expired with Expire() this will
|
// If the Credentials were forced to be expired with Expire() this will
|
||||||
// reflect that override.
|
// reflect that override.
|
||||||
func (c *Credentials) IsExpired() bool {
|
func (c *Credentials) IsExpired() bool {
|
||||||
c.m.RLock()
|
return c.isExpired(c.creds.Load())
|
||||||
defer c.m.RUnlock()
|
|
||||||
|
|
||||||
return c.isExpired()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// isExpired helper method wrapping the definition of expired credentials.
|
// isExpired helper method wrapping the definition of expired credentials.
|
||||||
func (c *Credentials) isExpired() bool {
|
func (c *Credentials) isExpired(creds interface{}) bool {
|
||||||
return c.forceRefresh || c.provider.IsExpired()
|
return creds == nil || creds.(Value) == Value{} || c.provider.IsExpired()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpiresAt provides access to the functionality of the Expirer interface of
|
// ExpiresAt provides access to the functionality of the Expirer interface of
|
||||||
// the underlying Provider, if it supports that interface. Otherwise, it returns
|
// the underlying Provider, if it supports that interface. Otherwise, it returns
|
||||||
// an error.
|
// an error.
|
||||||
func (c *Credentials) ExpiresAt() (time.Time, error) {
|
func (c *Credentials) ExpiresAt() (time.Time, error) {
|
||||||
c.m.RLock()
|
|
||||||
defer c.m.RUnlock()
|
|
||||||
|
|
||||||
expirer, ok := c.provider.(Expirer)
|
expirer, ok := c.provider.(Expirer)
|
||||||
if !ok {
|
if !ok {
|
||||||
return time.Time{}, awserr.New("ProviderNotExpirer",
|
return time.Time{}, awserr.New("ProviderNotExpirer",
|
||||||
fmt.Sprintf("provider %s does not support ExpiresAt()", c.creds.ProviderName),
|
fmt.Sprintf("provider %s does not support ExpiresAt()", c.creds.Load().(Value).ProviderName),
|
||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
if c.forceRefresh {
|
if c.creds.Load().(Value) == (Value{}) {
|
||||||
// set expiration time to the distant past
|
// set expiration time to the distant past
|
||||||
return time.Time{}, nil
|
return time.Time{}, nil
|
||||||
}
|
}
|
||||||
return expirer.ExpiresAt(), nil
|
return expirer.ExpiresAt(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type suppressedContext struct {
|
||||||
|
Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *suppressedContext) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return time.Time{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *suppressedContext) Done() <-chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *suppressedContext) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
20
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
20
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/aws/client"
|
"github.com/aws/aws-sdk-go/aws/client"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
@ -87,7 +88,14 @@ func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*
|
||||||
// Error will be returned if the request fails, or unable to extract
|
// Error will be returned if the request fails, or unable to extract
|
||||||
// the desired credentials.
|
// the desired credentials.
|
||||||
func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
credsList, err := requestCredList(m.Client)
|
return m.RetrieveWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveWithContext retrieves credentials from the EC2 service.
|
||||||
|
// Error will be returned if the request fails, or unable to extract
|
||||||
|
// the desired credentials.
|
||||||
|
func (m *EC2RoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
|
credsList, err := requestCredList(ctx, m.Client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return credentials.Value{ProviderName: ProviderName}, err
|
return credentials.Value{ProviderName: ProviderName}, err
|
||||||
}
|
}
|
||||||
|
@ -97,7 +105,7 @@ func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
}
|
}
|
||||||
credsName := credsList[0]
|
credsName := credsList[0]
|
||||||
|
|
||||||
roleCreds, err := requestCred(m.Client, credsName)
|
roleCreds, err := requestCred(ctx, m.Client, credsName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return credentials.Value{ProviderName: ProviderName}, err
|
return credentials.Value{ProviderName: ProviderName}, err
|
||||||
}
|
}
|
||||||
|
@ -130,8 +138,8 @@ const iamSecurityCredsPath = "iam/security-credentials/"
|
||||||
|
|
||||||
// requestCredList requests a list of credentials from the EC2 service.
|
// requestCredList requests a list of credentials from the EC2 service.
|
||||||
// If there are no credentials, or there is an error making or receiving the request
|
// If there are no credentials, or there is an error making or receiving the request
|
||||||
func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
|
func requestCredList(ctx aws.Context, client *ec2metadata.EC2Metadata) ([]string, error) {
|
||||||
resp, err := client.GetMetadata(iamSecurityCredsPath)
|
resp, err := client.GetMetadataWithContext(ctx, iamSecurityCredsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err)
|
return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err)
|
||||||
}
|
}
|
||||||
|
@ -154,8 +162,8 @@ func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
|
||||||
//
|
//
|
||||||
// If the credentials cannot be found, or there is an error reading the response
|
// If the credentials cannot be found, or there is an error reading the response
|
||||||
// and error will be returned.
|
// and error will be returned.
|
||||||
func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
|
func requestCred(ctx aws.Context, client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
|
||||||
resp, err := client.GetMetadata(sdkuri.PathJoin(iamSecurityCredsPath, credsName))
|
resp, err := client.GetMetadataWithContext(ctx, sdkuri.PathJoin(iamSecurityCredsPath, credsName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ec2RoleCredRespBody{},
|
return ec2RoleCredRespBody{},
|
||||||
awserr.New("EC2RoleRequestError",
|
awserr.New("EC2RoleRequestError",
|
||||||
|
|
|
@ -116,7 +116,13 @@ func (p *Provider) IsExpired() bool {
|
||||||
// Retrieve will attempt to request the credentials from the endpoint the Provider
|
// Retrieve will attempt to request the credentials from the endpoint the Provider
|
||||||
// was configured for. And error will be returned if the retrieval fails.
|
// was configured for. And error will be returned if the retrieval fails.
|
||||||
func (p *Provider) Retrieve() (credentials.Value, error) {
|
func (p *Provider) Retrieve() (credentials.Value, error) {
|
||||||
resp, err := p.getCredentials()
|
return p.RetrieveWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveWithContext will attempt to request the credentials from the endpoint the Provider
|
||||||
|
// was configured for. And error will be returned if the retrieval fails.
|
||||||
|
func (p *Provider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
|
resp, err := p.getCredentials(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return credentials.Value{ProviderName: ProviderName},
|
return credentials.Value{ProviderName: ProviderName},
|
||||||
awserr.New("CredentialsEndpointError", "failed to load credentials", err)
|
awserr.New("CredentialsEndpointError", "failed to load credentials", err)
|
||||||
|
@ -148,7 +154,7 @@ type errorOutput struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) getCredentials() (*getCredentialsOutput, error) {
|
func (p *Provider) getCredentials(ctx aws.Context) (*getCredentialsOutput, error) {
|
||||||
op := &request.Operation{
|
op := &request.Operation{
|
||||||
Name: "GetCredentials",
|
Name: "GetCredentials",
|
||||||
HTTPMethod: "GET",
|
HTTPMethod: "GET",
|
||||||
|
@ -156,6 +162,7 @@ func (p *Provider) getCredentials() (*getCredentialsOutput, error) {
|
||||||
|
|
||||||
out := &getCredentialsOutput{}
|
out := &getCredentialsOutput{}
|
||||||
req := p.Client.NewRequest(op, nil, out)
|
req := p.Client.NewRequest(op, nil, out)
|
||||||
|
req.SetContext(ctx)
|
||||||
req.HTTPRequest.Header.Set("Accept", "application/json")
|
req.HTTPRequest.Header.Set("Accept", "application/json")
|
||||||
if authToken := p.AuthorizationToken; len(authToken) != 0 {
|
if authToken := p.AuthorizationToken; len(authToken) != 0 {
|
||||||
req.HTTPRequest.Header.Set("Authorization", authToken)
|
req.HTTPRequest.Header.Set("Authorization", authToken)
|
||||||
|
|
|
@ -90,6 +90,7 @@ import (
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/internal/sdkio"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -142,7 +143,7 @@ const (
|
||||||
|
|
||||||
// DefaultBufSize limits buffer size from growing to an enormous
|
// DefaultBufSize limits buffer size from growing to an enormous
|
||||||
// amount due to a faulty process.
|
// amount due to a faulty process.
|
||||||
DefaultBufSize = 1024
|
DefaultBufSize = int(8 * sdkio.KibiByte)
|
||||||
|
|
||||||
// DefaultTimeout default limit on time a process can run.
|
// DefaultTimeout default limit on time a process can run.
|
||||||
DefaultTimeout = time.Duration(1) * time.Minute
|
DefaultTimeout = time.Duration(1) * time.Minute
|
||||||
|
|
5
vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
generated
vendored
5
vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
generated
vendored
|
@ -17,8 +17,9 @@ var (
|
||||||
ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil)
|
ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// A SharedCredentialsProvider retrieves credentials from the current user's home
|
// A SharedCredentialsProvider retrieves access key pair (access key ID,
|
||||||
// directory, and keeps track if those credentials are expired.
|
// secret access key, and session token if present) credentials from the current
|
||||||
|
// user's home directory, and keeps track if those credentials are expired.
|
||||||
//
|
//
|
||||||
// Profile ini file example: $HOME/.aws/credentials
|
// Profile ini file example: $HOME/.aws/credentials
|
||||||
type SharedCredentialsProvider struct {
|
type SharedCredentialsProvider struct {
|
||||||
|
|
|
@ -19,7 +19,9 @@ type StaticProvider struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStaticCredentials returns a pointer to a new Credentials object
|
// NewStaticCredentials returns a pointer to a new Credentials object
|
||||||
// wrapping a static credentials value provider.
|
// wrapping a static credentials value provider. Token is only required
|
||||||
|
// for temporary security credentials retrieved via STS, otherwise an empty
|
||||||
|
// string can be passed for this parameter.
|
||||||
func NewStaticCredentials(id, secret, token string) *Credentials {
|
func NewStaticCredentials(id, secret, token string) *Credentials {
|
||||||
return NewCredentials(&StaticProvider{Value: Value{
|
return NewCredentials(&StaticProvider{Value: Value{
|
||||||
AccessKeyID: id,
|
AccessKeyID: id,
|
||||||
|
|
53
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
53
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
|
@ -87,6 +87,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/aws/client"
|
"github.com/aws/aws-sdk-go/aws/client"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
"github.com/aws/aws-sdk-go/internal/sdkrand"
|
"github.com/aws/aws-sdk-go/internal/sdkrand"
|
||||||
"github.com/aws/aws-sdk-go/service/sts"
|
"github.com/aws/aws-sdk-go/service/sts"
|
||||||
)
|
)
|
||||||
|
@ -118,6 +119,10 @@ type AssumeRoler interface {
|
||||||
AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
|
AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type assumeRolerWithContext interface {
|
||||||
|
AssumeRoleWithContext(aws.Context, *sts.AssumeRoleInput, ...request.Option) (*sts.AssumeRoleOutput, error)
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultDuration is the default amount of time in minutes that the credentials
|
// DefaultDuration is the default amount of time in minutes that the credentials
|
||||||
// will be valid for.
|
// will be valid for.
|
||||||
var DefaultDuration = time.Duration(15) * time.Minute
|
var DefaultDuration = time.Duration(15) * time.Minute
|
||||||
|
@ -144,6 +149,13 @@ type AssumeRoleProvider struct {
|
||||||
// Session name, if you wish to reuse the credentials elsewhere.
|
// Session name, if you wish to reuse the credentials elsewhere.
|
||||||
RoleSessionName string
|
RoleSessionName string
|
||||||
|
|
||||||
|
// Optional, you can pass tag key-value pairs to your session. These tags are called session tags.
|
||||||
|
Tags []*sts.Tag
|
||||||
|
|
||||||
|
// A list of keys for session tags that you want to set as transitive.
|
||||||
|
// If you set a tag key as transitive, the corresponding key and value passes to subsequent sessions in a role chain.
|
||||||
|
TransitiveTagKeys []*string
|
||||||
|
|
||||||
// Expiry duration of the STS credentials. Defaults to 15 minutes if not set.
|
// Expiry duration of the STS credentials. Defaults to 15 minutes if not set.
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
|
|
||||||
|
@ -157,6 +169,29 @@ type AssumeRoleProvider struct {
|
||||||
// size.
|
// size.
|
||||||
Policy *string
|
Policy *string
|
||||||
|
|
||||||
|
// The ARNs of IAM managed policies you want to use as managed session policies.
|
||||||
|
// The policies must exist in the same account as the role.
|
||||||
|
//
|
||||||
|
// This parameter is optional. You can provide up to 10 managed policy ARNs.
|
||||||
|
// However, the plain text that you use for both inline and managed session
|
||||||
|
// policies can't exceed 2,048 characters.
|
||||||
|
//
|
||||||
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
|
// and tags for your request are to the upper size limit.
|
||||||
|
//
|
||||||
|
// Passing policies to this operation returns new temporary credentials. The
|
||||||
|
// resulting session's permissions are the intersection of the role's identity-based
|
||||||
|
// policy and the session policies. You can use the role's temporary credentials
|
||||||
|
// in subsequent AWS API calls to access resources in the account that owns
|
||||||
|
// the role. You cannot use session policies to grant more permissions than
|
||||||
|
// those allowed by the identity-based policy of the role that is being assumed.
|
||||||
|
// For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
PolicyArns []*sts.PolicyDescriptorType
|
||||||
|
|
||||||
// The identification number of the MFA device that is associated with the user
|
// The identification number of the MFA device that is associated with the user
|
||||||
// who is making the AssumeRole call. Specify this value if the trust policy
|
// who is making the AssumeRole call. Specify this value if the trust policy
|
||||||
// of the role being assumed includes a condition that requires MFA authentication.
|
// of the role being assumed includes a condition that requires MFA authentication.
|
||||||
|
@ -258,6 +293,11 @@ func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*
|
||||||
|
|
||||||
// Retrieve generates a new set of temporary credentials using STS.
|
// Retrieve generates a new set of temporary credentials using STS.
|
||||||
func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
|
return p.RetrieveWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveWithContext generates a new set of temporary credentials using STS.
|
||||||
|
func (p *AssumeRoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
// Apply defaults where parameters are not set.
|
// Apply defaults where parameters are not set.
|
||||||
if p.RoleSessionName == "" {
|
if p.RoleSessionName == "" {
|
||||||
// Try to work out a role name that will hopefully end up unique.
|
// Try to work out a role name that will hopefully end up unique.
|
||||||
|
@ -273,6 +313,9 @@ func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
RoleArn: aws.String(p.RoleARN),
|
RoleArn: aws.String(p.RoleARN),
|
||||||
RoleSessionName: aws.String(p.RoleSessionName),
|
RoleSessionName: aws.String(p.RoleSessionName),
|
||||||
ExternalId: p.ExternalID,
|
ExternalId: p.ExternalID,
|
||||||
|
Tags: p.Tags,
|
||||||
|
PolicyArns: p.PolicyArns,
|
||||||
|
TransitiveTagKeys: p.TransitiveTagKeys,
|
||||||
}
|
}
|
||||||
if p.Policy != nil {
|
if p.Policy != nil {
|
||||||
input.Policy = p.Policy
|
input.Policy = p.Policy
|
||||||
|
@ -295,7 +338,15 @@ func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
roleOutput, err := p.Client.AssumeRole(input)
|
var roleOutput *sts.AssumeRoleOutput
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if c, ok := p.Client.(assumeRolerWithContext); ok {
|
||||||
|
roleOutput, err = c.AssumeRoleWithContext(ctx, input)
|
||||||
|
} else {
|
||||||
|
roleOutput, err = p.Client.AssumeRole(input)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return credentials.Value{ProviderName: ProviderName}, err
|
return credentials.Value{ProviderName: ProviderName}, err
|
||||||
}
|
}
|
||||||
|
|
66
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/web_identity_provider.go
generated
vendored
66
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/web_identity_provider.go
generated
vendored
|
@ -28,15 +28,46 @@ const (
|
||||||
// compare test values.
|
// compare test values.
|
||||||
var now = time.Now
|
var now = time.Now
|
||||||
|
|
||||||
|
// TokenFetcher shuold return WebIdentity token bytes or an error
|
||||||
|
type TokenFetcher interface {
|
||||||
|
FetchToken(credentials.Context) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchTokenPath is a path to a WebIdentity token file
|
||||||
|
type FetchTokenPath string
|
||||||
|
|
||||||
|
// FetchToken returns a token by reading from the filesystem
|
||||||
|
func (f FetchTokenPath) FetchToken(ctx credentials.Context) ([]byte, error) {
|
||||||
|
data, err := ioutil.ReadFile(string(f))
|
||||||
|
if err != nil {
|
||||||
|
errMsg := fmt.Sprintf("unable to read file at %s", f)
|
||||||
|
return nil, awserr.New(ErrCodeWebIdentity, errMsg, err)
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
// WebIdentityRoleProvider is used to retrieve credentials using
|
// WebIdentityRoleProvider is used to retrieve credentials using
|
||||||
// an OIDC token.
|
// an OIDC token.
|
||||||
type WebIdentityRoleProvider struct {
|
type WebIdentityRoleProvider struct {
|
||||||
credentials.Expiry
|
credentials.Expiry
|
||||||
|
PolicyArns []*sts.PolicyDescriptorType
|
||||||
|
|
||||||
client stsiface.STSAPI
|
// Duration the STS credentials will be valid for. Truncated to seconds.
|
||||||
|
// If unset, the assumed role will use AssumeRoleWithWebIdentity's default
|
||||||
|
// expiry duration. See
|
||||||
|
// https://docs.aws.amazon.com/sdk-for-go/api/service/sts/#STS.AssumeRoleWithWebIdentity
|
||||||
|
// for more information.
|
||||||
|
Duration time.Duration
|
||||||
|
|
||||||
|
// The amount of time the credentials will be refreshed before they expire.
|
||||||
|
// This is useful refresh credentials before they expire to reduce risk of
|
||||||
|
// using credentials as they expire. If unset, will default to no expiry
|
||||||
|
// window.
|
||||||
ExpiryWindow time.Duration
|
ExpiryWindow time.Duration
|
||||||
|
|
||||||
tokenFilePath string
|
client stsiface.STSAPI
|
||||||
|
|
||||||
|
tokenFetcher TokenFetcher
|
||||||
roleARN string
|
roleARN string
|
||||||
roleSessionName string
|
roleSessionName string
|
||||||
}
|
}
|
||||||
|
@ -52,9 +83,15 @@ func NewWebIdentityCredentials(c client.ConfigProvider, roleARN, roleSessionName
|
||||||
// NewWebIdentityRoleProvider will return a new WebIdentityRoleProvider with the
|
// NewWebIdentityRoleProvider will return a new WebIdentityRoleProvider with the
|
||||||
// provided stsiface.STSAPI
|
// provided stsiface.STSAPI
|
||||||
func NewWebIdentityRoleProvider(svc stsiface.STSAPI, roleARN, roleSessionName, path string) *WebIdentityRoleProvider {
|
func NewWebIdentityRoleProvider(svc stsiface.STSAPI, roleARN, roleSessionName, path string) *WebIdentityRoleProvider {
|
||||||
|
return NewWebIdentityRoleProviderWithToken(svc, roleARN, roleSessionName, FetchTokenPath(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWebIdentityRoleProviderWithToken will return a new WebIdentityRoleProvider with the
|
||||||
|
// provided stsiface.STSAPI and a TokenFetcher
|
||||||
|
func NewWebIdentityRoleProviderWithToken(svc stsiface.STSAPI, roleARN, roleSessionName string, tokenFetcher TokenFetcher) *WebIdentityRoleProvider {
|
||||||
return &WebIdentityRoleProvider{
|
return &WebIdentityRoleProvider{
|
||||||
client: svc,
|
client: svc,
|
||||||
tokenFilePath: path,
|
tokenFetcher: tokenFetcher,
|
||||||
roleARN: roleARN,
|
roleARN: roleARN,
|
||||||
roleSessionName: roleSessionName,
|
roleSessionName: roleSessionName,
|
||||||
}
|
}
|
||||||
|
@ -64,10 +101,16 @@ func NewWebIdentityRoleProvider(svc stsiface.STSAPI, roleARN, roleSessionName, p
|
||||||
// 'WebIdentityTokenFilePath' specified destination and if that is empty an
|
// 'WebIdentityTokenFilePath' specified destination and if that is empty an
|
||||||
// error will be returned.
|
// error will be returned.
|
||||||
func (p *WebIdentityRoleProvider) Retrieve() (credentials.Value, error) {
|
func (p *WebIdentityRoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
b, err := ioutil.ReadFile(p.tokenFilePath)
|
return p.RetrieveWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetrieveWithContext will attempt to assume a role from a token which is located at
|
||||||
|
// 'WebIdentityTokenFilePath' specified destination and if that is empty an
|
||||||
|
// error will be returned.
|
||||||
|
func (p *WebIdentityRoleProvider) RetrieveWithContext(ctx credentials.Context) (credentials.Value, error) {
|
||||||
|
b, err := p.tokenFetcher.FetchToken(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errMsg := fmt.Sprintf("unable to read file at %s", p.tokenFilePath)
|
return credentials.Value{}, awserr.New(ErrCodeWebIdentity, "failed fetching WebIdentity token: ", err)
|
||||||
return credentials.Value{}, awserr.New(ErrCodeWebIdentity, errMsg, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionName := p.roleSessionName
|
sessionName := p.roleSessionName
|
||||||
|
@ -76,11 +119,22 @@ func (p *WebIdentityRoleProvider) Retrieve() (credentials.Value, error) {
|
||||||
// uses unix time in nanoseconds to uniquely identify sessions.
|
// uses unix time in nanoseconds to uniquely identify sessions.
|
||||||
sessionName = strconv.FormatInt(now().UnixNano(), 10)
|
sessionName = strconv.FormatInt(now().UnixNano(), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var duration *int64
|
||||||
|
if p.Duration != 0 {
|
||||||
|
duration = aws.Int64(int64(p.Duration / time.Second))
|
||||||
|
}
|
||||||
|
|
||||||
req, resp := p.client.AssumeRoleWithWebIdentityRequest(&sts.AssumeRoleWithWebIdentityInput{
|
req, resp := p.client.AssumeRoleWithWebIdentityRequest(&sts.AssumeRoleWithWebIdentityInput{
|
||||||
|
PolicyArns: p.PolicyArns,
|
||||||
RoleArn: &p.roleARN,
|
RoleArn: &p.roleARN,
|
||||||
RoleSessionName: &sessionName,
|
RoleSessionName: &sessionName,
|
||||||
WebIdentityToken: aws.String(string(b)),
|
WebIdentityToken: aws.String(string(b)),
|
||||||
|
DurationSeconds: duration,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
req.SetContext(ctx)
|
||||||
|
|
||||||
// InvalidIdentityToken error is a temporary error that can occur
|
// InvalidIdentityToken error is a temporary error that can occur
|
||||||
// when assuming an Role with a JWT web identity token.
|
// when assuming an Role with a JWT web identity token.
|
||||||
req.RetryErrorCodes = append(req.RetryErrorCodes, sts.ErrCodeInvalidIdentityTokenException)
|
req.RetryErrorCodes = append(req.RetryErrorCodes, sts.ErrCodeInvalidIdentityTokenException)
|
||||||
|
|
|
@ -66,7 +66,6 @@ func (rep *Reporter) sendAPICallAttemptMetric(r *request.Request) {
|
||||||
|
|
||||||
XAmzRequestID: aws.String(r.RequestID),
|
XAmzRequestID: aws.String(r.RequestID),
|
||||||
|
|
||||||
AttemptCount: aws.Int(r.RetryCount + 1),
|
|
||||||
AttemptLatency: aws.Int(int(now.Sub(r.AttemptTime).Nanoseconds() / int64(time.Millisecond))),
|
AttemptLatency: aws.Int(int(now.Sub(r.AttemptTime).Nanoseconds() / int64(time.Millisecond))),
|
||||||
AccessKey: aws.String(creds.AccessKeyID),
|
AccessKey: aws.String(creds.AccessKeyID),
|
||||||
}
|
}
|
||||||
|
@ -90,7 +89,7 @@ func getMetricException(err awserr.Error) metricException {
|
||||||
code := err.Code()
|
code := err.Code()
|
||||||
|
|
||||||
switch code {
|
switch code {
|
||||||
case "RequestError",
|
case request.ErrCodeRequestError,
|
||||||
request.ErrCodeSerialization,
|
request.ErrCodeSerialization,
|
||||||
request.CanceledErrorCode:
|
request.CanceledErrorCode:
|
||||||
return sdkException{
|
return sdkException{
|
||||||
|
|
|
@ -4,28 +4,73 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
"github.com/aws/aws-sdk-go/internal/sdkuri"
|
"github.com/aws/aws-sdk-go/internal/sdkuri"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// getToken uses the duration to return a token for EC2 metadata service,
|
||||||
|
// or an error if the request failed.
|
||||||
|
func (c *EC2Metadata) getToken(ctx aws.Context, duration time.Duration) (tokenOutput, error) {
|
||||||
|
op := &request.Operation{
|
||||||
|
Name: "GetToken",
|
||||||
|
HTTPMethod: "PUT",
|
||||||
|
HTTPPath: "/latest/api/token",
|
||||||
|
}
|
||||||
|
|
||||||
|
var output tokenOutput
|
||||||
|
req := c.NewRequest(op, nil, &output)
|
||||||
|
req.SetContext(ctx)
|
||||||
|
|
||||||
|
// remove the fetch token handler from the request handlers to avoid infinite recursion
|
||||||
|
req.Handlers.Sign.RemoveByName(fetchTokenHandlerName)
|
||||||
|
|
||||||
|
// Swap the unmarshalMetadataHandler with unmarshalTokenHandler on this request.
|
||||||
|
req.Handlers.Unmarshal.Swap(unmarshalMetadataHandlerName, unmarshalTokenHandler)
|
||||||
|
|
||||||
|
ttl := strconv.FormatInt(int64(duration/time.Second), 10)
|
||||||
|
req.HTTPRequest.Header.Set(ttlHeader, ttl)
|
||||||
|
|
||||||
|
err := req.Send()
|
||||||
|
|
||||||
|
// Errors with bad request status should be returned.
|
||||||
|
if err != nil {
|
||||||
|
err = awserr.NewRequestFailure(
|
||||||
|
awserr.New(req.HTTPResponse.Status, http.StatusText(req.HTTPResponse.StatusCode), err),
|
||||||
|
req.HTTPResponse.StatusCode, req.RequestID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return output, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetMetadata uses the path provided to request information from the EC2
|
// GetMetadata uses the path provided to request information from the EC2
|
||||||
// instance metdata service. The content will be returned as a string, or
|
// instance metadata service. The content will be returned as a string, or
|
||||||
// error if the request failed.
|
// error if the request failed.
|
||||||
func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
||||||
|
return c.GetMetadataWithContext(aws.BackgroundContext(), p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetadataWithContext uses the path provided to request information from the EC2
|
||||||
|
// instance metadata service. The content will be returned as a string, or
|
||||||
|
// error if the request failed.
|
||||||
|
func (c *EC2Metadata) GetMetadataWithContext(ctx aws.Context, p string) (string, error) {
|
||||||
op := &request.Operation{
|
op := &request.Operation{
|
||||||
Name: "GetMetadata",
|
Name: "GetMetadata",
|
||||||
HTTPMethod: "GET",
|
HTTPMethod: "GET",
|
||||||
HTTPPath: sdkuri.PathJoin("/meta-data", p),
|
HTTPPath: sdkuri.PathJoin("/latest/meta-data", p),
|
||||||
}
|
}
|
||||||
|
|
||||||
output := &metadataOutput{}
|
output := &metadataOutput{}
|
||||||
req := c.NewRequest(op, nil, output)
|
|
||||||
err := req.Send()
|
|
||||||
|
|
||||||
|
req := c.NewRequest(op, nil, output)
|
||||||
|
|
||||||
|
req.SetContext(ctx)
|
||||||
|
|
||||||
|
err := req.Send()
|
||||||
return output.Content, err
|
return output.Content, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,21 +78,24 @@ func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
||||||
// there is no user-data setup for the EC2 instance a "NotFoundError" error
|
// there is no user-data setup for the EC2 instance a "NotFoundError" error
|
||||||
// code will be returned.
|
// code will be returned.
|
||||||
func (c *EC2Metadata) GetUserData() (string, error) {
|
func (c *EC2Metadata) GetUserData() (string, error) {
|
||||||
|
return c.GetUserDataWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserDataWithContext returns the userdata that was configured for the service. If
|
||||||
|
// there is no user-data setup for the EC2 instance a "NotFoundError" error
|
||||||
|
// code will be returned.
|
||||||
|
func (c *EC2Metadata) GetUserDataWithContext(ctx aws.Context) (string, error) {
|
||||||
op := &request.Operation{
|
op := &request.Operation{
|
||||||
Name: "GetUserData",
|
Name: "GetUserData",
|
||||||
HTTPMethod: "GET",
|
HTTPMethod: "GET",
|
||||||
HTTPPath: "/user-data",
|
HTTPPath: "/latest/user-data",
|
||||||
}
|
}
|
||||||
|
|
||||||
output := &metadataOutput{}
|
output := &metadataOutput{}
|
||||||
req := c.NewRequest(op, nil, output)
|
req := c.NewRequest(op, nil, output)
|
||||||
req.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
|
req.SetContext(ctx)
|
||||||
if r.HTTPResponse.StatusCode == http.StatusNotFound {
|
|
||||||
r.Error = awserr.New("NotFoundError", "user-data not found", r.Error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
err := req.Send()
|
|
||||||
|
|
||||||
|
err := req.Send()
|
||||||
return output.Content, err
|
return output.Content, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,16 +103,24 @@ func (c *EC2Metadata) GetUserData() (string, error) {
|
||||||
// instance metadata service for dynamic data. The content will be returned
|
// instance metadata service for dynamic data. The content will be returned
|
||||||
// as a string, or error if the request failed.
|
// as a string, or error if the request failed.
|
||||||
func (c *EC2Metadata) GetDynamicData(p string) (string, error) {
|
func (c *EC2Metadata) GetDynamicData(p string) (string, error) {
|
||||||
|
return c.GetDynamicDataWithContext(aws.BackgroundContext(), p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDynamicDataWithContext uses the path provided to request information from the EC2
|
||||||
|
// instance metadata service for dynamic data. The content will be returned
|
||||||
|
// as a string, or error if the request failed.
|
||||||
|
func (c *EC2Metadata) GetDynamicDataWithContext(ctx aws.Context, p string) (string, error) {
|
||||||
op := &request.Operation{
|
op := &request.Operation{
|
||||||
Name: "GetDynamicData",
|
Name: "GetDynamicData",
|
||||||
HTTPMethod: "GET",
|
HTTPMethod: "GET",
|
||||||
HTTPPath: sdkuri.PathJoin("/dynamic", p),
|
HTTPPath: sdkuri.PathJoin("/latest/dynamic", p),
|
||||||
}
|
}
|
||||||
|
|
||||||
output := &metadataOutput{}
|
output := &metadataOutput{}
|
||||||
req := c.NewRequest(op, nil, output)
|
req := c.NewRequest(op, nil, output)
|
||||||
err := req.Send()
|
req.SetContext(ctx)
|
||||||
|
|
||||||
|
err := req.Send()
|
||||||
return output.Content, err
|
return output.Content, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +128,14 @@ func (c *EC2Metadata) GetDynamicData(p string) (string, error) {
|
||||||
// instance. Error is returned if the request fails or is unable to parse
|
// instance. Error is returned if the request fails or is unable to parse
|
||||||
// the response.
|
// the response.
|
||||||
func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) {
|
func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) {
|
||||||
resp, err := c.GetDynamicData("instance-identity/document")
|
return c.GetInstanceIdentityDocumentWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInstanceIdentityDocumentWithContext retrieves an identity document describing an
|
||||||
|
// instance. Error is returned if the request fails or is unable to parse
|
||||||
|
// the response.
|
||||||
|
func (c *EC2Metadata) GetInstanceIdentityDocumentWithContext(ctx aws.Context) (EC2InstanceIdentityDocument, error) {
|
||||||
|
resp, err := c.GetDynamicDataWithContext(ctx, "instance-identity/document")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return EC2InstanceIdentityDocument{},
|
return EC2InstanceIdentityDocument{},
|
||||||
awserr.New("EC2MetadataRequestError",
|
awserr.New("EC2MetadataRequestError",
|
||||||
|
@ -91,7 +154,12 @@ func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument
|
||||||
|
|
||||||
// IAMInfo retrieves IAM info from the metadata API
|
// IAMInfo retrieves IAM info from the metadata API
|
||||||
func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) {
|
func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) {
|
||||||
resp, err := c.GetMetadata("iam/info")
|
return c.IAMInfoWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// IAMInfoWithContext retrieves IAM info from the metadata API
|
||||||
|
func (c *EC2Metadata) IAMInfoWithContext(ctx aws.Context) (EC2IAMInfo, error) {
|
||||||
|
resp, err := c.GetMetadataWithContext(ctx, "iam/info")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return EC2IAMInfo{},
|
return EC2IAMInfo{},
|
||||||
awserr.New("EC2MetadataRequestError",
|
awserr.New("EC2MetadataRequestError",
|
||||||
|
@ -116,24 +184,36 @@ func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) {
|
||||||
|
|
||||||
// Region returns the region the instance is running in.
|
// Region returns the region the instance is running in.
|
||||||
func (c *EC2Metadata) Region() (string, error) {
|
func (c *EC2Metadata) Region() (string, error) {
|
||||||
resp, err := c.GetMetadata("placement/availability-zone")
|
return c.RegionWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegionWithContext returns the region the instance is running in.
|
||||||
|
func (c *EC2Metadata) RegionWithContext(ctx aws.Context) (string, error) {
|
||||||
|
ec2InstanceIdentityDocument, err := c.GetInstanceIdentityDocumentWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
// extract region from the ec2InstanceIdentityDocument
|
||||||
if len(resp) == 0 {
|
region := ec2InstanceIdentityDocument.Region
|
||||||
return "", awserr.New("EC2MetadataError", "invalid Region response", nil)
|
if len(region) == 0 {
|
||||||
|
return "", awserr.New("EC2MetadataError", "invalid region received for ec2metadata instance", nil)
|
||||||
}
|
}
|
||||||
|
// returns region
|
||||||
// returns region without the suffix. Eg: us-west-2a becomes us-west-2
|
return region, nil
|
||||||
return resp[:len(resp)-1], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Available returns if the application has access to the EC2 Metadata service.
|
// Available returns if the application has access to the EC2 Metadata service.
|
||||||
// Can be used to determine if application is running within an EC2 Instance and
|
// Can be used to determine if application is running within an EC2 Instance and
|
||||||
// the metadata service is available.
|
// the metadata service is available.
|
||||||
func (c *EC2Metadata) Available() bool {
|
func (c *EC2Metadata) Available() bool {
|
||||||
if _, err := c.GetMetadata("instance-id"); err != nil {
|
return c.AvailableWithContext(aws.BackgroundContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AvailableWithContext returns if the application has access to the EC2 Metadata service.
|
||||||
|
// Can be used to determine if application is running within an EC2 Instance and
|
||||||
|
// the metadata service is available.
|
||||||
|
func (c *EC2Metadata) AvailableWithContext(ctx aws.Context) bool {
|
||||||
|
if _, err := c.GetMetadataWithContext(ctx, "instance-id"); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
// variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to
|
// variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to
|
||||||
// true instructs the SDK to disable the EC2 Metadata client. The client cannot
|
// true instructs the SDK to disable the EC2 Metadata client. The client cannot
|
||||||
// be used while the environment variable is set to true, (case insensitive).
|
// be used while the environment variable is set to true, (case insensitive).
|
||||||
|
//
|
||||||
|
// The endpoint of the EC2 IMDS client can be configured via the environment
|
||||||
|
// variable, AWS_EC2_METADATA_SERVICE_ENDPOINT when creating the client with a
|
||||||
|
// Session. See aws/session#Options.EC2IMDSEndpoint for more details.
|
||||||
package ec2metadata
|
package ec2metadata
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -12,7 +16,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -24,9 +30,25 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
// ServiceName is the name of the service.
|
// ServiceName is the name of the service.
|
||||||
const ServiceName = "ec2metadata"
|
ServiceName = "ec2metadata"
|
||||||
const disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED"
|
disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED"
|
||||||
|
|
||||||
|
// Headers for Token and TTL
|
||||||
|
ttlHeader = "x-aws-ec2-metadata-token-ttl-seconds"
|
||||||
|
tokenHeader = "x-aws-ec2-metadata-token"
|
||||||
|
|
||||||
|
// Named Handler constants
|
||||||
|
fetchTokenHandlerName = "FetchTokenHandler"
|
||||||
|
unmarshalMetadataHandlerName = "unmarshalMetadataHandler"
|
||||||
|
unmarshalTokenHandlerName = "unmarshalTokenHandler"
|
||||||
|
enableTokenProviderHandlerName = "enableTokenProviderHandler"
|
||||||
|
|
||||||
|
// TTL constants
|
||||||
|
defaultTTL = 21600 * time.Second
|
||||||
|
ttlExpirationWindow = 30 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
// A EC2Metadata is an EC2 Metadata service Client.
|
// A EC2Metadata is an EC2 Metadata service Client.
|
||||||
type EC2Metadata struct {
|
type EC2Metadata struct {
|
||||||
|
@ -52,6 +74,9 @@ func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata {
|
||||||
// a client when not using a session. Generally using just New with a session
|
// a client when not using a session. Generally using just New with a session
|
||||||
// is preferred.
|
// is preferred.
|
||||||
//
|
//
|
||||||
|
// Will remove the URL path from the endpoint provided to ensure the EC2 IMDS
|
||||||
|
// client is able to communicate with the EC2 IMDS API.
|
||||||
|
//
|
||||||
// If an unmodified HTTP client is provided from the stdlib default, or no client
|
// If an unmodified HTTP client is provided from the stdlib default, or no client
|
||||||
// the EC2RoleProvider's EC2Metadata HTTP client's timeout will be shortened.
|
// the EC2RoleProvider's EC2Metadata HTTP client's timeout will be shortened.
|
||||||
// To disable this set Config.EC2MetadataDisableTimeoutOverride to false. Enabled by default.
|
// To disable this set Config.EC2MetadataDisableTimeoutOverride to false. Enabled by default.
|
||||||
|
@ -63,8 +88,19 @@ func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
|
||||||
// use a shorter timeout than default because the metadata
|
// use a shorter timeout than default because the metadata
|
||||||
// service is local if it is running, and to fail faster
|
// service is local if it is running, and to fail faster
|
||||||
// if not running on an ec2 instance.
|
// if not running on an ec2 instance.
|
||||||
Timeout: 5 * time.Second,
|
Timeout: 1 * time.Second,
|
||||||
}
|
}
|
||||||
|
// max number of retries on the client operation
|
||||||
|
cfg.MaxRetries = aws.Int(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if u, err := url.Parse(endpoint); err == nil {
|
||||||
|
// Remove path from the endpoint since it will be added by requests.
|
||||||
|
// This is an artifact of the SDK adding `/latest` to the endpoint for
|
||||||
|
// EC2 IMDS, but this is now moved to the operation definition.
|
||||||
|
u.Path = ""
|
||||||
|
u.RawPath = ""
|
||||||
|
endpoint = u.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
svc := &EC2Metadata{
|
svc := &EC2Metadata{
|
||||||
|
@ -80,13 +116,27 @@ func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
svc.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
// token provider instance
|
||||||
|
tp := newTokenProvider(svc, defaultTTL)
|
||||||
|
|
||||||
|
// NamedHandler for fetching token
|
||||||
|
svc.Handlers.Sign.PushBackNamed(request.NamedHandler{
|
||||||
|
Name: fetchTokenHandlerName,
|
||||||
|
Fn: tp.fetchTokenHandler,
|
||||||
|
})
|
||||||
|
// NamedHandler for enabling token provider
|
||||||
|
svc.Handlers.Complete.PushBackNamed(request.NamedHandler{
|
||||||
|
Name: enableTokenProviderHandlerName,
|
||||||
|
Fn: tp.enableTokenProviderHandler,
|
||||||
|
})
|
||||||
|
|
||||||
|
svc.Handlers.Unmarshal.PushBackNamed(unmarshalHandler)
|
||||||
svc.Handlers.UnmarshalError.PushBack(unmarshalError)
|
svc.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||||
svc.Handlers.Validate.Clear()
|
svc.Handlers.Validate.Clear()
|
||||||
svc.Handlers.Validate.PushBack(validateEndpointHandler)
|
svc.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||||
|
|
||||||
// Disable the EC2 Metadata service if the environment variable is set.
|
// Disable the EC2 Metadata service if the environment variable is set.
|
||||||
// This shortcirctes the service's functionality to always fail to send
|
// This short-circuits the service's functionality to always fail to send
|
||||||
// requests.
|
// requests.
|
||||||
if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" {
|
if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" {
|
||||||
svc.Handlers.Send.SwapNamed(request.NamedHandler{
|
svc.Handlers.Send.SwapNamed(request.NamedHandler{
|
||||||
|
@ -107,7 +157,6 @@ func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
|
||||||
for _, option := range opts {
|
for _, option := range opts {
|
||||||
option(svc.Client)
|
option(svc.Client)
|
||||||
}
|
}
|
||||||
|
|
||||||
return svc
|
return svc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,30 +168,74 @@ type metadataOutput struct {
|
||||||
Content string
|
Content string
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalHandler(r *request.Request) {
|
type tokenOutput struct {
|
||||||
|
Token string
|
||||||
|
TTL time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshal token handler is used to parse the response of a getToken operation
|
||||||
|
var unmarshalTokenHandler = request.NamedHandler{
|
||||||
|
Name: unmarshalTokenHandlerName,
|
||||||
|
Fn: func(r *request.Request) {
|
||||||
defer r.HTTPResponse.Body.Close()
|
defer r.HTTPResponse.Body.Close()
|
||||||
b := &bytes.Buffer{}
|
var b bytes.Buffer
|
||||||
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
|
if _, err := io.Copy(&b, r.HTTPResponse.Body); err != nil {
|
||||||
r.Error = awserr.New(request.ErrCodeSerialization, "unable to unmarshal EC2 metadata response", err)
|
r.Error = awserr.NewRequestFailure(awserr.New(request.ErrCodeSerialization,
|
||||||
|
"unable to unmarshal EC2 metadata response", err), r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v := r.HTTPResponse.Header.Get(ttlHeader)
|
||||||
|
data, ok := r.Data.(*tokenOutput)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Token = b.String()
|
||||||
|
// TTL is in seconds
|
||||||
|
i, err := strconv.ParseInt(v, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(awserr.New(request.ParamFormatErrCode,
|
||||||
|
"unable to parse EC2 token TTL response", err), r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := time.Duration(i) * time.Second
|
||||||
|
data.TTL = t
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var unmarshalHandler = request.NamedHandler{
|
||||||
|
Name: unmarshalMetadataHandlerName,
|
||||||
|
Fn: func(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
var b bytes.Buffer
|
||||||
|
if _, err := io.Copy(&b, r.HTTPResponse.Body); err != nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(awserr.New(request.ErrCodeSerialization,
|
||||||
|
"unable to unmarshal EC2 metadata response", err), r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if data, ok := r.Data.(*metadataOutput); ok {
|
if data, ok := r.Data.(*metadataOutput); ok {
|
||||||
data.Content = b.String()
|
data.Content = b.String()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalError(r *request.Request) {
|
func unmarshalError(r *request.Request) {
|
||||||
defer r.HTTPResponse.Body.Close()
|
defer r.HTTPResponse.Body.Close()
|
||||||
b := &bytes.Buffer{}
|
var b bytes.Buffer
|
||||||
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
|
|
||||||
r.Error = awserr.New(request.ErrCodeSerialization, "unable to unmarshal EC2 metadata error response", err)
|
if _, err := io.Copy(&b, r.HTTPResponse.Body); err != nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(
|
||||||
|
awserr.New(request.ErrCodeSerialization, "unable to unmarshal EC2 metadata error response", err),
|
||||||
|
r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response body format is not consistent between metadata endpoints.
|
// Response body format is not consistent between metadata endpoints.
|
||||||
// Grab the error message as a string and include that as the source error
|
// Grab the error message as a string and include that as the source error
|
||||||
r.Error = awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String()))
|
r.Error = awserr.NewRequestFailure(awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String())),
|
||||||
|
r.HTTPResponse.StatusCode, r.RequestID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateEndpointHandler(r *request.Request) {
|
func validateEndpointHandler(r *request.Request) {
|
||||||
|
|
92
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/token_provider.go
generated
vendored
Normal file
92
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/token_provider.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package ec2metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A tokenProvider struct provides access to EC2Metadata client
|
||||||
|
// and atomic instance of a token, along with configuredTTL for it.
|
||||||
|
// tokenProvider also provides an atomic flag to disable the
|
||||||
|
// fetch token operation.
|
||||||
|
// The disabled member will use 0 as false, and 1 as true.
|
||||||
|
type tokenProvider struct {
|
||||||
|
client *EC2Metadata
|
||||||
|
token atomic.Value
|
||||||
|
configuredTTL time.Duration
|
||||||
|
disabled uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// A ec2Token struct helps use of token in EC2 Metadata service ops
|
||||||
|
type ec2Token struct {
|
||||||
|
token string
|
||||||
|
credentials.Expiry
|
||||||
|
}
|
||||||
|
|
||||||
|
// newTokenProvider provides a pointer to a tokenProvider instance
|
||||||
|
func newTokenProvider(c *EC2Metadata, duration time.Duration) *tokenProvider {
|
||||||
|
return &tokenProvider{client: c, configuredTTL: duration}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchTokenHandler fetches token for EC2Metadata service client by default.
|
||||||
|
func (t *tokenProvider) fetchTokenHandler(r *request.Request) {
|
||||||
|
|
||||||
|
// short-circuits to insecure data flow if tokenProvider is disabled.
|
||||||
|
if v := atomic.LoadUint32(&t.disabled); v == 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ec2Token, ok := t.token.Load().(ec2Token); ok && !ec2Token.IsExpired() {
|
||||||
|
r.HTTPRequest.Header.Set(tokenHeader, ec2Token.token)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := t.client.getToken(r.Context(), t.configuredTTL)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
// change the disabled flag on token provider to true,
|
||||||
|
// when error is request timeout error.
|
||||||
|
if requestFailureError, ok := err.(awserr.RequestFailure); ok {
|
||||||
|
switch requestFailureError.StatusCode() {
|
||||||
|
case http.StatusForbidden, http.StatusNotFound, http.StatusMethodNotAllowed:
|
||||||
|
atomic.StoreUint32(&t.disabled, 1)
|
||||||
|
case http.StatusBadRequest:
|
||||||
|
r.Error = requestFailureError
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if request timed out while waiting for response
|
||||||
|
if e, ok := requestFailureError.OrigErr().(awserr.Error); ok {
|
||||||
|
if e.Code() == request.ErrCodeRequestError {
|
||||||
|
atomic.StoreUint32(&t.disabled, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newToken := ec2Token{
|
||||||
|
token: output.Token,
|
||||||
|
}
|
||||||
|
newToken.SetExpiration(time.Now().Add(output.TTL), ttlExpirationWindow)
|
||||||
|
t.token.Store(newToken)
|
||||||
|
|
||||||
|
// Inject token header to the request.
|
||||||
|
if ec2Token, ok := t.token.Load().(ec2Token); ok {
|
||||||
|
r.HTTPRequest.Header.Set(tokenHeader, ec2Token.token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// enableTokenProviderHandler enables the token provider
|
||||||
|
func (t *tokenProvider) enableTokenProviderHandler(r *request.Request) {
|
||||||
|
// If the error code status is 401, we enable the token provider
|
||||||
|
if e, ok := r.Error.(awserr.RequestFailure); ok && e != nil &&
|
||||||
|
e.StatusCode() == http.StatusUnauthorized {
|
||||||
|
atomic.StoreUint32(&t.disabled, 0)
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,6 +83,7 @@ func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resol
|
||||||
p := &ps[i]
|
p := &ps[i]
|
||||||
custAddEC2Metadata(p)
|
custAddEC2Metadata(p)
|
||||||
custAddS3DualStack(p)
|
custAddS3DualStack(p)
|
||||||
|
custRegionalS3(p)
|
||||||
custRmIotDataService(p)
|
custRmIotDataService(p)
|
||||||
custFixAppAutoscalingChina(p)
|
custFixAppAutoscalingChina(p)
|
||||||
custFixAppAutoscalingUsGov(p)
|
custFixAppAutoscalingUsGov(p)
|
||||||
|
@ -92,7 +93,7 @@ func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resol
|
||||||
}
|
}
|
||||||
|
|
||||||
func custAddS3DualStack(p *partition) {
|
func custAddS3DualStack(p *partition) {
|
||||||
if p.ID != "aws" {
|
if !(p.ID == "aws" || p.ID == "aws-cn" || p.ID == "aws-us-gov") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +101,33 @@ func custAddS3DualStack(p *partition) {
|
||||||
custAddDualstack(p, "s3-control")
|
custAddDualstack(p, "s3-control")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func custRegionalS3(p *partition) {
|
||||||
|
if p.ID != "aws" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
service, ok := p.Services["s3"]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If global endpoint already exists no customization needed.
|
||||||
|
if _, ok := service.Endpoints["aws-global"]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
service.PartitionEndpoint = "aws-global"
|
||||||
|
service.Endpoints["us-east-1"] = endpoint{}
|
||||||
|
service.Endpoints["aws-global"] = endpoint{
|
||||||
|
Hostname: "s3.amazonaws.com",
|
||||||
|
CredentialScope: credentialScope{
|
||||||
|
Region: "us-east-1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Services["s3"] = service
|
||||||
|
}
|
||||||
|
|
||||||
func custAddDualstack(p *partition, svcName string) {
|
func custAddDualstack(p *partition, svcName string) {
|
||||||
s, ok := p.Services[svcName]
|
s, ok := p.Services[svcName]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,6 +3,7 @@ package endpoints
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
)
|
)
|
||||||
|
@ -46,6 +47,108 @@ type Options struct {
|
||||||
//
|
//
|
||||||
// This option is ignored if StrictMatching is enabled.
|
// This option is ignored if StrictMatching is enabled.
|
||||||
ResolveUnknownService bool
|
ResolveUnknownService bool
|
||||||
|
|
||||||
|
// STS Regional Endpoint flag helps with resolving the STS endpoint
|
||||||
|
STSRegionalEndpoint STSRegionalEndpoint
|
||||||
|
|
||||||
|
// S3 Regional Endpoint flag helps with resolving the S3 endpoint
|
||||||
|
S3UsEast1RegionalEndpoint S3UsEast1RegionalEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// STSRegionalEndpoint is an enum for the states of the STS Regional Endpoint
|
||||||
|
// options.
|
||||||
|
type STSRegionalEndpoint int
|
||||||
|
|
||||||
|
func (e STSRegionalEndpoint) String() string {
|
||||||
|
switch e {
|
||||||
|
case LegacySTSEndpoint:
|
||||||
|
return "legacy"
|
||||||
|
case RegionalSTSEndpoint:
|
||||||
|
return "regional"
|
||||||
|
case UnsetSTSEndpoint:
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// UnsetSTSEndpoint represents that STS Regional Endpoint flag is not specified.
|
||||||
|
UnsetSTSEndpoint STSRegionalEndpoint = iota
|
||||||
|
|
||||||
|
// LegacySTSEndpoint represents when STS Regional Endpoint flag is specified
|
||||||
|
// to use legacy endpoints.
|
||||||
|
LegacySTSEndpoint
|
||||||
|
|
||||||
|
// RegionalSTSEndpoint represents when STS Regional Endpoint flag is specified
|
||||||
|
// to use regional endpoints.
|
||||||
|
RegionalSTSEndpoint
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetSTSRegionalEndpoint function returns the STSRegionalEndpointFlag based
|
||||||
|
// on the input string provided in env config or shared config by the user.
|
||||||
|
//
|
||||||
|
// `legacy`, `regional` are the only case-insensitive valid strings for
|
||||||
|
// resolving the STS regional Endpoint flag.
|
||||||
|
func GetSTSRegionalEndpoint(s string) (STSRegionalEndpoint, error) {
|
||||||
|
switch {
|
||||||
|
case strings.EqualFold(s, "legacy"):
|
||||||
|
return LegacySTSEndpoint, nil
|
||||||
|
case strings.EqualFold(s, "regional"):
|
||||||
|
return RegionalSTSEndpoint, nil
|
||||||
|
default:
|
||||||
|
return UnsetSTSEndpoint, fmt.Errorf("unable to resolve the value of STSRegionalEndpoint for %v", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// S3UsEast1RegionalEndpoint is an enum for the states of the S3 us-east-1
|
||||||
|
// Regional Endpoint options.
|
||||||
|
type S3UsEast1RegionalEndpoint int
|
||||||
|
|
||||||
|
func (e S3UsEast1RegionalEndpoint) String() string {
|
||||||
|
switch e {
|
||||||
|
case LegacyS3UsEast1Endpoint:
|
||||||
|
return "legacy"
|
||||||
|
case RegionalS3UsEast1Endpoint:
|
||||||
|
return "regional"
|
||||||
|
case UnsetS3UsEast1Endpoint:
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// UnsetS3UsEast1Endpoint represents that S3 Regional Endpoint flag is not
|
||||||
|
// specified.
|
||||||
|
UnsetS3UsEast1Endpoint S3UsEast1RegionalEndpoint = iota
|
||||||
|
|
||||||
|
// LegacyS3UsEast1Endpoint represents when S3 Regional Endpoint flag is
|
||||||
|
// specified to use legacy endpoints.
|
||||||
|
LegacyS3UsEast1Endpoint
|
||||||
|
|
||||||
|
// RegionalS3UsEast1Endpoint represents when S3 Regional Endpoint flag is
|
||||||
|
// specified to use regional endpoints.
|
||||||
|
RegionalS3UsEast1Endpoint
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetS3UsEast1RegionalEndpoint function returns the S3UsEast1RegionalEndpointFlag based
|
||||||
|
// on the input string provided in env config or shared config by the user.
|
||||||
|
//
|
||||||
|
// `legacy`, `regional` are the only case-insensitive valid strings for
|
||||||
|
// resolving the S3 regional Endpoint flag.
|
||||||
|
func GetS3UsEast1RegionalEndpoint(s string) (S3UsEast1RegionalEndpoint, error) {
|
||||||
|
switch {
|
||||||
|
case strings.EqualFold(s, "legacy"):
|
||||||
|
return LegacyS3UsEast1Endpoint, nil
|
||||||
|
case strings.EqualFold(s, "regional"):
|
||||||
|
return RegionalS3UsEast1Endpoint, nil
|
||||||
|
default:
|
||||||
|
return UnsetS3UsEast1Endpoint,
|
||||||
|
fmt.Errorf("unable to resolve the value of S3UsEast1RegionalEndpoint for %v", s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set combines all of the option functions together.
|
// Set combines all of the option functions together.
|
||||||
|
@ -79,6 +182,12 @@ func ResolveUnknownServiceOption(o *Options) {
|
||||||
o.ResolveUnknownService = true
|
o.ResolveUnknownService = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STSRegionalEndpointOption enables the STS endpoint resolver behavior to resolve
|
||||||
|
// STS endpoint to their regional endpoint, instead of the global endpoint.
|
||||||
|
func STSRegionalEndpointOption(o *Options) {
|
||||||
|
o.STSRegionalEndpoint = RegionalSTSEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
// A Resolver provides the interface for functionality to resolve endpoints.
|
// A Resolver provides the interface for functionality to resolve endpoints.
|
||||||
// The build in Partition and DefaultResolver return value satisfy this interface.
|
// The build in Partition and DefaultResolver return value satisfy this interface.
|
||||||
type Resolver interface {
|
type Resolver interface {
|
||||||
|
@ -194,7 +303,7 @@ func (p Partition) ID() string { return p.id }
|
||||||
// require the provided service and region to be known by the partition.
|
// require the provided service and region to be known by the partition.
|
||||||
// If the endpoint cannot be strictly resolved an error will be returned. This
|
// If the endpoint cannot be strictly resolved an error will be returned. This
|
||||||
// mode is useful to ensure the endpoint resolved is valid. Without
|
// mode is useful to ensure the endpoint resolved is valid. Without
|
||||||
// StrictMatching enabled the endpoint returned my look valid but may not work.
|
// StrictMatching enabled the endpoint returned may look valid but may not work.
|
||||||
// StrictMatching requires the SDK to be updated if you want to take advantage
|
// StrictMatching requires the SDK to be updated if you want to take advantage
|
||||||
// of new regions and services expansions.
|
// of new regions and services expansions.
|
||||||
//
|
//
|
||||||
|
@ -208,7 +317,7 @@ func (p Partition) EndpointFor(service, region string, opts ...func(*Options)) (
|
||||||
// Regions returns a map of Regions indexed by their ID. This is useful for
|
// Regions returns a map of Regions indexed by their ID. This is useful for
|
||||||
// enumerating over the regions in a partition.
|
// enumerating over the regions in a partition.
|
||||||
func (p Partition) Regions() map[string]Region {
|
func (p Partition) Regions() map[string]Region {
|
||||||
rs := map[string]Region{}
|
rs := make(map[string]Region, len(p.p.Regions))
|
||||||
for id, r := range p.p.Regions {
|
for id, r := range p.p.Regions {
|
||||||
rs[id] = Region{
|
rs[id] = Region{
|
||||||
id: id,
|
id: id,
|
||||||
|
@ -223,7 +332,7 @@ func (p Partition) Regions() map[string]Region {
|
||||||
// Services returns a map of Service indexed by their ID. This is useful for
|
// Services returns a map of Service indexed by their ID. This is useful for
|
||||||
// enumerating over the services in a partition.
|
// enumerating over the services in a partition.
|
||||||
func (p Partition) Services() map[string]Service {
|
func (p Partition) Services() map[string]Service {
|
||||||
ss := map[string]Service{}
|
ss := make(map[string]Service, len(p.p.Services))
|
||||||
for id := range p.p.Services {
|
for id := range p.p.Services {
|
||||||
ss[id] = Service{
|
ss[id] = Service{
|
||||||
id: id,
|
id: id,
|
||||||
|
@ -310,7 +419,7 @@ func (s Service) Regions() map[string]Region {
|
||||||
// A region is the AWS region the service exists in. Whereas a Endpoint is
|
// A region is the AWS region the service exists in. Whereas a Endpoint is
|
||||||
// an URL that can be resolved to a instance of a service.
|
// an URL that can be resolved to a instance of a service.
|
||||||
func (s Service) Endpoints() map[string]Endpoint {
|
func (s Service) Endpoints() map[string]Endpoint {
|
||||||
es := map[string]Endpoint{}
|
es := make(map[string]Endpoint, len(s.p.Services[s.id].Endpoints))
|
||||||
for id := range s.p.Services[s.id].Endpoints {
|
for id := range s.p.Services[s.id].Endpoints {
|
||||||
es[id] = Endpoint{
|
es[id] = Endpoint{
|
||||||
id: id,
|
id: id,
|
||||||
|
@ -350,6 +459,9 @@ type ResolvedEndpoint struct {
|
||||||
// The endpoint URL
|
// The endpoint URL
|
||||||
URL string
|
URL string
|
||||||
|
|
||||||
|
// The endpoint partition
|
||||||
|
PartitionID string
|
||||||
|
|
||||||
// The region that should be used for signing requests.
|
// The region that should be used for signing requests.
|
||||||
SigningRegion string
|
SigningRegion string
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package endpoints
|
||||||
|
|
||||||
|
var legacyGlobalRegions = map[string]map[string]struct{}{
|
||||||
|
"sts": {
|
||||||
|
"ap-northeast-1": {},
|
||||||
|
"ap-south-1": {},
|
||||||
|
"ap-southeast-1": {},
|
||||||
|
"ap-southeast-2": {},
|
||||||
|
"ca-central-1": {},
|
||||||
|
"eu-central-1": {},
|
||||||
|
"eu-north-1": {},
|
||||||
|
"eu-west-1": {},
|
||||||
|
"eu-west-2": {},
|
||||||
|
"eu-west-3": {},
|
||||||
|
"sa-east-1": {},
|
||||||
|
"us-east-1": {},
|
||||||
|
"us-east-2": {},
|
||||||
|
"us-west-1": {},
|
||||||
|
"us-west-2": {},
|
||||||
|
},
|
||||||
|
"s3": {
|
||||||
|
"us-east-1": {},
|
||||||
|
},
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var regionValidationRegex = regexp.MustCompile(`^[[:alnum:]]([[:alnum:]\-]*[[:alnum:]])?$`)
|
||||||
|
|
||||||
type partitions []partition
|
type partitions []partition
|
||||||
|
|
||||||
func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||||
|
@ -75,24 +77,56 @@ func (p partition) canResolveEndpoint(service, region string, strictMatch bool)
|
||||||
return p.RegionRegex.MatchString(region)
|
return p.RegionRegex.MatchString(region)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allowLegacyEmptyRegion(service string) bool {
|
||||||
|
legacy := map[string]struct{}{
|
||||||
|
"budgets": {},
|
||||||
|
"ce": {},
|
||||||
|
"chime": {},
|
||||||
|
"cloudfront": {},
|
||||||
|
"ec2metadata": {},
|
||||||
|
"iam": {},
|
||||||
|
"importexport": {},
|
||||||
|
"organizations": {},
|
||||||
|
"route53": {},
|
||||||
|
"sts": {},
|
||||||
|
"support": {},
|
||||||
|
"waf": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, allowed := legacy[service]
|
||||||
|
return allowed
|
||||||
|
}
|
||||||
|
|
||||||
func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) {
|
func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) {
|
||||||
var opt Options
|
var opt Options
|
||||||
opt.Set(opts...)
|
opt.Set(opts...)
|
||||||
|
|
||||||
s, hasService := p.Services[service]
|
s, hasService := p.Services[service]
|
||||||
if !(hasService || opt.ResolveUnknownService) {
|
if len(service) == 0 || !(hasService || opt.ResolveUnknownService) {
|
||||||
// Only return error if the resolver will not fallback to creating
|
// Only return error if the resolver will not fallback to creating
|
||||||
// endpoint based on service endpoint ID passed in.
|
// endpoint based on service endpoint ID passed in.
|
||||||
return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services))
|
return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(region) == 0 && allowLegacyEmptyRegion(service) && len(s.PartitionEndpoint) != 0 {
|
||||||
|
region = s.PartitionEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service == "sts" && opt.STSRegionalEndpoint != RegionalSTSEndpoint) ||
|
||||||
|
(service == "s3" && opt.S3UsEast1RegionalEndpoint != RegionalS3UsEast1Endpoint) {
|
||||||
|
if _, ok := legacyGlobalRegions[service][region]; ok {
|
||||||
|
region = "aws-global"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
e, hasEndpoint := s.endpointForRegion(region)
|
e, hasEndpoint := s.endpointForRegion(region)
|
||||||
if !hasEndpoint && opt.StrictMatching {
|
if len(region) == 0 || (!hasEndpoint && opt.StrictMatching) {
|
||||||
return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints))
|
return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints))
|
||||||
}
|
}
|
||||||
|
|
||||||
defs := []endpoint{p.Defaults, s.Defaults}
|
defs := []endpoint{p.Defaults, s.Defaults}
|
||||||
return e.resolve(service, region, p.DNSSuffix, defs, opt), nil
|
|
||||||
|
return e.resolve(service, p.ID, region, p.DNSSuffix, defs, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func serviceList(ss services) []string {
|
func serviceList(ss services) []string {
|
||||||
|
@ -201,7 +235,7 @@ func getByPriority(s []string, p []string, def string) string {
|
||||||
return s[0]
|
return s[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint {
|
func (e endpoint) resolve(service, partitionID, region, dnsSuffix string, defs []endpoint, opts Options) (ResolvedEndpoint, error) {
|
||||||
var merged endpoint
|
var merged endpoint
|
||||||
for _, def := range defs {
|
for _, def := range defs {
|
||||||
merged.mergeIn(def)
|
merged.mergeIn(def)
|
||||||
|
@ -209,20 +243,6 @@ func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, op
|
||||||
merged.mergeIn(e)
|
merged.mergeIn(e)
|
||||||
e = merged
|
e = merged
|
||||||
|
|
||||||
hostname := e.Hostname
|
|
||||||
|
|
||||||
// Offset the hostname for dualstack if enabled
|
|
||||||
if opts.UseDualStack && e.HasDualStack == boxedTrue {
|
|
||||||
hostname = e.DualStackHostname
|
|
||||||
}
|
|
||||||
|
|
||||||
u := strings.Replace(hostname, "{service}", service, 1)
|
|
||||||
u = strings.Replace(u, "{region}", region, 1)
|
|
||||||
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
|
|
||||||
|
|
||||||
scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
|
|
||||||
u = fmt.Sprintf("%s://%s", scheme, u)
|
|
||||||
|
|
||||||
signingRegion := e.CredentialScope.Region
|
signingRegion := e.CredentialScope.Region
|
||||||
if len(signingRegion) == 0 {
|
if len(signingRegion) == 0 {
|
||||||
signingRegion = region
|
signingRegion = region
|
||||||
|
@ -235,13 +255,32 @@ func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, op
|
||||||
signingNameDerived = true
|
signingNameDerived = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostname := e.Hostname
|
||||||
|
// Offset the hostname for dualstack if enabled
|
||||||
|
if opts.UseDualStack && e.HasDualStack == boxedTrue {
|
||||||
|
hostname = e.DualStackHostname
|
||||||
|
region = signingRegion
|
||||||
|
}
|
||||||
|
|
||||||
|
if !validateInputRegion(region) {
|
||||||
|
return ResolvedEndpoint{}, fmt.Errorf("invalid region identifier format provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
u := strings.Replace(hostname, "{service}", service, 1)
|
||||||
|
u = strings.Replace(u, "{region}", region, 1)
|
||||||
|
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
|
||||||
|
|
||||||
|
scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
|
||||||
|
u = fmt.Sprintf("%s://%s", scheme, u)
|
||||||
|
|
||||||
return ResolvedEndpoint{
|
return ResolvedEndpoint{
|
||||||
URL: u,
|
URL: u,
|
||||||
|
PartitionID: partitionID,
|
||||||
SigningRegion: signingRegion,
|
SigningRegion: signingRegion,
|
||||||
SigningName: signingName,
|
SigningName: signingName,
|
||||||
SigningNameDerived: signingNameDerived,
|
SigningNameDerived: signingNameDerived,
|
||||||
SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
|
SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEndpointScheme(protocols []string, disableSSL bool) string {
|
func getEndpointScheme(protocols []string, disableSSL bool) string {
|
||||||
|
@ -306,3 +345,7 @@ const (
|
||||||
boxedFalse
|
boxedFalse
|
||||||
boxedTrue
|
boxedTrue
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func validateInputRegion(region string) bool {
|
||||||
|
return regionValidationRegex.MatchString(region)
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ func isErrConnectionReset(err error) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(err.Error(), "connection reset") ||
|
if strings.Contains(err.Error(), "use of closed network connection") ||
|
||||||
|
strings.Contains(err.Error(), "connection reset") ||
|
||||||
strings.Contains(err.Error(), "broken pipe") {
|
strings.Contains(err.Error(), "broken pipe") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
type Handlers struct {
|
type Handlers struct {
|
||||||
Validate HandlerList
|
Validate HandlerList
|
||||||
Build HandlerList
|
Build HandlerList
|
||||||
|
BuildStream HandlerList
|
||||||
Sign HandlerList
|
Sign HandlerList
|
||||||
Send HandlerList
|
Send HandlerList
|
||||||
ValidateResponse HandlerList
|
ValidateResponse HandlerList
|
||||||
|
@ -28,6 +29,7 @@ func (h *Handlers) Copy() Handlers {
|
||||||
return Handlers{
|
return Handlers{
|
||||||
Validate: h.Validate.copy(),
|
Validate: h.Validate.copy(),
|
||||||
Build: h.Build.copy(),
|
Build: h.Build.copy(),
|
||||||
|
BuildStream: h.BuildStream.copy(),
|
||||||
Sign: h.Sign.copy(),
|
Sign: h.Sign.copy(),
|
||||||
Send: h.Send.copy(),
|
Send: h.Send.copy(),
|
||||||
ValidateResponse: h.ValidateResponse.copy(),
|
ValidateResponse: h.ValidateResponse.copy(),
|
||||||
|
@ -46,6 +48,7 @@ func (h *Handlers) Copy() Handlers {
|
||||||
func (h *Handlers) Clear() {
|
func (h *Handlers) Clear() {
|
||||||
h.Validate.Clear()
|
h.Validate.Clear()
|
||||||
h.Build.Clear()
|
h.Build.Clear()
|
||||||
|
h.BuildStream.Clear()
|
||||||
h.Send.Clear()
|
h.Send.Clear()
|
||||||
h.Sign.Clear()
|
h.Sign.Clear()
|
||||||
h.Unmarshal.Clear()
|
h.Unmarshal.Clear()
|
||||||
|
@ -67,6 +70,9 @@ func (h *Handlers) IsEmpty() bool {
|
||||||
if h.Build.Len() != 0 {
|
if h.Build.Len() != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if h.BuildStream.Len() != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if h.Send.Len() != 0 {
|
if h.Send.Len() != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -320,3 +326,18 @@ func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
|
||||||
AddToUserAgent(r, s)
|
AddToUserAgent(r, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithSetRequestHeaders updates the operation request's HTTP header to contain
|
||||||
|
// the header key value pairs provided. If the header key already exists in the
|
||||||
|
// request's HTTP header set, the existing value(s) will be replaced.
|
||||||
|
func WithSetRequestHeaders(h map[string]string) Option {
|
||||||
|
return withRequestHeader(h).SetRequestHeaders
|
||||||
|
}
|
||||||
|
|
||||||
|
type withRequestHeader map[string]string
|
||||||
|
|
||||||
|
func (h withRequestHeader) SetRequestHeaders(r *Request) {
|
||||||
|
for k, v := range h {
|
||||||
|
r.HTTPRequest.Header[k] = []string{v}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,10 @@ const (
|
||||||
// API request that was canceled. Requests given a aws.Context may
|
// API request that was canceled. Requests given a aws.Context may
|
||||||
// return this error when canceled.
|
// return this error when canceled.
|
||||||
CanceledErrorCode = "RequestCanceled"
|
CanceledErrorCode = "RequestCanceled"
|
||||||
|
|
||||||
|
// ErrCodeRequestError is an error preventing the SDK from continuing to
|
||||||
|
// process the request.
|
||||||
|
ErrCodeRequestError = "RequestError"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Request is the service request to be made.
|
// A Request is the service request to be made.
|
||||||
|
@ -51,6 +55,7 @@ type Request struct {
|
||||||
HTTPRequest *http.Request
|
HTTPRequest *http.Request
|
||||||
HTTPResponse *http.Response
|
HTTPResponse *http.Response
|
||||||
Body io.ReadSeeker
|
Body io.ReadSeeker
|
||||||
|
streamingBody io.ReadCloser
|
||||||
BodyStart int64 // offset from beginning of Body that the request body starts
|
BodyStart int64 // offset from beginning of Body that the request body starts
|
||||||
Params interface{}
|
Params interface{}
|
||||||
Error error
|
Error error
|
||||||
|
@ -99,8 +104,12 @@ type Operation struct {
|
||||||
BeforePresignFn func(r *Request) error
|
BeforePresignFn func(r *Request) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new Request pointer for the service API
|
// New returns a new Request pointer for the service API operation and
|
||||||
// operation and parameters.
|
// parameters.
|
||||||
|
//
|
||||||
|
// A Retryer should be provided to direct how the request is retried. If
|
||||||
|
// Retryer is nil, a default no retry value will be used. You can use
|
||||||
|
// NoOpRetryer in the Client package to disable retry behavior directly.
|
||||||
//
|
//
|
||||||
// Params is any value of input parameters to be the request payload.
|
// Params is any value of input parameters to be the request payload.
|
||||||
// Data is pointer value to an object which the request's response
|
// Data is pointer value to an object which the request's response
|
||||||
|
@ -108,6 +117,10 @@ type Operation struct {
|
||||||
func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
|
func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
|
||||||
retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
|
retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
|
||||||
|
|
||||||
|
if retryer == nil {
|
||||||
|
retryer = noOpRetryer{}
|
||||||
|
}
|
||||||
|
|
||||||
method := operation.HTTPMethod
|
method := operation.HTTPMethod
|
||||||
if method == "" {
|
if method == "" {
|
||||||
method = "POST"
|
method = "POST"
|
||||||
|
@ -122,8 +135,6 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
|
||||||
err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
|
err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
SanitizeHostForHeader(httpReq)
|
|
||||||
|
|
||||||
r := &Request{
|
r := &Request{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
ClientInfo: clientInfo,
|
ClientInfo: clientInfo,
|
||||||
|
@ -287,6 +298,13 @@ func (r *Request) SetReaderBody(reader io.ReadSeeker) {
|
||||||
r.ResetBody()
|
r.ResetBody()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetStreamingBody set the reader to be used for the request that will stream
|
||||||
|
// bytes to the server. Request's Body must not be set to any reader.
|
||||||
|
func (r *Request) SetStreamingBody(reader io.ReadCloser) {
|
||||||
|
r.streamingBody = reader
|
||||||
|
r.SetReaderBody(aws.ReadSeekCloser(reader))
|
||||||
|
}
|
||||||
|
|
||||||
// Presign returns the request's signed URL. Error will be returned
|
// Presign returns the request's signed URL. Error will be returned
|
||||||
// if the signing fails. The expire parameter is only used for presigned Amazon
|
// if the signing fails. The expire parameter is only used for presigned Amazon
|
||||||
// S3 API requests. All other AWS services will use a fixed expiration
|
// S3 API requests. All other AWS services will use a fixed expiration
|
||||||
|
@ -406,11 +424,17 @@ func (r *Request) Sign() error {
|
||||||
return r.Error
|
return r.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SanitizeHostForHeader(r.HTTPRequest)
|
||||||
|
|
||||||
r.Handlers.Sign.Run(r)
|
r.Handlers.Sign.Run(r)
|
||||||
return r.Error
|
return r.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Request) getNextRequestBody() (body io.ReadCloser, err error) {
|
func (r *Request) getNextRequestBody() (body io.ReadCloser, err error) {
|
||||||
|
if r.streamingBody != nil {
|
||||||
|
return r.streamingBody, nil
|
||||||
|
}
|
||||||
|
|
||||||
if r.safeBody != nil {
|
if r.safeBody != nil {
|
||||||
r.safeBody.Close()
|
r.safeBody.Close()
|
||||||
}
|
}
|
||||||
|
@ -615,6 +639,10 @@ func getHost(r *http.Request) string {
|
||||||
return r.Host
|
return r.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.URL == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
return r.URL.Host
|
return r.URL.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,13 @@ import (
|
||||||
// does the pagination between API operations, and Paginator defines the
|
// does the pagination between API operations, and Paginator defines the
|
||||||
// configuration that will be used per page request.
|
// configuration that will be used per page request.
|
||||||
//
|
//
|
||||||
// cont := true
|
// for p.Next() {
|
||||||
// for p.Next() && cont {
|
|
||||||
// data := p.Page().(*s3.ListObjectsOutput)
|
// data := p.Page().(*s3.ListObjectsOutput)
|
||||||
// // process the page's data
|
// // process the page's data
|
||||||
|
// // ...
|
||||||
|
// // break out of loop to stop fetching additional pages
|
||||||
// }
|
// }
|
||||||
|
//
|
||||||
// return p.Err()
|
// return p.Err()
|
||||||
//
|
//
|
||||||
// See service client API operation Pages methods for examples how the SDK will
|
// See service client API operation Pages methods for examples how the SDK will
|
||||||
|
|
|
@ -35,16 +35,47 @@ type Retryer interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithRetryer sets a Retryer value to the given Config returning the Config
|
// WithRetryer sets a Retryer value to the given Config returning the Config
|
||||||
// value for chaining.
|
// value for chaining. The value must not be nil.
|
||||||
func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
|
func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
|
||||||
|
if retryer == nil {
|
||||||
|
if cfg.Logger != nil {
|
||||||
|
cfg.Logger.Log("ERROR: Request.WithRetryer called with nil retryer. Replacing with retry disabled Retryer.")
|
||||||
|
}
|
||||||
|
retryer = noOpRetryer{}
|
||||||
|
}
|
||||||
cfg.Retryer = retryer
|
cfg.Retryer = retryer
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// noOpRetryer is a internal no op retryer used when a request is created
|
||||||
|
// without a retryer.
|
||||||
|
//
|
||||||
|
// Provides a retryer that performs no retries.
|
||||||
|
// It should be used when we do not want retries to be performed.
|
||||||
|
type noOpRetryer struct{}
|
||||||
|
|
||||||
|
// MaxRetries returns the number of maximum returns the service will use to make
|
||||||
|
// an individual API; For NoOpRetryer the MaxRetries will always be zero.
|
||||||
|
func (d noOpRetryer) MaxRetries() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldRetry will always return false for NoOpRetryer, as it should never retry.
|
||||||
|
func (d noOpRetryer) ShouldRetry(_ *Request) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetryRules returns the delay duration before retrying this request again;
|
||||||
|
// since NoOpRetryer does not retry, RetryRules always returns 0.
|
||||||
|
func (d noOpRetryer) RetryRules(_ *Request) time.Duration {
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// retryableCodes is a collection of service response codes which are retry-able
|
// retryableCodes is a collection of service response codes which are retry-able
|
||||||
// without any further action.
|
// without any further action.
|
||||||
var retryableCodes = map[string]struct{}{
|
var retryableCodes = map[string]struct{}{
|
||||||
"RequestError": {},
|
ErrCodeRequestError: {},
|
||||||
"RequestTimeout": {},
|
"RequestTimeout": {},
|
||||||
ErrCodeResponseTimeout: {},
|
ErrCodeResponseTimeout: {},
|
||||||
"RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
|
"RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
|
||||||
|
@ -52,6 +83,7 @@ var retryableCodes = map[string]struct{}{
|
||||||
|
|
||||||
var throttleCodes = map[string]struct{}{
|
var throttleCodes = map[string]struct{}{
|
||||||
"ProvisionedThroughputExceededException": {},
|
"ProvisionedThroughputExceededException": {},
|
||||||
|
"ThrottledException": {}, // SNS, XRay, ResourceGroupsTagging API
|
||||||
"Throttling": {},
|
"Throttling": {},
|
||||||
"ThrottlingException": {},
|
"ThrottlingException": {},
|
||||||
"RequestLimitExceeded": {},
|
"RequestLimitExceeded": {},
|
||||||
|
@ -60,6 +92,7 @@ var throttleCodes = map[string]struct{}{
|
||||||
"TooManyRequestsException": {}, // Lambda functions
|
"TooManyRequestsException": {}, // Lambda functions
|
||||||
"PriorRequestNotComplete": {}, // Route53
|
"PriorRequestNotComplete": {}, // Route53
|
||||||
"TransactionInProgressException": {},
|
"TransactionInProgressException": {},
|
||||||
|
"EC2ThrottledException": {}, // EC2
|
||||||
}
|
}
|
||||||
|
|
||||||
// credsExpiredCodes is a collection of error codes which signify the credentials
|
// credsExpiredCodes is a collection of error codes which signify the credentials
|
||||||
|
@ -145,8 +178,8 @@ func shouldRetryError(origErr error) bool {
|
||||||
origErr := err.OrigErr()
|
origErr := err.OrigErr()
|
||||||
var shouldRetry bool
|
var shouldRetry bool
|
||||||
if origErr != nil {
|
if origErr != nil {
|
||||||
shouldRetry := shouldRetryError(origErr)
|
shouldRetry = shouldRetryError(origErr)
|
||||||
if err.Code() == "RequestError" && !shouldRetry {
|
if err.Code() == ErrCodeRequestError && !shouldRetry {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package session
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
@ -47,10 +48,10 @@ func resolveCredentials(cfg *aws.Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebIdentityEmptyRoleARNErr will occur if 'AWS_WEB_IDENTITY_TOKEN_FILE' was set but
|
// WebIdentityEmptyRoleARNErr will occur if 'AWS_WEB_IDENTITY_TOKEN_FILE' was set but
|
||||||
// 'AWS_IAM_ROLE_ARN' was not set.
|
// 'AWS_ROLE_ARN' was not set.
|
||||||
var WebIdentityEmptyRoleARNErr = awserr.New(stscreds.ErrCodeWebIdentity, "role ARN is not set", nil)
|
var WebIdentityEmptyRoleARNErr = awserr.New(stscreds.ErrCodeWebIdentity, "role ARN is not set", nil)
|
||||||
|
|
||||||
// WebIdentityEmptyTokenFilePathErr will occur if 'AWS_IAM_ROLE_ARN' was set but
|
// WebIdentityEmptyTokenFilePathErr will occur if 'AWS_ROLE_ARN' was set but
|
||||||
// 'AWS_WEB_IDENTITY_TOKEN_FILE' was not set.
|
// 'AWS_WEB_IDENTITY_TOKEN_FILE' was not set.
|
||||||
var WebIdentityEmptyTokenFilePathErr = awserr.New(stscreds.ErrCodeWebIdentity, "token file path is not set", nil)
|
var WebIdentityEmptyTokenFilePathErr = awserr.New(stscreds.ErrCodeWebIdentity, "token file path is not set", nil)
|
||||||
|
|
||||||
|
@ -206,7 +207,14 @@ func credsFromAssumeRole(cfg aws.Config,
|
||||||
sharedCfg.RoleARN,
|
sharedCfg.RoleARN,
|
||||||
func(opt *stscreds.AssumeRoleProvider) {
|
func(opt *stscreds.AssumeRoleProvider) {
|
||||||
opt.RoleSessionName = sharedCfg.RoleSessionName
|
opt.RoleSessionName = sharedCfg.RoleSessionName
|
||||||
|
|
||||||
|
if sessOpts.AssumeRoleDuration == 0 &&
|
||||||
|
sharedCfg.AssumeRoleDuration != nil &&
|
||||||
|
*sharedCfg.AssumeRoleDuration/time.Minute > 15 {
|
||||||
|
opt.Duration = *sharedCfg.AssumeRoleDuration
|
||||||
|
} else if sessOpts.AssumeRoleDuration != 0 {
|
||||||
opt.Duration = sessOpts.AssumeRoleDuration
|
opt.Duration = sessOpts.AssumeRoleDuration
|
||||||
|
}
|
||||||
|
|
||||||
// Assume role with external ID
|
// Assume role with external ID
|
||||||
if len(sharedCfg.ExternalID) > 0 {
|
if len(sharedCfg.ExternalID) > 0 {
|
||||||
|
|
|
@ -241,5 +241,22 @@ over the AWS_CA_BUNDLE environment variable, and will be used if both are set.
|
||||||
Setting a custom HTTPClient in the aws.Config options will override this setting.
|
Setting a custom HTTPClient in the aws.Config options will override this setting.
|
||||||
To use this option and custom HTTP client, the HTTP client needs to be provided
|
To use this option and custom HTTP client, the HTTP client needs to be provided
|
||||||
when creating the session. Not the service client.
|
when creating the session. Not the service client.
|
||||||
|
|
||||||
|
The endpoint of the EC2 IMDS client can be configured via the environment
|
||||||
|
variable, AWS_EC2_METADATA_SERVICE_ENDPOINT when creating the client with a
|
||||||
|
Session. See Options.EC2IMDSEndpoint for more details.
|
||||||
|
|
||||||
|
AWS_EC2_METADATA_SERVICE_ENDPOINT=http://169.254.169.254
|
||||||
|
|
||||||
|
If using an URL with an IPv6 address literal, the IPv6 address
|
||||||
|
component must be enclosed in square brackets.
|
||||||
|
|
||||||
|
AWS_EC2_METADATA_SERVICE_ENDPOINT=http://[::1]
|
||||||
|
|
||||||
|
The custom EC2 IMDS endpoint can also be specified via the Session options.
|
||||||
|
|
||||||
|
sess, err := session.NewSessionWithOptions(session.Options{
|
||||||
|
EC2IMDSEndpoint: "http://[::1]",
|
||||||
|
})
|
||||||
*/
|
*/
|
||||||
package session
|
package session
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package session
|
package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnvProviderName provides a name of the provider when config is loaded from environment.
|
// EnvProviderName provides a name of the provider when config is loaded from environment.
|
||||||
|
@ -125,6 +128,31 @@ type envConfig struct {
|
||||||
//
|
//
|
||||||
// AWS_ROLE_SESSION_NAME=session_name
|
// AWS_ROLE_SESSION_NAME=session_name
|
||||||
RoleSessionName string
|
RoleSessionName string
|
||||||
|
|
||||||
|
// Specifies the STS Regional Endpoint flag for the SDK to resolve the endpoint
|
||||||
|
// for a service.
|
||||||
|
//
|
||||||
|
// AWS_STS_REGIONAL_ENDPOINTS=regional
|
||||||
|
// This can take value as `regional` or `legacy`
|
||||||
|
STSRegionalEndpoint endpoints.STSRegionalEndpoint
|
||||||
|
|
||||||
|
// Specifies the S3 Regional Endpoint flag for the SDK to resolve the
|
||||||
|
// endpoint for a service.
|
||||||
|
//
|
||||||
|
// AWS_S3_US_EAST_1_REGIONAL_ENDPOINT=regional
|
||||||
|
// This can take value as `regional` or `legacy`
|
||||||
|
S3UsEast1RegionalEndpoint endpoints.S3UsEast1RegionalEndpoint
|
||||||
|
|
||||||
|
// Specifies if the S3 service should allow ARNs to direct the region
|
||||||
|
// the client's requests are sent to.
|
||||||
|
//
|
||||||
|
// AWS_S3_USE_ARN_REGION=true
|
||||||
|
S3UseARNRegion bool
|
||||||
|
|
||||||
|
// Specifies the alternative endpoint to use for EC2 IMDS.
|
||||||
|
//
|
||||||
|
// AWS_EC2_METADATA_SERVICE_ENDPOINT=http://[::1]
|
||||||
|
EC2IMDSEndpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -179,6 +207,18 @@ var (
|
||||||
roleSessionNameEnvKey = []string{
|
roleSessionNameEnvKey = []string{
|
||||||
"AWS_ROLE_SESSION_NAME",
|
"AWS_ROLE_SESSION_NAME",
|
||||||
}
|
}
|
||||||
|
stsRegionalEndpointKey = []string{
|
||||||
|
"AWS_STS_REGIONAL_ENDPOINTS",
|
||||||
|
}
|
||||||
|
s3UsEast1RegionalEndpoint = []string{
|
||||||
|
"AWS_S3_US_EAST_1_REGIONAL_ENDPOINT",
|
||||||
|
}
|
||||||
|
s3UseARNRegionEnvKey = []string{
|
||||||
|
"AWS_S3_USE_ARN_REGION",
|
||||||
|
}
|
||||||
|
ec2IMDSEndpointEnvKey = []string{
|
||||||
|
"AWS_EC2_METADATA_SERVICE_ENDPOINT",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// loadEnvConfig retrieves the SDK's environment configuration.
|
// loadEnvConfig retrieves the SDK's environment configuration.
|
||||||
|
@ -187,7 +227,7 @@ var (
|
||||||
// If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value
|
// If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value
|
||||||
// the shared SDK config will be loaded in addition to the SDK's specific
|
// the shared SDK config will be loaded in addition to the SDK's specific
|
||||||
// configuration values.
|
// configuration values.
|
||||||
func loadEnvConfig() envConfig {
|
func loadEnvConfig() (envConfig, error) {
|
||||||
enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG"))
|
enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG"))
|
||||||
return envConfigLoad(enableSharedConfig)
|
return envConfigLoad(enableSharedConfig)
|
||||||
}
|
}
|
||||||
|
@ -198,11 +238,11 @@ func loadEnvConfig() envConfig {
|
||||||
// Loads the shared configuration in addition to the SDK's specific configuration.
|
// Loads the shared configuration in addition to the SDK's specific configuration.
|
||||||
// This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG`
|
// This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG`
|
||||||
// environment variable is set.
|
// environment variable is set.
|
||||||
func loadSharedEnvConfig() envConfig {
|
func loadSharedEnvConfig() (envConfig, error) {
|
||||||
return envConfigLoad(true)
|
return envConfigLoad(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func envConfigLoad(enableSharedConfig bool) envConfig {
|
func envConfigLoad(enableSharedConfig bool) (envConfig, error) {
|
||||||
cfg := envConfig{}
|
cfg := envConfig{}
|
||||||
|
|
||||||
cfg.EnableSharedConfig = enableSharedConfig
|
cfg.EnableSharedConfig = enableSharedConfig
|
||||||
|
@ -264,12 +304,50 @@ func envConfigLoad(enableSharedConfig bool) envConfig {
|
||||||
|
|
||||||
cfg.CustomCABundle = os.Getenv("AWS_CA_BUNDLE")
|
cfg.CustomCABundle = os.Getenv("AWS_CA_BUNDLE")
|
||||||
|
|
||||||
return cfg
|
var err error
|
||||||
|
// STS Regional Endpoint variable
|
||||||
|
for _, k := range stsRegionalEndpointKey {
|
||||||
|
if v := os.Getenv(k); len(v) != 0 {
|
||||||
|
cfg.STSRegionalEndpoint, err = endpoints.GetSTSRegionalEndpoint(v)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("failed to load, %v from env config, %v", k, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// S3 Regional Endpoint variable
|
||||||
|
for _, k := range s3UsEast1RegionalEndpoint {
|
||||||
|
if v := os.Getenv(k); len(v) != 0 {
|
||||||
|
cfg.S3UsEast1RegionalEndpoint, err = endpoints.GetS3UsEast1RegionalEndpoint(v)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("failed to load, %v from env config, %v", k, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var s3UseARNRegion string
|
||||||
|
setFromEnvVal(&s3UseARNRegion, s3UseARNRegionEnvKey)
|
||||||
|
if len(s3UseARNRegion) != 0 {
|
||||||
|
switch {
|
||||||
|
case strings.EqualFold(s3UseARNRegion, "false"):
|
||||||
|
cfg.S3UseARNRegion = false
|
||||||
|
case strings.EqualFold(s3UseARNRegion, "true"):
|
||||||
|
cfg.S3UseARNRegion = true
|
||||||
|
default:
|
||||||
|
return envConfig{}, fmt.Errorf(
|
||||||
|
"invalid value for environment variable, %s=%s, need true or false",
|
||||||
|
s3UseARNRegionEnvKey[0], s3UseARNRegion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setFromEnvVal(&cfg.EC2IMDSEndpoint, ec2IMDSEndpointEnvKey)
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFromEnvVal(dst *string, keys []string) {
|
func setFromEnvVal(dst *string, keys []string) {
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if v := os.Getenv(k); len(v) > 0 {
|
if v := os.Getenv(k); len(v) != 0 {
|
||||||
*dst = v
|
*dst = v
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,8 @@ var ErrSharedConfigInvalidCredSource = awserr.New(ErrCodeSharedConfig, "credenti
|
||||||
type Session struct {
|
type Session struct {
|
||||||
Config *aws.Config
|
Config *aws.Config
|
||||||
Handlers request.Handlers
|
Handlers request.Handlers
|
||||||
|
|
||||||
|
options Options
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new instance of the handlers merging in the provided configs
|
// New creates a new instance of the handlers merging in the provided configs
|
||||||
|
@ -73,7 +75,7 @@ type Session struct {
|
||||||
// func is called instead of waiting to receive an error until a request is made.
|
// func is called instead of waiting to receive an error until a request is made.
|
||||||
func New(cfgs ...*aws.Config) *Session {
|
func New(cfgs ...*aws.Config) *Session {
|
||||||
// load initial config from environment
|
// load initial config from environment
|
||||||
envCfg := loadEnvConfig()
|
envCfg, envErr := loadEnvConfig()
|
||||||
|
|
||||||
if envCfg.EnableSharedConfig {
|
if envCfg.EnableSharedConfig {
|
||||||
var cfg aws.Config
|
var cfg aws.Config
|
||||||
|
@ -93,17 +95,17 @@ func New(cfgs ...*aws.Config) *Session {
|
||||||
// Session creation failed, need to report the error and prevent
|
// Session creation failed, need to report the error and prevent
|
||||||
// any requests from succeeding.
|
// any requests from succeeding.
|
||||||
s = &Session{Config: defaults.Config()}
|
s = &Session{Config: defaults.Config()}
|
||||||
s.Config.MergeIn(cfgs...)
|
s.logDeprecatedNewSessionError(msg, err, cfgs)
|
||||||
s.Config.Logger.Log("ERROR:", msg, "Error:", err)
|
|
||||||
s.Handlers.Validate.PushBack(func(r *request.Request) {
|
|
||||||
r.Error = err
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
s := deprecatedNewSession(cfgs...)
|
s := deprecatedNewSession(envCfg, cfgs...)
|
||||||
|
if envErr != nil {
|
||||||
|
msg := "failed to load env config"
|
||||||
|
s.logDeprecatedNewSessionError(msg, envErr, cfgs)
|
||||||
|
}
|
||||||
|
|
||||||
if csmCfg, err := loadCSMConfig(envCfg, []string{}); err != nil {
|
if csmCfg, err := loadCSMConfig(envCfg, []string{}); err != nil {
|
||||||
if l := s.Config.Logger; l != nil {
|
if l := s.Config.Logger; l != nil {
|
||||||
|
@ -112,11 +114,8 @@ func New(cfgs ...*aws.Config) *Session {
|
||||||
} else if csmCfg.Enabled {
|
} else if csmCfg.Enabled {
|
||||||
err := enableCSM(&s.Handlers, csmCfg, s.Config.Logger)
|
err := enableCSM(&s.Handlers, csmCfg, s.Config.Logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("failed to enable CSM, %v", err)
|
msg := "failed to enable CSM"
|
||||||
s.Config.Logger.Log("ERROR:", err.Error())
|
s.logDeprecatedNewSessionError(msg, err, cfgs)
|
||||||
s.Handlers.Validate.PushBack(func(r *request.Request) {
|
|
||||||
r.Error = err
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,6 +245,23 @@ type Options struct {
|
||||||
// function to initialize this value before changing the handlers to be
|
// function to initialize this value before changing the handlers to be
|
||||||
// used by the SDK.
|
// used by the SDK.
|
||||||
Handlers request.Handlers
|
Handlers request.Handlers
|
||||||
|
|
||||||
|
// Allows specifying a custom endpoint to be used by the EC2 IMDS client
|
||||||
|
// when making requests to the EC2 IMDS API. The must endpoint value must
|
||||||
|
// include protocol prefix.
|
||||||
|
//
|
||||||
|
// If unset, will the EC2 IMDS client will use its default endpoint.
|
||||||
|
//
|
||||||
|
// Can also be specified via the environment variable,
|
||||||
|
// AWS_EC2_METADATA_SERVICE_ENDPOINT.
|
||||||
|
//
|
||||||
|
// AWS_EC2_METADATA_SERVICE_ENDPOINT=http://169.254.169.254
|
||||||
|
//
|
||||||
|
// If using an URL with an IPv6 address literal, the IPv6 address
|
||||||
|
// component must be enclosed in square brackets.
|
||||||
|
//
|
||||||
|
// AWS_EC2_METADATA_SERVICE_ENDPOINT=http://[::1]
|
||||||
|
EC2IMDSEndpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSessionWithOptions returns a new Session created from SDK defaults, config files,
|
// NewSessionWithOptions returns a new Session created from SDK defaults, config files,
|
||||||
|
@ -279,10 +295,17 @@ type Options struct {
|
||||||
// }))
|
// }))
|
||||||
func NewSessionWithOptions(opts Options) (*Session, error) {
|
func NewSessionWithOptions(opts Options) (*Session, error) {
|
||||||
var envCfg envConfig
|
var envCfg envConfig
|
||||||
|
var err error
|
||||||
if opts.SharedConfigState == SharedConfigEnable {
|
if opts.SharedConfigState == SharedConfigEnable {
|
||||||
envCfg = loadSharedEnvConfig()
|
envCfg, err = loadSharedEnvConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to load shared config, %v", err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
envCfg = loadEnvConfig()
|
envCfg, err = loadEnvConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to load environment config, %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.Profile) != 0 {
|
if len(opts.Profile) != 0 {
|
||||||
|
@ -325,7 +348,25 @@ func Must(sess *Session, err error) *Session {
|
||||||
return sess
|
return sess
|
||||||
}
|
}
|
||||||
|
|
||||||
func deprecatedNewSession(cfgs ...*aws.Config) *Session {
|
// Wraps the endpoint resolver with a resolver that will return a custom
|
||||||
|
// endpoint for EC2 IMDS.
|
||||||
|
func wrapEC2IMDSEndpoint(resolver endpoints.Resolver, endpoint string) endpoints.Resolver {
|
||||||
|
return endpoints.ResolverFunc(
|
||||||
|
func(service, region string, opts ...func(*endpoints.Options)) (
|
||||||
|
endpoints.ResolvedEndpoint, error,
|
||||||
|
) {
|
||||||
|
if service == ec2MetadataServiceID {
|
||||||
|
return endpoints.ResolvedEndpoint{
|
||||||
|
URL: endpoint,
|
||||||
|
SigningName: ec2MetadataServiceID,
|
||||||
|
SigningRegion: region,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return resolver.EndpointFor(service, region)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func deprecatedNewSession(envCfg envConfig, cfgs ...*aws.Config) *Session {
|
||||||
cfg := defaults.Config()
|
cfg := defaults.Config()
|
||||||
handlers := defaults.Handlers()
|
handlers := defaults.Handlers()
|
||||||
|
|
||||||
|
@ -337,6 +378,11 @@ func deprecatedNewSession(cfgs ...*aws.Config) *Session {
|
||||||
// endpoints for service client configurations.
|
// endpoints for service client configurations.
|
||||||
cfg.EndpointResolver = endpoints.DefaultResolver()
|
cfg.EndpointResolver = endpoints.DefaultResolver()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(envCfg.EC2IMDSEndpoint) != 0 {
|
||||||
|
cfg.EndpointResolver = wrapEC2IMDSEndpoint(cfg.EndpointResolver, envCfg.EC2IMDSEndpoint)
|
||||||
|
}
|
||||||
|
|
||||||
cfg.Credentials = defaults.CredChain(cfg, handlers)
|
cfg.Credentials = defaults.CredChain(cfg, handlers)
|
||||||
|
|
||||||
// Reapply any passed in configs to override credentials if set
|
// Reapply any passed in configs to override credentials if set
|
||||||
|
@ -345,6 +391,9 @@ func deprecatedNewSession(cfgs ...*aws.Config) *Session {
|
||||||
s := &Session{
|
s := &Session{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Handlers: handlers,
|
Handlers: handlers,
|
||||||
|
options: Options{
|
||||||
|
EC2IMDSEndpoint: envCfg.EC2IMDSEndpoint,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
initHandlers(s)
|
initHandlers(s)
|
||||||
|
@ -414,6 +463,7 @@ func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session,
|
||||||
s := &Session{
|
s := &Session{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Handlers: handlers,
|
Handlers: handlers,
|
||||||
|
options: opts,
|
||||||
}
|
}
|
||||||
|
|
||||||
initHandlers(s)
|
initHandlers(s)
|
||||||
|
@ -550,6 +600,30 @@ func mergeConfigSrcs(cfg, userCfg *aws.Config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regional Endpoint flag for STS endpoint resolving
|
||||||
|
mergeSTSRegionalEndpointConfig(cfg, []endpoints.STSRegionalEndpoint{
|
||||||
|
userCfg.STSRegionalEndpoint,
|
||||||
|
envCfg.STSRegionalEndpoint,
|
||||||
|
sharedCfg.STSRegionalEndpoint,
|
||||||
|
endpoints.LegacySTSEndpoint,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Regional Endpoint flag for S3 endpoint resolving
|
||||||
|
mergeS3UsEast1RegionalEndpointConfig(cfg, []endpoints.S3UsEast1RegionalEndpoint{
|
||||||
|
userCfg.S3UsEast1RegionalEndpoint,
|
||||||
|
envCfg.S3UsEast1RegionalEndpoint,
|
||||||
|
sharedCfg.S3UsEast1RegionalEndpoint,
|
||||||
|
endpoints.LegacyS3UsEast1Endpoint,
|
||||||
|
})
|
||||||
|
|
||||||
|
ec2IMDSEndpoint := sessOpts.EC2IMDSEndpoint
|
||||||
|
if len(ec2IMDSEndpoint) == 0 {
|
||||||
|
ec2IMDSEndpoint = envCfg.EC2IMDSEndpoint
|
||||||
|
}
|
||||||
|
if len(ec2IMDSEndpoint) != 0 {
|
||||||
|
cfg.EndpointResolver = wrapEC2IMDSEndpoint(cfg.EndpointResolver, ec2IMDSEndpoint)
|
||||||
|
}
|
||||||
|
|
||||||
// Configure credentials if not already set by the user when creating the
|
// Configure credentials if not already set by the user when creating the
|
||||||
// Session.
|
// Session.
|
||||||
if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
|
if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
|
||||||
|
@ -560,9 +634,35 @@ func mergeConfigSrcs(cfg, userCfg *aws.Config,
|
||||||
cfg.Credentials = creds
|
cfg.Credentials = creds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg.S3UseARNRegion = userCfg.S3UseARNRegion
|
||||||
|
if cfg.S3UseARNRegion == nil {
|
||||||
|
cfg.S3UseARNRegion = &envCfg.S3UseARNRegion
|
||||||
|
}
|
||||||
|
if cfg.S3UseARNRegion == nil {
|
||||||
|
cfg.S3UseARNRegion = &sharedCfg.S3UseARNRegion
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mergeSTSRegionalEndpointConfig(cfg *aws.Config, values []endpoints.STSRegionalEndpoint) {
|
||||||
|
for _, v := range values {
|
||||||
|
if v != endpoints.UnsetSTSEndpoint {
|
||||||
|
cfg.STSRegionalEndpoint = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeS3UsEast1RegionalEndpointConfig(cfg *aws.Config, values []endpoints.S3UsEast1RegionalEndpoint) {
|
||||||
|
for _, v := range values {
|
||||||
|
if v != endpoints.UnsetS3UsEast1Endpoint {
|
||||||
|
cfg.S3UsEast1RegionalEndpoint = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func initHandlers(s *Session) {
|
func initHandlers(s *Session) {
|
||||||
// Add the Validate parameter handler if it is not disabled.
|
// Add the Validate parameter handler if it is not disabled.
|
||||||
s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
|
s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
|
||||||
|
@ -581,6 +681,7 @@ func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
||||||
newSession := &Session{
|
newSession := &Session{
|
||||||
Config: s.Config.Copy(cfgs...),
|
Config: s.Config.Copy(cfgs...),
|
||||||
Handlers: s.Handlers.Copy(),
|
Handlers: s.Handlers.Copy(),
|
||||||
|
options: s.options,
|
||||||
}
|
}
|
||||||
|
|
||||||
initHandlers(newSession)
|
initHandlers(newSession)
|
||||||
|
@ -591,47 +692,69 @@ func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
||||||
// ClientConfig satisfies the client.ConfigProvider interface and is used to
|
// ClientConfig satisfies the client.ConfigProvider interface and is used to
|
||||||
// configure the service client instances. Passing the Session to the service
|
// configure the service client instances. Passing the Session to the service
|
||||||
// client's constructor (New) will use this method to configure the client.
|
// client's constructor (New) will use this method to configure the client.
|
||||||
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
|
func (s *Session) ClientConfig(service string, cfgs ...*aws.Config) client.Config {
|
||||||
// Backwards compatibility, the error will be eaten if user calls ClientConfig
|
|
||||||
// directly. All SDK services will use ClientconfigWithError.
|
|
||||||
cfg, _ := s.clientConfigWithErr(serviceName, cfgs...)
|
|
||||||
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Session) clientConfigWithErr(serviceName string, cfgs ...*aws.Config) (client.Config, error) {
|
|
||||||
s = s.Copy(cfgs...)
|
s = s.Copy(cfgs...)
|
||||||
|
|
||||||
var resolved endpoints.ResolvedEndpoint
|
|
||||||
var err error
|
|
||||||
|
|
||||||
region := aws.StringValue(s.Config.Region)
|
region := aws.StringValue(s.Config.Region)
|
||||||
|
resolved, err := s.resolveEndpoint(service, region, s.Config)
|
||||||
|
if err != nil {
|
||||||
|
s.Handlers.Validate.PushBack(func(r *request.Request) {
|
||||||
|
if len(r.ClientInfo.Endpoint) != 0 {
|
||||||
|
// Error occurred while resolving endpoint, but the request
|
||||||
|
// being invoked has had an endpoint specified after the client
|
||||||
|
// was created.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.Error = err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if endpoint := aws.StringValue(s.Config.Endpoint); len(endpoint) != 0 {
|
return client.Config{
|
||||||
resolved.URL = endpoints.AddScheme(endpoint, aws.BoolValue(s.Config.DisableSSL))
|
Config: s.Config,
|
||||||
resolved.SigningRegion = region
|
Handlers: s.Handlers,
|
||||||
} else {
|
PartitionID: resolved.PartitionID,
|
||||||
resolved, err = s.Config.EndpointResolver.EndpointFor(
|
Endpoint: resolved.URL,
|
||||||
serviceName, region,
|
SigningRegion: resolved.SigningRegion,
|
||||||
|
SigningNameDerived: resolved.SigningNameDerived,
|
||||||
|
SigningName: resolved.SigningName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ec2MetadataServiceID = "ec2metadata"
|
||||||
|
|
||||||
|
func (s *Session) resolveEndpoint(service, region string, cfg *aws.Config) (endpoints.ResolvedEndpoint, error) {
|
||||||
|
|
||||||
|
if ep := aws.StringValue(cfg.Endpoint); len(ep) != 0 {
|
||||||
|
return endpoints.ResolvedEndpoint{
|
||||||
|
URL: endpoints.AddScheme(ep, aws.BoolValue(cfg.DisableSSL)),
|
||||||
|
SigningRegion: region,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved, err := cfg.EndpointResolver.EndpointFor(service, region,
|
||||||
func(opt *endpoints.Options) {
|
func(opt *endpoints.Options) {
|
||||||
opt.DisableSSL = aws.BoolValue(s.Config.DisableSSL)
|
opt.DisableSSL = aws.BoolValue(cfg.DisableSSL)
|
||||||
opt.UseDualStack = aws.BoolValue(s.Config.UseDualStack)
|
opt.UseDualStack = aws.BoolValue(cfg.UseDualStack)
|
||||||
|
// Support for STSRegionalEndpoint where the STSRegionalEndpoint is
|
||||||
|
// provided in envConfig or sharedConfig with envConfig getting
|
||||||
|
// precedence.
|
||||||
|
opt.STSRegionalEndpoint = cfg.STSRegionalEndpoint
|
||||||
|
|
||||||
|
// Support for S3UsEast1RegionalEndpoint where the S3UsEast1RegionalEndpoint is
|
||||||
|
// provided in envConfig or sharedConfig with envConfig getting
|
||||||
|
// precedence.
|
||||||
|
opt.S3UsEast1RegionalEndpoint = cfg.S3UsEast1RegionalEndpoint
|
||||||
|
|
||||||
// Support the condition where the service is modeled but its
|
// Support the condition where the service is modeled but its
|
||||||
// endpoint metadata is not available.
|
// endpoint metadata is not available.
|
||||||
opt.ResolveUnknownService = true
|
opt.ResolveUnknownService = true
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return endpoints.ResolvedEndpoint{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.Config{
|
return resolved, nil
|
||||||
Config: s.Config,
|
|
||||||
Handlers: s.Handlers,
|
|
||||||
Endpoint: resolved.URL,
|
|
||||||
SigningRegion: resolved.SigningRegion,
|
|
||||||
SigningNameDerived: resolved.SigningNameDerived,
|
|
||||||
SigningName: resolved.SigningName,
|
|
||||||
}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception
|
// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception
|
||||||
|
@ -641,12 +764,9 @@ func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Conf
|
||||||
s = s.Copy(cfgs...)
|
s = s.Copy(cfgs...)
|
||||||
|
|
||||||
var resolved endpoints.ResolvedEndpoint
|
var resolved endpoints.ResolvedEndpoint
|
||||||
|
|
||||||
region := aws.StringValue(s.Config.Region)
|
|
||||||
|
|
||||||
if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 {
|
if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 {
|
||||||
resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL))
|
resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL))
|
||||||
resolved.SigningRegion = region
|
resolved.SigningRegion = aws.StringValue(s.Config.Region)
|
||||||
}
|
}
|
||||||
|
|
||||||
return client.Config{
|
return client.Config{
|
||||||
|
@ -658,3 +778,14 @@ func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Conf
|
||||||
SigningName: resolved.SigningName,
|
SigningName: resolved.SigningName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logDeprecatedNewSessionError function enables error handling for session
|
||||||
|
func (s *Session) logDeprecatedNewSessionError(msg string, err error, cfgs []*aws.Config) {
|
||||||
|
// Session creation failed, need to report the error and prevent
|
||||||
|
// any requests from succeeding.
|
||||||
|
s.Config.MergeIn(cfgs...)
|
||||||
|
s.Config.Logger.Log("ERROR:", msg, "Error:", err)
|
||||||
|
s.Handlers.Validate.PushBack(func(r *request.Request) {
|
||||||
|
r.Error = err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@ package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||||
"github.com/aws/aws-sdk-go/internal/ini"
|
"github.com/aws/aws-sdk-go/internal/ini"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ const (
|
||||||
externalIDKey = `external_id` // optional
|
externalIDKey = `external_id` // optional
|
||||||
mfaSerialKey = `mfa_serial` // optional
|
mfaSerialKey = `mfa_serial` // optional
|
||||||
roleSessionNameKey = `role_session_name` // optional
|
roleSessionNameKey = `role_session_name` // optional
|
||||||
|
roleDurationSecondsKey = "duration_seconds" // optional
|
||||||
|
|
||||||
// CSM options
|
// CSM options
|
||||||
csmEnabledKey = `csm_enabled`
|
csmEnabledKey = `csm_enabled`
|
||||||
|
@ -40,10 +43,19 @@ const (
|
||||||
// Web Identity Token File
|
// Web Identity Token File
|
||||||
webIdentityTokenFileKey = `web_identity_token_file` // optional
|
webIdentityTokenFileKey = `web_identity_token_file` // optional
|
||||||
|
|
||||||
|
// Additional config fields for regional or legacy endpoints
|
||||||
|
stsRegionalEndpointSharedKey = `sts_regional_endpoints`
|
||||||
|
|
||||||
|
// Additional config fields for regional or legacy endpoints
|
||||||
|
s3UsEast1RegionalSharedKey = `s3_us_east_1_regional_endpoint`
|
||||||
|
|
||||||
// DefaultSharedConfigProfile is the default profile to be used when
|
// DefaultSharedConfigProfile is the default profile to be used when
|
||||||
// loading configuration from the config files if another profile name
|
// loading configuration from the config files if another profile name
|
||||||
// is not provided.
|
// is not provided.
|
||||||
DefaultSharedConfigProfile = `default`
|
DefaultSharedConfigProfile = `default`
|
||||||
|
|
||||||
|
// S3 ARN Region Usage
|
||||||
|
s3UseARNRegionKey = "s3_use_arn_region"
|
||||||
)
|
)
|
||||||
|
|
||||||
// sharedConfig represents the configuration fields of the SDK config files.
|
// sharedConfig represents the configuration fields of the SDK config files.
|
||||||
|
@ -67,6 +79,7 @@ type sharedConfig struct {
|
||||||
RoleSessionName string
|
RoleSessionName string
|
||||||
ExternalID string
|
ExternalID string
|
||||||
MFASerial string
|
MFASerial string
|
||||||
|
AssumeRoleDuration *time.Duration
|
||||||
|
|
||||||
SourceProfileName string
|
SourceProfileName string
|
||||||
SourceProfile *sharedConfig
|
SourceProfile *sharedConfig
|
||||||
|
@ -88,6 +101,24 @@ type sharedConfig struct {
|
||||||
CSMHost string
|
CSMHost string
|
||||||
CSMPort string
|
CSMPort string
|
||||||
CSMClientID string
|
CSMClientID string
|
||||||
|
|
||||||
|
// Specifies the Regional Endpoint flag for the SDK to resolve the endpoint for a service
|
||||||
|
//
|
||||||
|
// sts_regional_endpoints = regional
|
||||||
|
// This can take value as `LegacySTSEndpoint` or `RegionalSTSEndpoint`
|
||||||
|
STSRegionalEndpoint endpoints.STSRegionalEndpoint
|
||||||
|
|
||||||
|
// Specifies the Regional Endpoint flag for the SDK to resolve the endpoint for a service
|
||||||
|
//
|
||||||
|
// s3_us_east_1_regional_endpoint = regional
|
||||||
|
// This can take value as `LegacyS3UsEast1Endpoint` or `RegionalS3UsEast1Endpoint`
|
||||||
|
S3UsEast1RegionalEndpoint endpoints.S3UsEast1RegionalEndpoint
|
||||||
|
|
||||||
|
// Specifies if the S3 service should allow ARNs to direct the region
|
||||||
|
// the client's requests are sent to.
|
||||||
|
//
|
||||||
|
// s3_use_arn_region=true
|
||||||
|
S3UseARNRegion bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type sharedConfigFile struct {
|
type sharedConfigFile struct {
|
||||||
|
@ -244,8 +275,30 @@ func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile, e
|
||||||
updateString(&cfg.RoleSessionName, section, roleSessionNameKey)
|
updateString(&cfg.RoleSessionName, section, roleSessionNameKey)
|
||||||
updateString(&cfg.SourceProfileName, section, sourceProfileKey)
|
updateString(&cfg.SourceProfileName, section, sourceProfileKey)
|
||||||
updateString(&cfg.CredentialSource, section, credentialSourceKey)
|
updateString(&cfg.CredentialSource, section, credentialSourceKey)
|
||||||
|
|
||||||
updateString(&cfg.Region, section, regionKey)
|
updateString(&cfg.Region, section, regionKey)
|
||||||
|
|
||||||
|
if section.Has(roleDurationSecondsKey) {
|
||||||
|
d := time.Duration(section.Int(roleDurationSecondsKey)) * time.Second
|
||||||
|
cfg.AssumeRoleDuration = &d
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := section.String(stsRegionalEndpointSharedKey); len(v) != 0 {
|
||||||
|
sre, err := endpoints.GetSTSRegionalEndpoint(v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to load %s from shared config, %s, %v",
|
||||||
|
stsRegionalEndpointSharedKey, file.Filename, err)
|
||||||
|
}
|
||||||
|
cfg.STSRegionalEndpoint = sre
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := section.String(s3UsEast1RegionalSharedKey); len(v) != 0 {
|
||||||
|
sre, err := endpoints.GetS3UsEast1RegionalEndpoint(v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to load %s from shared config, %s, %v",
|
||||||
|
s3UsEast1RegionalSharedKey, file.Filename, err)
|
||||||
|
}
|
||||||
|
cfg.S3UsEast1RegionalEndpoint = sre
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateString(&cfg.CredentialProcess, section, credentialProcessKey)
|
updateString(&cfg.CredentialProcess, section, credentialProcessKey)
|
||||||
|
@ -271,6 +324,8 @@ func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile, e
|
||||||
updateString(&cfg.CSMPort, section, csmPortKey)
|
updateString(&cfg.CSMPort, section, csmPortKey)
|
||||||
updateString(&cfg.CSMClientID, section, csmClientIDKey)
|
updateString(&cfg.CSMClientID, section, csmClientIDKey)
|
||||||
|
|
||||||
|
updateBool(&cfg.S3UseARNRegion, section, s3UseARNRegionKey)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,6 +418,15 @@ func updateString(dst *string, section ini.Section, key string) {
|
||||||
*dst = section.String(key)
|
*dst = section.String(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateBool will only update the dst with the value in the section key, key
|
||||||
|
// is present in the section.
|
||||||
|
func updateBool(dst *bool, section ini.Section, key string) {
|
||||||
|
if !section.Has(key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*dst = section.Bool(key)
|
||||||
|
}
|
||||||
|
|
||||||
// updateBoolPtr will only update the dst with the value in the section key,
|
// updateBoolPtr will only update the dst with the value in the section key,
|
||||||
// key is present in the section.
|
// key is present in the section.
|
||||||
func updateBoolPtr(dst **bool, section ini.Section, key string) {
|
func updateBoolPtr(dst **bool, section ini.Section, key string) {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package v4
|
package v4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"github.com/aws/aws-sdk-go/internal/strings"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// validator houses a set of rule needed for validation of a
|
// validator houses a set of rule needed for validation of a
|
||||||
|
@ -61,7 +60,7 @@ type patterns []string
|
||||||
// been found
|
// been found
|
||||||
func (p patterns) IsValid(value string) bool {
|
func (p patterns) IsValid(value string) bool {
|
||||||
for _, pattern := range p {
|
for _, pattern := range p {
|
||||||
if strings.HasPrefix(http.CanonicalHeaderKey(value), pattern) {
|
if strings.HasPrefixFold(value, pattern) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/request_context_go1.5.go
generated
vendored
Normal file
13
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/request_context_go1.5.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package v4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
)
|
||||||
|
|
||||||
|
func requestContext(r *http.Request) aws.Context {
|
||||||
|
return aws.BackgroundContext()
|
||||||
|
}
|
13
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/request_context_go1.7.go
generated
vendored
Normal file
13
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/request_context_go1.7.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package v4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
)
|
||||||
|
|
||||||
|
func requestContext(r *http.Request) aws.Context {
|
||||||
|
return r.Context()
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package v4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
type credentialValueProvider interface {
|
||||||
|
Get() (credentials.Value, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StreamSigner implements signing of event stream encoded payloads
|
||||||
|
type StreamSigner struct {
|
||||||
|
region string
|
||||||
|
service string
|
||||||
|
|
||||||
|
credentials credentialValueProvider
|
||||||
|
|
||||||
|
prevSig []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStreamSigner creates a SigV4 signer used to sign Event Stream encoded messages
|
||||||
|
func NewStreamSigner(region, service string, seedSignature []byte, credentials *credentials.Credentials) *StreamSigner {
|
||||||
|
return &StreamSigner{
|
||||||
|
region: region,
|
||||||
|
service: service,
|
||||||
|
credentials: credentials,
|
||||||
|
prevSig: seedSignature,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSignature takes an event stream encoded headers and payload and returns a signature
|
||||||
|
func (s *StreamSigner) GetSignature(headers, payload []byte, date time.Time) ([]byte, error) {
|
||||||
|
credValue, err := s.credentials.Get()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sigKey := deriveSigningKey(s.region, s.service, credValue.SecretAccessKey, date)
|
||||||
|
|
||||||
|
keyPath := buildSigningScope(s.region, s.service, date)
|
||||||
|
|
||||||
|
stringToSign := buildEventStreamStringToSign(headers, payload, s.prevSig, keyPath, date)
|
||||||
|
|
||||||
|
signature := hmacSHA256(sigKey, []byte(stringToSign))
|
||||||
|
s.prevSig = signature
|
||||||
|
|
||||||
|
return signature, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildEventStreamStringToSign(headers, payload, prevSig []byte, scope string, date time.Time) string {
|
||||||
|
return strings.Join([]string{
|
||||||
|
"AWS4-HMAC-SHA256-PAYLOAD",
|
||||||
|
formatTime(date),
|
||||||
|
scope,
|
||||||
|
hex.EncodeToString(prevSig),
|
||||||
|
hex.EncodeToString(hashSHA256(headers)),
|
||||||
|
hex.EncodeToString(hashSHA256(payload)),
|
||||||
|
}, "\n")
|
||||||
|
}
|
|
@ -76,9 +76,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
authorizationHeader = "Authorization"
|
||||||
|
authHeaderSignatureElem = "Signature="
|
||||||
|
signatureQueryKey = "X-Amz-Signature"
|
||||||
|
|
||||||
authHeaderPrefix = "AWS4-HMAC-SHA256"
|
authHeaderPrefix = "AWS4-HMAC-SHA256"
|
||||||
timeFormat = "20060102T150405Z"
|
timeFormat = "20060102T150405Z"
|
||||||
shortTimeFormat = "20060102"
|
shortTimeFormat = "20060102"
|
||||||
|
awsV4Request = "aws4_request"
|
||||||
|
|
||||||
// emptyStringSHA256 is a SHA256 of an empty string
|
// emptyStringSHA256 is a SHA256 of an empty string
|
||||||
emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
|
emptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
|
||||||
|
@ -87,7 +92,7 @@ const (
|
||||||
var ignoredHeaders = rules{
|
var ignoredHeaders = rules{
|
||||||
blacklist{
|
blacklist{
|
||||||
mapRule{
|
mapRule{
|
||||||
"Authorization": struct{}{},
|
authorizationHeader: struct{}{},
|
||||||
"User-Agent": struct{}{},
|
"User-Agent": struct{}{},
|
||||||
"X-Amzn-Trace-Id": struct{}{},
|
"X-Amzn-Trace-Id": struct{}{},
|
||||||
},
|
},
|
||||||
|
@ -231,8 +236,6 @@ type signingCtx struct {
|
||||||
|
|
||||||
credValues credentials.Value
|
credValues credentials.Value
|
||||||
isPresign bool
|
isPresign bool
|
||||||
formattedTime string
|
|
||||||
formattedShortTime string
|
|
||||||
unsignedPayload bool
|
unsignedPayload bool
|
||||||
|
|
||||||
bodyDigest string
|
bodyDigest string
|
||||||
|
@ -337,7 +340,7 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
ctx.credValues, err = v4.Credentials.Get()
|
ctx.credValues, err = v4.Credentials.GetWithContext(requestContext(r))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.Header{}, err
|
return http.Header{}, err
|
||||||
}
|
}
|
||||||
|
@ -532,39 +535,56 @@ func (ctx *signingCtx) build(disableHeaderHoisting bool) error {
|
||||||
ctx.buildSignature() // depends on string to sign
|
ctx.buildSignature() // depends on string to sign
|
||||||
|
|
||||||
if ctx.isPresign {
|
if ctx.isPresign {
|
||||||
ctx.Request.URL.RawQuery += "&X-Amz-Signature=" + ctx.signature
|
ctx.Request.URL.RawQuery += "&" + signatureQueryKey + "=" + ctx.signature
|
||||||
} else {
|
} else {
|
||||||
parts := []string{
|
parts := []string{
|
||||||
authHeaderPrefix + " Credential=" + ctx.credValues.AccessKeyID + "/" + ctx.credentialString,
|
authHeaderPrefix + " Credential=" + ctx.credValues.AccessKeyID + "/" + ctx.credentialString,
|
||||||
"SignedHeaders=" + ctx.signedHeaders,
|
"SignedHeaders=" + ctx.signedHeaders,
|
||||||
"Signature=" + ctx.signature,
|
authHeaderSignatureElem + ctx.signature,
|
||||||
}
|
}
|
||||||
ctx.Request.Header.Set("Authorization", strings.Join(parts, ", "))
|
ctx.Request.Header.Set(authorizationHeader, strings.Join(parts, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *signingCtx) buildTime() {
|
// GetSignedRequestSignature attempts to extract the signature of the request.
|
||||||
ctx.formattedTime = ctx.Time.UTC().Format(timeFormat)
|
// Returning an error if the request is unsigned, or unable to extract the
|
||||||
ctx.formattedShortTime = ctx.Time.UTC().Format(shortTimeFormat)
|
// signature.
|
||||||
|
func GetSignedRequestSignature(r *http.Request) ([]byte, error) {
|
||||||
|
|
||||||
|
if auth := r.Header.Get(authorizationHeader); len(auth) != 0 {
|
||||||
|
ps := strings.Split(auth, ", ")
|
||||||
|
for _, p := range ps {
|
||||||
|
if idx := strings.Index(p, authHeaderSignatureElem); idx >= 0 {
|
||||||
|
sig := p[len(authHeaderSignatureElem):]
|
||||||
|
if len(sig) == 0 {
|
||||||
|
return nil, fmt.Errorf("invalid request signature authorization header")
|
||||||
|
}
|
||||||
|
return hex.DecodeString(sig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sig := r.URL.Query().Get("X-Amz-Signature"); len(sig) != 0 {
|
||||||
|
return hex.DecodeString(sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("request not signed")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *signingCtx) buildTime() {
|
||||||
if ctx.isPresign {
|
if ctx.isPresign {
|
||||||
duration := int64(ctx.ExpireTime / time.Second)
|
duration := int64(ctx.ExpireTime / time.Second)
|
||||||
ctx.Query.Set("X-Amz-Date", ctx.formattedTime)
|
ctx.Query.Set("X-Amz-Date", formatTime(ctx.Time))
|
||||||
ctx.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10))
|
ctx.Query.Set("X-Amz-Expires", strconv.FormatInt(duration, 10))
|
||||||
} else {
|
} else {
|
||||||
ctx.Request.Header.Set("X-Amz-Date", ctx.formattedTime)
|
ctx.Request.Header.Set("X-Amz-Date", formatTime(ctx.Time))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *signingCtx) buildCredentialString() {
|
func (ctx *signingCtx) buildCredentialString() {
|
||||||
ctx.credentialString = strings.Join([]string{
|
ctx.credentialString = buildSigningScope(ctx.Region, ctx.ServiceName, ctx.Time)
|
||||||
ctx.formattedShortTime,
|
|
||||||
ctx.Region,
|
|
||||||
ctx.ServiceName,
|
|
||||||
"aws4_request",
|
|
||||||
}, "/")
|
|
||||||
|
|
||||||
if ctx.isPresign {
|
if ctx.isPresign {
|
||||||
ctx.Query.Set("X-Amz-Credential", ctx.credValues.AccessKeyID+"/"+ctx.credentialString)
|
ctx.Query.Set("X-Amz-Credential", ctx.credValues.AccessKeyID+"/"+ctx.credentialString)
|
||||||
|
@ -588,8 +608,7 @@ func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) {
|
||||||
var headers []string
|
var headers []string
|
||||||
headers = append(headers, "host")
|
headers = append(headers, "host")
|
||||||
for k, v := range header {
|
for k, v := range header {
|
||||||
canonicalKey := http.CanonicalHeaderKey(k)
|
if !r.IsValid(k) {
|
||||||
if !r.IsValid(canonicalKey) {
|
|
||||||
continue // ignored header
|
continue // ignored header
|
||||||
}
|
}
|
||||||
if ctx.SignedHeaderVals == nil {
|
if ctx.SignedHeaderVals == nil {
|
||||||
|
@ -653,19 +672,15 @@ func (ctx *signingCtx) buildCanonicalString() {
|
||||||
func (ctx *signingCtx) buildStringToSign() {
|
func (ctx *signingCtx) buildStringToSign() {
|
||||||
ctx.stringToSign = strings.Join([]string{
|
ctx.stringToSign = strings.Join([]string{
|
||||||
authHeaderPrefix,
|
authHeaderPrefix,
|
||||||
ctx.formattedTime,
|
formatTime(ctx.Time),
|
||||||
ctx.credentialString,
|
ctx.credentialString,
|
||||||
hex.EncodeToString(makeSha256([]byte(ctx.canonicalString))),
|
hex.EncodeToString(hashSHA256([]byte(ctx.canonicalString))),
|
||||||
}, "\n")
|
}, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *signingCtx) buildSignature() {
|
func (ctx *signingCtx) buildSignature() {
|
||||||
secret := ctx.credValues.SecretAccessKey
|
creds := deriveSigningKey(ctx.Region, ctx.ServiceName, ctx.credValues.SecretAccessKey, ctx.Time)
|
||||||
date := makeHmac([]byte("AWS4"+secret), []byte(ctx.formattedShortTime))
|
signature := hmacSHA256(creds, []byte(ctx.stringToSign))
|
||||||
region := makeHmac(date, []byte(ctx.Region))
|
|
||||||
service := makeHmac(region, []byte(ctx.ServiceName))
|
|
||||||
credentials := makeHmac(service, []byte("aws4_request"))
|
|
||||||
signature := makeHmac(credentials, []byte(ctx.stringToSign))
|
|
||||||
ctx.signature = hex.EncodeToString(signature)
|
ctx.signature = hex.EncodeToString(signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,13 +741,13 @@ func (ctx *signingCtx) removePresign() {
|
||||||
ctx.Query.Del("X-Amz-SignedHeaders")
|
ctx.Query.Del("X-Amz-SignedHeaders")
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHmac(key []byte, data []byte) []byte {
|
func hmacSHA256(key []byte, data []byte) []byte {
|
||||||
hash := hmac.New(sha256.New, key)
|
hash := hmac.New(sha256.New, key)
|
||||||
hash.Write(data)
|
hash.Write(data)
|
||||||
return hash.Sum(nil)
|
return hash.Sum(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeSha256(data []byte) []byte {
|
func hashSHA256(data []byte) []byte {
|
||||||
hash := sha256.New()
|
hash := sha256.New()
|
||||||
hash.Write(data)
|
hash.Write(data)
|
||||||
return hash.Sum(nil)
|
return hash.Sum(nil)
|
||||||
|
@ -804,3 +819,28 @@ func stripExcessSpaces(vals []string) {
|
||||||
vals[i] = string(buf[:m])
|
vals[i] = string(buf[:m])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildSigningScope(region, service string, dt time.Time) string {
|
||||||
|
return strings.Join([]string{
|
||||||
|
formatShortTime(dt),
|
||||||
|
region,
|
||||||
|
service,
|
||||||
|
awsV4Request,
|
||||||
|
}, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
func deriveSigningKey(region, service, secretKey string, dt time.Time) []byte {
|
||||||
|
kDate := hmacSHA256([]byte("AWS4"+secretKey), []byte(formatShortTime(dt)))
|
||||||
|
kRegion := hmacSHA256(kDate, []byte(region))
|
||||||
|
kService := hmacSHA256(kRegion, []byte(service))
|
||||||
|
signingKey := hmacSHA256(kService, []byte(awsV4Request))
|
||||||
|
return signingKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatShortTime(dt time.Time) string {
|
||||||
|
return dt.UTC().Format(shortTimeFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatTime(dt time.Time) string {
|
||||||
|
return dt.UTC().Format(timeFormat)
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package aws
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/internal/sdkio"
|
"github.com/aws/aws-sdk-go/internal/sdkio"
|
||||||
|
@ -205,3 +206,59 @@ func (b *WriteAtBuffer) Bytes() []byte {
|
||||||
defer b.m.Unlock()
|
defer b.m.Unlock()
|
||||||
return b.buf
|
return b.buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiCloser is a utility to close multiple io.Closers within a single
|
||||||
|
// statement.
|
||||||
|
type MultiCloser []io.Closer
|
||||||
|
|
||||||
|
// Close closes all of the io.Closers making up the MultiClosers. Any
|
||||||
|
// errors that occur while closing will be returned in the order they
|
||||||
|
// occur.
|
||||||
|
func (m MultiCloser) Close() error {
|
||||||
|
var errs errors
|
||||||
|
for _, c := range m {
|
||||||
|
err := c.Close()
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errs) != 0 {
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type errors []error
|
||||||
|
|
||||||
|
func (es errors) Error() string {
|
||||||
|
var parts []string
|
||||||
|
for _, e := range es {
|
||||||
|
parts = append(parts, e.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(parts, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopySeekableBody copies the seekable body to an io.Writer
|
||||||
|
func CopySeekableBody(dst io.Writer, src io.ReadSeeker) (int64, error) {
|
||||||
|
curPos, err := src.Seek(0, sdkio.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy errors may be assumed to be from the body.
|
||||||
|
n, err := io.Copy(dst, src)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// seek back to the first position after reading to reset
|
||||||
|
// the body for transmission.
|
||||||
|
_, err = src.Seek(curPos, sdkio.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
|
@ -5,4 +5,4 @@ package aws
|
||||||
const SDKName = "aws-sdk-go"
|
const SDKName = "aws-sdk-go"
|
||||||
|
|
||||||
// SDKVersion is the version of this SDK
|
// SDKVersion is the version of this SDK
|
||||||
const SDKVersion = "1.25.8"
|
const SDKVersion = "1.34.19"
|
||||||
|
|
40
vendor/github.com/aws/aws-sdk-go/internal/context/background_go1.5.go
generated
vendored
Normal file
40
vendor/github.com/aws/aws-sdk-go/internal/context/background_go1.5.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to
|
||||||
|
// provide a 1.6 and 1.5 safe version of context that is compatible with Go
|
||||||
|
// 1.7's Context.
|
||||||
|
//
|
||||||
|
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||||
|
// struct{}, since vars of this type must have distinct addresses.
|
||||||
|
type emptyCtx int
|
||||||
|
|
||||||
|
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Done() <-chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Value(key interface{}) interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *emptyCtx) String() string {
|
||||||
|
switch e {
|
||||||
|
case BackgroundCtx:
|
||||||
|
return "aws.BackgroundContext"
|
||||||
|
}
|
||||||
|
return "unknown empty Context"
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackgroundCtx is the common base context.
|
||||||
|
var BackgroundCtx = new(emptyCtx)
|
|
@ -0,0 +1,11 @@
|
||||||
|
package strings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HasPrefixFold tests whether the string s begins with prefix, interpreted as UTF-8 strings,
|
||||||
|
// under Unicode case-folding.
|
||||||
|
func HasPrefixFold(s, prefix string) bool {
|
||||||
|
return len(s) >= len(prefix) && strings.EqualFold(s[0:len(prefix)], prefix)
|
||||||
|
}
|
27
vendor/github.com/aws/aws-sdk-go/internal/sync/singleflight/LICENSE
generated
vendored
Normal file
27
vendor/github.com/aws/aws-sdk-go/internal/sync/singleflight/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
120
vendor/github.com/aws/aws-sdk-go/internal/sync/singleflight/singleflight.go
generated
vendored
Normal file
120
vendor/github.com/aws/aws-sdk-go/internal/sync/singleflight/singleflight.go
generated
vendored
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package singleflight provides a duplicate function call suppression
|
||||||
|
// mechanism.
|
||||||
|
package singleflight
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
// call is an in-flight or completed singleflight.Do call
|
||||||
|
type call struct {
|
||||||
|
wg sync.WaitGroup
|
||||||
|
|
||||||
|
// These fields are written once before the WaitGroup is done
|
||||||
|
// and are only read after the WaitGroup is done.
|
||||||
|
val interface{}
|
||||||
|
err error
|
||||||
|
|
||||||
|
// forgotten indicates whether Forget was called with this call's key
|
||||||
|
// while the call was still in flight.
|
||||||
|
forgotten bool
|
||||||
|
|
||||||
|
// These fields are read and written with the singleflight
|
||||||
|
// mutex held before the WaitGroup is done, and are read but
|
||||||
|
// not written after the WaitGroup is done.
|
||||||
|
dups int
|
||||||
|
chans []chan<- Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group represents a class of work and forms a namespace in
|
||||||
|
// which units of work can be executed with duplicate suppression.
|
||||||
|
type Group struct {
|
||||||
|
mu sync.Mutex // protects m
|
||||||
|
m map[string]*call // lazily initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result holds the results of Do, so they can be passed
|
||||||
|
// on a channel.
|
||||||
|
type Result struct {
|
||||||
|
Val interface{}
|
||||||
|
Err error
|
||||||
|
Shared bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do executes and returns the results of the given function, making
|
||||||
|
// sure that only one execution is in-flight for a given key at a
|
||||||
|
// time. If a duplicate comes in, the duplicate caller waits for the
|
||||||
|
// original to complete and receives the same results.
|
||||||
|
// The return value shared indicates whether v was given to multiple callers.
|
||||||
|
func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
|
||||||
|
g.mu.Lock()
|
||||||
|
if g.m == nil {
|
||||||
|
g.m = make(map[string]*call)
|
||||||
|
}
|
||||||
|
if c, ok := g.m[key]; ok {
|
||||||
|
c.dups++
|
||||||
|
g.mu.Unlock()
|
||||||
|
c.wg.Wait()
|
||||||
|
return c.val, c.err, true
|
||||||
|
}
|
||||||
|
c := new(call)
|
||||||
|
c.wg.Add(1)
|
||||||
|
g.m[key] = c
|
||||||
|
g.mu.Unlock()
|
||||||
|
|
||||||
|
g.doCall(c, key, fn)
|
||||||
|
return c.val, c.err, c.dups > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoChan is like Do but returns a channel that will receive the
|
||||||
|
// results when they are ready.
|
||||||
|
func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {
|
||||||
|
ch := make(chan Result, 1)
|
||||||
|
g.mu.Lock()
|
||||||
|
if g.m == nil {
|
||||||
|
g.m = make(map[string]*call)
|
||||||
|
}
|
||||||
|
if c, ok := g.m[key]; ok {
|
||||||
|
c.dups++
|
||||||
|
c.chans = append(c.chans, ch)
|
||||||
|
g.mu.Unlock()
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
c := &call{chans: []chan<- Result{ch}}
|
||||||
|
c.wg.Add(1)
|
||||||
|
g.m[key] = c
|
||||||
|
g.mu.Unlock()
|
||||||
|
|
||||||
|
go g.doCall(c, key, fn)
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// doCall handles the single call for a key.
|
||||||
|
func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
|
||||||
|
c.val, c.err = fn()
|
||||||
|
c.wg.Done()
|
||||||
|
|
||||||
|
g.mu.Lock()
|
||||||
|
if !c.forgotten {
|
||||||
|
delete(g.m, key)
|
||||||
|
}
|
||||||
|
for _, ch := range c.chans {
|
||||||
|
ch <- Result{c.val, c.err, c.dups > 0}
|
||||||
|
}
|
||||||
|
g.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forget tells the singleflight to forget about a key. Future calls
|
||||||
|
// to Do for this key will call the function rather than waiting for
|
||||||
|
// an earlier call to complete.
|
||||||
|
func (g *Group) Forget(key string) {
|
||||||
|
g.mu.Lock()
|
||||||
|
if c, ok := g.m[key]; ok {
|
||||||
|
c.forgotten = true
|
||||||
|
}
|
||||||
|
delete(g.m, key)
|
||||||
|
g.mu.Unlock()
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package checksum
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
const contentMD5Header = "Content-Md5"
|
||||||
|
|
||||||
|
// AddBodyContentMD5Handler computes and sets the HTTP Content-MD5 header for requests that
|
||||||
|
// require it.
|
||||||
|
func AddBodyContentMD5Handler(r *request.Request) {
|
||||||
|
// if Content-MD5 header is already present, return
|
||||||
|
if v := r.HTTPRequest.Header.Get(contentMD5Header); len(v) != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if S3DisableContentMD5Validation flag is set, return
|
||||||
|
if aws.BoolValue(r.Config.S3DisableContentMD5Validation) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if request is presigned, return
|
||||||
|
if r.IsPresigned() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if body is not seekable, return
|
||||||
|
if !aws.IsReaderSeekable(r.Body) {
|
||||||
|
if r.Config.Logger != nil {
|
||||||
|
r.Config.Logger.Log(fmt.Sprintf(
|
||||||
|
"Unable to compute Content-MD5 for unseekable body, S3.%s",
|
||||||
|
r.Operation.Name))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h := md5.New()
|
||||||
|
|
||||||
|
if _, err := aws.CopySeekableBody(h, r.Body); err != nil {
|
||||||
|
r.Error = awserr.New("ContentMD5", "failed to compute body MD5", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode the md5 checksum in base64 and set the request header.
|
||||||
|
v := base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
r.HTTPRequest.Header.Set(contentMD5Header, v)
|
||||||
|
}
|
|
@ -101,7 +101,7 @@ func (hs *decodedHeaders) UnmarshalJSON(b []byte) error {
|
||||||
}
|
}
|
||||||
headers.Set(h.Name, value)
|
headers.Set(h.Name, value)
|
||||||
}
|
}
|
||||||
(*hs) = decodedHeaders(headers)
|
*hs = decodedHeaders(headers)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,24 @@ type Decoder struct {
|
||||||
|
|
||||||
// NewDecoder initializes and returns a Decoder for decoding event
|
// NewDecoder initializes and returns a Decoder for decoding event
|
||||||
// stream messages from the reader provided.
|
// stream messages from the reader provided.
|
||||||
func NewDecoder(r io.Reader) *Decoder {
|
func NewDecoder(r io.Reader, opts ...func(*Decoder)) *Decoder {
|
||||||
return &Decoder{
|
d := &Decoder{
|
||||||
r: r,
|
r: r,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeWithLogger adds a logger to be used by the decoder when decoding
|
||||||
|
// stream events.
|
||||||
|
func DecodeWithLogger(logger aws.Logger) func(*Decoder) {
|
||||||
|
return func(d *Decoder) {
|
||||||
|
d.logger = logger
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode attempts to decode a single message from the event stream reader.
|
// Decode attempts to decode a single message from the event stream reader.
|
||||||
|
@ -40,6 +54,15 @@ func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m, err = Decode(reader, payloadBuf)
|
||||||
|
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode attempts to decode a single message from the event stream reader.
|
||||||
|
// Will return the event stream message, or error if Decode fails to read
|
||||||
|
// the message from the reader.
|
||||||
|
func Decode(reader io.Reader, payloadBuf []byte) (m Message, err error) {
|
||||||
crc := crc32.New(crc32IEEETable)
|
crc := crc32.New(crc32IEEETable)
|
||||||
hashReader := io.TeeReader(reader, crc)
|
hashReader := io.TeeReader(reader, crc)
|
||||||
|
|
||||||
|
@ -72,12 +95,6 @@ func (d *Decoder) Decode(payloadBuf []byte) (m Message, err error) {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseLogger specifies the Logger that that the decoder should use to log the
|
|
||||||
// message decode to.
|
|
||||||
func (d *Decoder) UseLogger(logger aws.Logger) {
|
|
||||||
d.logger = logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func logMessageDecode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
|
func logMessageDecode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, decodeErr error) {
|
||||||
w := bytes.NewBuffer(nil)
|
w := bytes.NewBuffer(nil)
|
||||||
defer func() { logger.Log(w.String()) }()
|
defer func() { logger.Log(w.String()) }()
|
||||||
|
|
|
@ -3,61 +3,107 @@ package eventstream
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Encoder provides EventStream message encoding.
|
// Encoder provides EventStream message encoding.
|
||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
w io.Writer
|
w io.Writer
|
||||||
|
logger aws.Logger
|
||||||
|
|
||||||
headersBuf *bytes.Buffer
|
headersBuf *bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEncoder initializes and returns an Encoder to encode Event Stream
|
// NewEncoder initializes and returns an Encoder to encode Event Stream
|
||||||
// messages to an io.Writer.
|
// messages to an io.Writer.
|
||||||
func NewEncoder(w io.Writer) *Encoder {
|
func NewEncoder(w io.Writer, opts ...func(*Encoder)) *Encoder {
|
||||||
return &Encoder{
|
e := &Encoder{
|
||||||
w: w,
|
w: w,
|
||||||
headersBuf: bytes.NewBuffer(nil),
|
headersBuf: bytes.NewBuffer(nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeWithLogger adds a logger to be used by the encode when decoding
|
||||||
|
// stream events.
|
||||||
|
func EncodeWithLogger(logger aws.Logger) func(*Encoder) {
|
||||||
|
return func(d *Encoder) {
|
||||||
|
d.logger = logger
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode encodes a single EventStream message to the io.Writer the Encoder
|
// Encode encodes a single EventStream message to the io.Writer the Encoder
|
||||||
// was created with. An error is returned if writing the message fails.
|
// was created with. An error is returned if writing the message fails.
|
||||||
func (e *Encoder) Encode(msg Message) error {
|
func (e *Encoder) Encode(msg Message) (err error) {
|
||||||
e.headersBuf.Reset()
|
e.headersBuf.Reset()
|
||||||
|
|
||||||
err := encodeHeaders(e.headersBuf, msg.Headers)
|
writer := e.w
|
||||||
if err != nil {
|
if e.logger != nil {
|
||||||
|
encodeMsgBuf := bytes.NewBuffer(nil)
|
||||||
|
writer = io.MultiWriter(writer, encodeMsgBuf)
|
||||||
|
defer func() {
|
||||||
|
logMessageEncode(e.logger, encodeMsgBuf, msg, err)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = EncodeHeaders(e.headersBuf, msg.Headers); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
crc := crc32.New(crc32IEEETable)
|
crc := crc32.New(crc32IEEETable)
|
||||||
hashWriter := io.MultiWriter(e.w, crc)
|
hashWriter := io.MultiWriter(writer, crc)
|
||||||
|
|
||||||
headersLen := uint32(e.headersBuf.Len())
|
headersLen := uint32(e.headersBuf.Len())
|
||||||
payloadLen := uint32(len(msg.Payload))
|
payloadLen := uint32(len(msg.Payload))
|
||||||
|
|
||||||
if err := encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil {
|
if err = encodePrelude(hashWriter, crc, headersLen, payloadLen); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if headersLen > 0 {
|
if headersLen > 0 {
|
||||||
if _, err := io.Copy(hashWriter, e.headersBuf); err != nil {
|
if _, err = io.Copy(hashWriter, e.headersBuf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if payloadLen > 0 {
|
if payloadLen > 0 {
|
||||||
if _, err := hashWriter.Write(msg.Payload); err != nil {
|
if _, err = hashWriter.Write(msg.Payload); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msgCRC := crc.Sum32()
|
msgCRC := crc.Sum32()
|
||||||
return binary.Write(e.w, binary.BigEndian, msgCRC)
|
return binary.Write(writer, binary.BigEndian, msgCRC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func logMessageEncode(logger aws.Logger, msgBuf *bytes.Buffer, msg Message, encodeErr error) {
|
||||||
|
w := bytes.NewBuffer(nil)
|
||||||
|
defer func() { logger.Log(w.String()) }()
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "Message to encode:\n")
|
||||||
|
encoder := json.NewEncoder(w)
|
||||||
|
if err := encoder.Encode(msg); err != nil {
|
||||||
|
fmt.Fprintf(w, "Failed to get encoded message, %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if encodeErr != nil {
|
||||||
|
fmt.Fprintf(w, "Encode error: %v\n", encodeErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "Raw message:\n%s\n", hex.Dump(msgBuf.Bytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error {
|
func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32) error {
|
||||||
|
@ -86,7 +132,9 @@ func encodePrelude(w io.Writer, crc hash.Hash32, headersLen, payloadLen uint32)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeHeaders(w io.Writer, headers Headers) error {
|
// EncodeHeaders writes the header values to the writer encoded in the event
|
||||||
|
// stream format. Returns an error if a header fails to encode.
|
||||||
|
func EncodeHeaders(w io.Writer, headers Headers) error {
|
||||||
for _, h := range headers {
|
for _, h := range headers {
|
||||||
hn := headerName{
|
hn := headerName{
|
||||||
Len: uint8(len(h.Name)),
|
Len: uint8(len(h.Name)),
|
||||||
|
|
55
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go
generated
vendored
55
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/error.go
generated
vendored
|
@ -1,6 +1,9 @@
|
||||||
package eventstreamapi
|
package eventstreamapi
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
type messageError struct {
|
type messageError struct {
|
||||||
code string
|
code string
|
||||||
|
@ -22,3 +25,53 @@ func (e messageError) Error() string {
|
||||||
func (e messageError) OrigErr() error {
|
func (e messageError) OrigErr() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnceError wraps the behavior of recording an error
|
||||||
|
// once and signal on a channel when this has occurred.
|
||||||
|
// Signaling is done by closing of the channel.
|
||||||
|
//
|
||||||
|
// Type is safe for concurrent usage.
|
||||||
|
type OnceError struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
err error
|
||||||
|
ch chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOnceError return a new OnceError
|
||||||
|
func NewOnceError() *OnceError {
|
||||||
|
return &OnceError{
|
||||||
|
ch: make(chan struct{}, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err acquires a read-lock and returns an
|
||||||
|
// error if one has been set.
|
||||||
|
func (e *OnceError) Err() error {
|
||||||
|
e.mu.RLock()
|
||||||
|
err := e.err
|
||||||
|
e.mu.RUnlock()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetError acquires a write-lock and will set
|
||||||
|
// the underlying error value if one has not been set.
|
||||||
|
func (e *OnceError) SetError(err error) {
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.mu.Lock()
|
||||||
|
if e.err == nil {
|
||||||
|
e.err = err
|
||||||
|
close(e.ch)
|
||||||
|
}
|
||||||
|
e.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorSet returns a channel that will be used to signal
|
||||||
|
// that an error has been set. This channel will be closed
|
||||||
|
// when the error value has been set for OnceError.
|
||||||
|
func (e *OnceError) ErrorSet() <-chan struct{} {
|
||||||
|
return e.ch
|
||||||
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@ package eventstreamapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
|
||||||
"github.com/aws/aws-sdk-go/private/protocol"
|
"github.com/aws/aws-sdk-go/private/protocol"
|
||||||
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
|
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
|
||||||
)
|
)
|
||||||
|
@ -15,27 +13,8 @@ type Unmarshaler interface {
|
||||||
UnmarshalEvent(protocol.PayloadUnmarshaler, eventstream.Message) error
|
UnmarshalEvent(protocol.PayloadUnmarshaler, eventstream.Message) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventStream headers with specific meaning to async API functionality.
|
|
||||||
const (
|
|
||||||
MessageTypeHeader = `:message-type` // Identifies type of message.
|
|
||||||
EventMessageType = `event`
|
|
||||||
ErrorMessageType = `error`
|
|
||||||
ExceptionMessageType = `exception`
|
|
||||||
|
|
||||||
// Message Events
|
|
||||||
EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats".
|
|
||||||
|
|
||||||
// Message Error
|
|
||||||
ErrorCodeHeader = `:error-code`
|
|
||||||
ErrorMessageHeader = `:error-message`
|
|
||||||
|
|
||||||
// Message Exception
|
|
||||||
ExceptionTypeHeader = `:exception-type`
|
|
||||||
)
|
|
||||||
|
|
||||||
// EventReader provides reading from the EventStream of an reader.
|
// EventReader provides reading from the EventStream of an reader.
|
||||||
type EventReader struct {
|
type EventReader struct {
|
||||||
reader io.ReadCloser
|
|
||||||
decoder *eventstream.Decoder
|
decoder *eventstream.Decoder
|
||||||
|
|
||||||
unmarshalerForEventType func(string) (Unmarshaler, error)
|
unmarshalerForEventType func(string) (Unmarshaler, error)
|
||||||
|
@ -47,27 +26,18 @@ type EventReader struct {
|
||||||
// NewEventReader returns a EventReader built from the reader and unmarshaler
|
// NewEventReader returns a EventReader built from the reader and unmarshaler
|
||||||
// provided. Use ReadStream method to start reading from the EventStream.
|
// provided. Use ReadStream method to start reading from the EventStream.
|
||||||
func NewEventReader(
|
func NewEventReader(
|
||||||
reader io.ReadCloser,
|
decoder *eventstream.Decoder,
|
||||||
payloadUnmarshaler protocol.PayloadUnmarshaler,
|
payloadUnmarshaler protocol.PayloadUnmarshaler,
|
||||||
unmarshalerForEventType func(string) (Unmarshaler, error),
|
unmarshalerForEventType func(string) (Unmarshaler, error),
|
||||||
) *EventReader {
|
) *EventReader {
|
||||||
return &EventReader{
|
return &EventReader{
|
||||||
reader: reader,
|
decoder: decoder,
|
||||||
decoder: eventstream.NewDecoder(reader),
|
|
||||||
payloadUnmarshaler: payloadUnmarshaler,
|
payloadUnmarshaler: payloadUnmarshaler,
|
||||||
unmarshalerForEventType: unmarshalerForEventType,
|
unmarshalerForEventType: unmarshalerForEventType,
|
||||||
payloadBuf: make([]byte, 10*1024),
|
payloadBuf: make([]byte, 10*1024),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseLogger instructs the EventReader to use the logger and log level
|
|
||||||
// specified.
|
|
||||||
func (r *EventReader) UseLogger(logger aws.Logger, logLevel aws.LogLevelType) {
|
|
||||||
if logger != nil && logLevel.Matches(aws.LogDebugWithEventStreamBody) {
|
|
||||||
r.decoder.UseLogger(logger)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadEvent attempts to read a message from the EventStream and return the
|
// ReadEvent attempts to read a message from the EventStream and return the
|
||||||
// unmarshaled event value that the message is for.
|
// unmarshaled event value that the message is for.
|
||||||
//
|
//
|
||||||
|
@ -95,14 +65,26 @@ func (r *EventReader) ReadEvent() (event interface{}, err error) {
|
||||||
case EventMessageType:
|
case EventMessageType:
|
||||||
return r.unmarshalEventMessage(msg)
|
return r.unmarshalEventMessage(msg)
|
||||||
case ExceptionMessageType:
|
case ExceptionMessageType:
|
||||||
err = r.unmarshalEventException(msg)
|
return nil, r.unmarshalEventException(msg)
|
||||||
return nil, err
|
|
||||||
case ErrorMessageType:
|
case ErrorMessageType:
|
||||||
return nil, r.unmarshalErrorMessage(msg)
|
return nil, r.unmarshalErrorMessage(msg)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown eventstream message type, %v", typ)
|
return nil, &UnknownMessageTypeError{
|
||||||
|
Type: typ, Message: msg.Clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnknownMessageTypeError provides an error when a message is received from
|
||||||
|
// the stream, but the reader is unable to determine what kind of message it is.
|
||||||
|
type UnknownMessageTypeError struct {
|
||||||
|
Type string
|
||||||
|
Message eventstream.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnknownMessageTypeError) Error() string {
|
||||||
|
return "unknown eventstream message type, " + e.Type
|
||||||
|
}
|
||||||
|
|
||||||
func (r *EventReader) unmarshalEventMessage(
|
func (r *EventReader) unmarshalEventMessage(
|
||||||
msg eventstream.Message,
|
msg eventstream.Message,
|
||||||
|
@ -174,11 +156,6 @@ func (r *EventReader) unmarshalErrorMessage(msg eventstream.Message) (err error)
|
||||||
return msgErr
|
return msgErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the EventReader's EventStream reader.
|
|
||||||
func (r *EventReader) Close() error {
|
|
||||||
return r.reader.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHeaderString returns the value of the header as a string. If the header
|
// GetHeaderString returns the value of the header as a string. If the header
|
||||||
// is not set or the value is not a string an error will be returned.
|
// is not set or the value is not a string an error will be returned.
|
||||||
func GetHeaderString(msg eventstream.Message, headerName string) (string, error) {
|
func GetHeaderString(msg eventstream.Message, headerName string) (string, error) {
|
23
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/shared.go
generated
vendored
Normal file
23
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/shared.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package eventstreamapi
|
||||||
|
|
||||||
|
// EventStream headers with specific meaning to async API functionality.
|
||||||
|
const (
|
||||||
|
ChunkSignatureHeader = `:chunk-signature` // chunk signature for message
|
||||||
|
DateHeader = `:date` // Date header for signature
|
||||||
|
|
||||||
|
// Message header and values
|
||||||
|
MessageTypeHeader = `:message-type` // Identifies type of message.
|
||||||
|
EventMessageType = `event`
|
||||||
|
ErrorMessageType = `error`
|
||||||
|
ExceptionMessageType = `exception`
|
||||||
|
|
||||||
|
// Message Events
|
||||||
|
EventTypeHeader = `:event-type` // Identifies message event type e.g. "Stats".
|
||||||
|
|
||||||
|
// Message Error
|
||||||
|
ErrorCodeHeader = `:error-code`
|
||||||
|
ErrorMessageHeader = `:error-message`
|
||||||
|
|
||||||
|
// Message Exception
|
||||||
|
ExceptionTypeHeader = `:exception-type`
|
||||||
|
)
|
123
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/signer.go
generated
vendored
Normal file
123
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/signer.go
generated
vendored
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
package eventstreamapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
|
||||||
|
)
|
||||||
|
|
||||||
|
var timeNow = time.Now
|
||||||
|
|
||||||
|
// StreamSigner defines an interface for the implementation of signing of event stream payloads
|
||||||
|
type StreamSigner interface {
|
||||||
|
GetSignature(headers, payload []byte, date time.Time) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignEncoder envelopes event stream messages
|
||||||
|
// into an event stream message payload with included
|
||||||
|
// signature headers using the provided signer and encoder.
|
||||||
|
type SignEncoder struct {
|
||||||
|
signer StreamSigner
|
||||||
|
encoder Encoder
|
||||||
|
bufEncoder *BufferEncoder
|
||||||
|
|
||||||
|
closeErr error
|
||||||
|
closed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSignEncoder returns a new SignEncoder using the provided stream signer and
|
||||||
|
// event stream encoder.
|
||||||
|
func NewSignEncoder(signer StreamSigner, encoder Encoder) *SignEncoder {
|
||||||
|
// TODO: Need to pass down logging
|
||||||
|
|
||||||
|
return &SignEncoder{
|
||||||
|
signer: signer,
|
||||||
|
encoder: encoder,
|
||||||
|
bufEncoder: NewBufferEncoder(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close encodes a final event stream signing envelope with an empty event stream
|
||||||
|
// payload. This final end-frame is used to mark the conclusion of the stream.
|
||||||
|
func (s *SignEncoder) Close() error {
|
||||||
|
if s.closed {
|
||||||
|
return s.closeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.encode([]byte{}); err != nil {
|
||||||
|
if strings.Contains(err.Error(), "on closed pipe") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s.closeErr = err
|
||||||
|
s.closed = true
|
||||||
|
return s.closeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode takes the provided message and add envelopes the message
|
||||||
|
// with the required signature.
|
||||||
|
func (s *SignEncoder) Encode(msg eventstream.Message) error {
|
||||||
|
payload, err := s.bufEncoder.Encode(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.encode(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SignEncoder) encode(payload []byte) error {
|
||||||
|
date := timeNow()
|
||||||
|
|
||||||
|
var msg eventstream.Message
|
||||||
|
msg.Headers.Set(DateHeader, eventstream.TimestampValue(date))
|
||||||
|
msg.Payload = payload
|
||||||
|
|
||||||
|
var headers bytes.Buffer
|
||||||
|
if err := eventstream.EncodeHeaders(&headers, msg.Headers); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err := s.signer.GetSignature(headers.Bytes(), msg.Payload, date)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Headers.Set(ChunkSignatureHeader, eventstream.BytesValue(sig))
|
||||||
|
|
||||||
|
return s.encoder.Encode(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BufferEncoder is a utility that provides a buffered
|
||||||
|
// event stream encoder
|
||||||
|
type BufferEncoder struct {
|
||||||
|
encoder Encoder
|
||||||
|
buffer *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBufferEncoder returns a new BufferEncoder initialized
|
||||||
|
// with a 1024 byte buffer.
|
||||||
|
func NewBufferEncoder() *BufferEncoder {
|
||||||
|
buf := bytes.NewBuffer(make([]byte, 1024))
|
||||||
|
return &BufferEncoder{
|
||||||
|
encoder: eventstream.NewEncoder(buf),
|
||||||
|
buffer: buf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode returns the encoded message as a byte slice.
|
||||||
|
// The returned byte slice will be modified on the next encode call
|
||||||
|
// and should not be held onto.
|
||||||
|
func (e *BufferEncoder) Encode(msg eventstream.Message) ([]byte, error) {
|
||||||
|
e.buffer.Reset()
|
||||||
|
|
||||||
|
if err := e.encoder.Encode(msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.buffer.Bytes(), nil
|
||||||
|
}
|
129
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/stream_writer.go
generated
vendored
Normal file
129
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/stream_writer.go
generated
vendored
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
package eventstreamapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StreamWriter provides concurrent safe writing to an event stream.
|
||||||
|
type StreamWriter struct {
|
||||||
|
eventWriter *EventWriter
|
||||||
|
stream chan eventWriteAsyncReport
|
||||||
|
|
||||||
|
done chan struct{}
|
||||||
|
closeOnce sync.Once
|
||||||
|
err *OnceError
|
||||||
|
|
||||||
|
streamCloser io.Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStreamWriter returns a StreamWriter for the event writer, and stream
|
||||||
|
// closer provided.
|
||||||
|
func NewStreamWriter(eventWriter *EventWriter, streamCloser io.Closer) *StreamWriter {
|
||||||
|
w := &StreamWriter{
|
||||||
|
eventWriter: eventWriter,
|
||||||
|
streamCloser: streamCloser,
|
||||||
|
stream: make(chan eventWriteAsyncReport),
|
||||||
|
done: make(chan struct{}),
|
||||||
|
err: NewOnceError(),
|
||||||
|
}
|
||||||
|
go w.writeStream()
|
||||||
|
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close terminates the writers ability to write new events to the stream. Any
|
||||||
|
// future call to Send will fail with an error.
|
||||||
|
func (w *StreamWriter) Close() error {
|
||||||
|
w.closeOnce.Do(w.safeClose)
|
||||||
|
return w.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *StreamWriter) safeClose() {
|
||||||
|
close(w.done)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorSet returns a channel which will be closed
|
||||||
|
// if an error occurs.
|
||||||
|
func (w *StreamWriter) ErrorSet() <-chan struct{} {
|
||||||
|
return w.err.ErrorSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err returns any error that occurred while attempting to write an event to the
|
||||||
|
// stream.
|
||||||
|
func (w *StreamWriter) Err() error {
|
||||||
|
return w.err.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send writes a single event to the stream returning an error if the write
|
||||||
|
// failed.
|
||||||
|
//
|
||||||
|
// Send may be called concurrently. Events will be written to the stream
|
||||||
|
// safely.
|
||||||
|
func (w *StreamWriter) Send(ctx aws.Context, event Marshaler) error {
|
||||||
|
if err := w.Err(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resultCh := make(chan error)
|
||||||
|
wrapped := eventWriteAsyncReport{
|
||||||
|
Event: event,
|
||||||
|
Result: resultCh,
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case w.stream <- wrapped:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-w.done:
|
||||||
|
return fmt.Errorf("stream closed, unable to send event")
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err := <-resultCh:
|
||||||
|
return err
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
case <-w.done:
|
||||||
|
return fmt.Errorf("stream closed, unable to send event")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *StreamWriter) writeStream() {
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case wrapper := <-w.stream:
|
||||||
|
err := w.eventWriter.WriteEvent(wrapper.Event)
|
||||||
|
wrapper.ReportResult(w.done, err)
|
||||||
|
if err != nil {
|
||||||
|
w.err.SetError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-w.done:
|
||||||
|
if err := w.streamCloser.Close(); err != nil {
|
||||||
|
w.err.SetError(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type eventWriteAsyncReport struct {
|
||||||
|
Event Marshaler
|
||||||
|
Result chan<- error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e eventWriteAsyncReport) ReportResult(cancel <-chan struct{}, err error) bool {
|
||||||
|
select {
|
||||||
|
case e.Result <- err:
|
||||||
|
return true
|
||||||
|
case <-cancel:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
109
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/writer.go
generated
vendored
Normal file
109
vendor/github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi/writer.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
package eventstreamapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol/eventstream"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Marshaler provides a marshaling interface for event types to event stream
|
||||||
|
// messages.
|
||||||
|
type Marshaler interface {
|
||||||
|
MarshalEvent(protocol.PayloadMarshaler) (eventstream.Message, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoder is an stream encoder that will encode an event stream message for
|
||||||
|
// the transport.
|
||||||
|
type Encoder interface {
|
||||||
|
Encode(eventstream.Message) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventWriter provides a wrapper around the underlying event stream encoder
|
||||||
|
// for an io.WriteCloser.
|
||||||
|
type EventWriter struct {
|
||||||
|
encoder Encoder
|
||||||
|
payloadMarshaler protocol.PayloadMarshaler
|
||||||
|
eventTypeFor func(Marshaler) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventWriter returns a new event stream writer, that will write to the
|
||||||
|
// writer provided. Use the WriteEvent method to write an event to the stream.
|
||||||
|
func NewEventWriter(encoder Encoder, pm protocol.PayloadMarshaler, eventTypeFor func(Marshaler) (string, error),
|
||||||
|
) *EventWriter {
|
||||||
|
return &EventWriter{
|
||||||
|
encoder: encoder,
|
||||||
|
payloadMarshaler: pm,
|
||||||
|
eventTypeFor: eventTypeFor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteEvent writes an event to the stream. Returns an error if the event
|
||||||
|
// fails to marshal into a message, or writing to the underlying writer fails.
|
||||||
|
func (w *EventWriter) WriteEvent(event Marshaler) error {
|
||||||
|
msg, err := w.marshal(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.encoder.Encode(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *EventWriter) marshal(event Marshaler) (eventstream.Message, error) {
|
||||||
|
eventType, err := w.eventTypeFor(event)
|
||||||
|
if err != nil {
|
||||||
|
return eventstream.Message{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := event.MarshalEvent(w.payloadMarshaler)
|
||||||
|
if err != nil {
|
||||||
|
return eventstream.Message{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Headers.Set(EventTypeHeader, eventstream.StringValue(eventType))
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//type EventEncoder struct {
|
||||||
|
// encoder Encoder
|
||||||
|
// ppayloadMarshaler protocol.PayloadMarshaler
|
||||||
|
// eventTypeFor func(Marshaler) (string, error)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (e EventEncoder) Encode(event Marshaler) error {
|
||||||
|
// msg, err := e.marshal(event)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return w.encoder.Encode(msg)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (e EventEncoder) marshal(event Marshaler) (eventstream.Message, error) {
|
||||||
|
// eventType, err := w.eventTypeFor(event)
|
||||||
|
// if err != nil {
|
||||||
|
// return eventstream.Message{}, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// msg, err := event.MarshalEvent(w.payloadMarshaler)
|
||||||
|
// if err != nil {
|
||||||
|
// return eventstream.Message{}, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// msg.Headers.Set(EventTypeHeader, eventstream.StringValue(eventType))
|
||||||
|
// return msg, nil
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (w *EventWriter) marshal(event Marshaler) (eventstream.Message, error) {
|
||||||
|
// eventType, err := w.eventTypeFor(event)
|
||||||
|
// if err != nil {
|
||||||
|
// return eventstream.Message{}, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// msg, err := event.MarshalEvent(w.payloadMarshaler)
|
||||||
|
// if err != nil {
|
||||||
|
// return eventstream.Message{}, err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// msg.Headers.Set(EventTypeHeader, eventstream.StringValue(eventType))
|
||||||
|
// return msg, nil
|
||||||
|
//}
|
||||||
|
//
|
|
@ -52,6 +52,15 @@ func (hs *Headers) Del(name string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of the headers
|
||||||
|
func (hs Headers) Clone() Headers {
|
||||||
|
o := make(Headers, 0, len(hs))
|
||||||
|
for _, h := range hs {
|
||||||
|
o.Set(h.Name, h.Value)
|
||||||
|
}
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
func decodeHeaders(r io.Reader) (Headers, error) {
|
func decodeHeaders(r io.Reader) (Headers, error) {
|
||||||
hs := Headers{}
|
hs := Headers{}
|
||||||
|
|
||||||
|
|
|
@ -461,6 +461,11 @@ func (v *TimestampValue) decode(r io.Reader) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface
|
||||||
|
func (v TimestampValue) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(v.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
func timeFromEpochMilli(t int64) time.Time {
|
func timeFromEpochMilli(t int64) time.Time {
|
||||||
secs := t / 1e3
|
secs := t / 1e3
|
||||||
msec := t % 1e3
|
msec := t % 1e3
|
||||||
|
|
|
@ -27,7 +27,7 @@ func (m *Message) rawMessage() (rawMessage, error) {
|
||||||
|
|
||||||
if len(m.Headers) > 0 {
|
if len(m.Headers) > 0 {
|
||||||
var headers bytes.Buffer
|
var headers bytes.Buffer
|
||||||
if err := encodeHeaders(&headers, m.Headers); err != nil {
|
if err := EncodeHeaders(&headers, m.Headers); err != nil {
|
||||||
return rawMessage{}, err
|
return rawMessage{}, err
|
||||||
}
|
}
|
||||||
raw.Headers = headers.Bytes()
|
raw.Headers = headers.Bytes()
|
||||||
|
@ -57,6 +57,20 @@ func (m *Message) rawMessage() (rawMessage, error) {
|
||||||
return raw, nil
|
return raw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of the message.
|
||||||
|
func (m Message) Clone() Message {
|
||||||
|
var payload []byte
|
||||||
|
if m.Payload != nil {
|
||||||
|
payload = make([]byte, len(m.Payload))
|
||||||
|
copy(payload, m.Payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Message{
|
||||||
|
Headers: m.Headers.Clone(),
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type messagePrelude struct {
|
type messagePrelude struct {
|
||||||
Length uint32
|
Length uint32
|
||||||
HeadersLen uint32
|
HeadersLen uint32
|
||||||
|
|
|
@ -6,7 +6,9 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
@ -14,6 +16,8 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/private/protocol"
|
"github.com/aws/aws-sdk-go/private/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var millisecondsFloat = new(big.Float).SetInt64(1e3)
|
||||||
|
|
||||||
// UnmarshalJSONError unmarshal's the reader's JSON document into the passed in
|
// UnmarshalJSONError unmarshal's the reader's JSON document into the passed in
|
||||||
// type. The value to unmarshal the json document into must be a pointer to the
|
// type. The value to unmarshal the json document into must be a pointer to the
|
||||||
// type.
|
// type.
|
||||||
|
@ -38,17 +42,42 @@ func UnmarshalJSONError(v interface{}, stream io.Reader) error {
|
||||||
func UnmarshalJSON(v interface{}, stream io.Reader) error {
|
func UnmarshalJSON(v interface{}, stream io.Reader) error {
|
||||||
var out interface{}
|
var out interface{}
|
||||||
|
|
||||||
err := json.NewDecoder(stream).Decode(&out)
|
decoder := json.NewDecoder(stream)
|
||||||
|
decoder.UseNumber()
|
||||||
|
err := decoder.Decode(&out)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return unmarshalAny(reflect.ValueOf(v), out, "")
|
return unmarshaler{}.unmarshalAny(reflect.ValueOf(v), out, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
// UnmarshalJSONCaseInsensitive reads a stream and unmarshals the result into the
|
||||||
|
// object v. Ignores casing for structure members.
|
||||||
|
func UnmarshalJSONCaseInsensitive(v interface{}, stream io.Reader) error {
|
||||||
|
var out interface{}
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(stream)
|
||||||
|
decoder.UseNumber()
|
||||||
|
err := decoder.Decode(&out)
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return unmarshaler{
|
||||||
|
caseInsensitive: true,
|
||||||
|
}.unmarshalAny(reflect.ValueOf(v), out, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
type unmarshaler struct {
|
||||||
|
caseInsensitive bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u unmarshaler) unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
||||||
vtype := value.Type()
|
vtype := value.Type()
|
||||||
if vtype.Kind() == reflect.Ptr {
|
if vtype.Kind() == reflect.Ptr {
|
||||||
vtype = vtype.Elem() // check kind of actual element type
|
vtype = vtype.Elem() // check kind of actual element type
|
||||||
|
@ -80,17 +109,17 @@ func unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag)
|
||||||
if field, ok := vtype.FieldByName("_"); ok {
|
if field, ok := vtype.FieldByName("_"); ok {
|
||||||
tag = field.Tag
|
tag = field.Tag
|
||||||
}
|
}
|
||||||
return unmarshalStruct(value, data, tag)
|
return u.unmarshalStruct(value, data, tag)
|
||||||
case "list":
|
case "list":
|
||||||
return unmarshalList(value, data, tag)
|
return u.unmarshalList(value, data, tag)
|
||||||
case "map":
|
case "map":
|
||||||
return unmarshalMap(value, data, tag)
|
return u.unmarshalMap(value, data, tag)
|
||||||
default:
|
default:
|
||||||
return unmarshalScalar(value, data, tag)
|
return u.unmarshalScalar(value, data, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
func (u unmarshaler) unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -114,7 +143,7 @@ func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTa
|
||||||
// unwrap any payloads
|
// unwrap any payloads
|
||||||
if payload := tag.Get("payload"); payload != "" {
|
if payload := tag.Get("payload"); payload != "" {
|
||||||
field, _ := t.FieldByName(payload)
|
field, _ := t.FieldByName(payload)
|
||||||
return unmarshalAny(value.FieldByName(payload), data, field.Tag)
|
return u.unmarshalAny(value.FieldByName(payload), data, field.Tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
@ -128,9 +157,19 @@ func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTa
|
||||||
if locName := field.Tag.Get("locationName"); locName != "" {
|
if locName := field.Tag.Get("locationName"); locName != "" {
|
||||||
name = locName
|
name = locName
|
||||||
}
|
}
|
||||||
|
if u.caseInsensitive {
|
||||||
|
if _, ok := mapData[name]; !ok {
|
||||||
|
// Fallback to uncased name search if the exact name didn't match.
|
||||||
|
for kn, v := range mapData {
|
||||||
|
if strings.EqualFold(kn, name) {
|
||||||
|
mapData[name] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
member := value.FieldByIndex(field.Index)
|
member := value.FieldByIndex(field.Index)
|
||||||
err := unmarshalAny(member, mapData[name], field.Tag)
|
err := u.unmarshalAny(member, mapData[name], field.Tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -138,7 +177,7 @@ func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTa
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
func (u unmarshaler) unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -153,7 +192,7 @@ func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, c := range listData {
|
for i, c := range listData {
|
||||||
err := unmarshalAny(value.Index(i), c, "")
|
err := u.unmarshalAny(value.Index(i), c, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -162,7 +201,7 @@ func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
func (u unmarshaler) unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -179,14 +218,14 @@ func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag)
|
||||||
kvalue := reflect.ValueOf(k)
|
kvalue := reflect.ValueOf(k)
|
||||||
vvalue := reflect.New(value.Type().Elem()).Elem()
|
vvalue := reflect.New(value.Type().Elem()).Elem()
|
||||||
|
|
||||||
unmarshalAny(vvalue, v, "")
|
u.unmarshalAny(vvalue, v, "")
|
||||||
value.SetMapIndex(kvalue, vvalue)
|
value.SetMapIndex(kvalue, vvalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
func (u unmarshaler) unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error {
|
||||||
|
|
||||||
switch d := data.(type) {
|
switch d := data.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
|
@ -222,16 +261,31 @@ func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTa
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
|
return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
|
||||||
}
|
}
|
||||||
case float64:
|
case json.Number:
|
||||||
switch value.Interface().(type) {
|
switch value.Interface().(type) {
|
||||||
case *int64:
|
case *int64:
|
||||||
di := int64(d)
|
// Retain the old behavior where we would just truncate the float64
|
||||||
|
// calling d.Int64() here could cause an invalid syntax error due to the usage of strconv.ParseInt
|
||||||
|
f, err := d.Float64()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
di := int64(f)
|
||||||
value.Set(reflect.ValueOf(&di))
|
value.Set(reflect.ValueOf(&di))
|
||||||
case *float64:
|
case *float64:
|
||||||
value.Set(reflect.ValueOf(&d))
|
f, err := d.Float64()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.Set(reflect.ValueOf(&f))
|
||||||
case *time.Time:
|
case *time.Time:
|
||||||
// Time unmarshaled from a float64 can only be epoch seconds
|
float, ok := new(big.Float).SetString(d.String())
|
||||||
t := time.Unix(int64(d), 0).UTC()
|
if !ok {
|
||||||
|
return fmt.Errorf("unsupported float time representation: %v", d.String())
|
||||||
|
}
|
||||||
|
float = float.Mul(float, millisecondsFloat)
|
||||||
|
ms, _ := float.Int64()
|
||||||
|
t := time.Unix(0, ms*1e6).UTC()
|
||||||
value.Set(reflect.ValueOf(&t))
|
value.Set(reflect.ValueOf(&t))
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
|
return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
|
||||||
|
|
|
@ -64,7 +64,7 @@ func (h HandlerPayloadMarshal) MarshalPayload(w io.Writer, v interface{}) error
|
||||||
metadata.ClientInfo{},
|
metadata.ClientInfo{},
|
||||||
request.Handlers{},
|
request.Handlers{},
|
||||||
nil,
|
nil,
|
||||||
&request.Operation{HTTPMethod: "GET"},
|
&request.Operation{HTTPMethod: "PUT"},
|
||||||
v,
|
v,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RequireHTTPMinProtocol request handler is used to enforce that
|
||||||
|
// the target endpoint supports the given major and minor HTTP protocol version.
|
||||||
|
type RequireHTTPMinProtocol struct {
|
||||||
|
Major, Minor int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler will mark the request.Request with an error if the
|
||||||
|
// target endpoint did not connect with the required HTTP protocol
|
||||||
|
// major and minor version.
|
||||||
|
func (p RequireHTTPMinProtocol) Handler(r *request.Request) {
|
||||||
|
if r.Error != nil || r.HTTPResponse == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(r.HTTPResponse.Proto, "HTTP") {
|
||||||
|
r.Error = newMinHTTPProtoError(p.Major, p.Minor, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.HTTPResponse.ProtoMajor < p.Major || r.HTTPResponse.ProtoMinor < p.Minor {
|
||||||
|
r.Error = newMinHTTPProtoError(p.Major, p.Minor, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeMinimumHTTPProtocolError error code is returned when the target endpoint
|
||||||
|
// did not match the required HTTP major and minor protocol version.
|
||||||
|
const ErrCodeMinimumHTTPProtocolError = "MinimumHTTPProtocolError"
|
||||||
|
|
||||||
|
func newMinHTTPProtoError(major, minor int, r *request.Request) error {
|
||||||
|
return awserr.NewRequestFailure(
|
||||||
|
awserr.New("MinimumHTTPProtocolError",
|
||||||
|
fmt.Sprintf(
|
||||||
|
"operation requires minimum HTTP protocol of HTTP/%d.%d, but was %s",
|
||||||
|
major, minor, r.HTTPResponse.Proto,
|
||||||
|
),
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
r.HTTPResponse.StatusCode, r.RequestID,
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
// Package query provides serialization of AWS query requests, and responses.
|
// Package query provides serialization of AWS query requests, and responses.
|
||||||
package query
|
package query
|
||||||
|
|
||||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/query.json build_test.go
|
//go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/input/query.json build_test.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package query
|
package query
|
||||||
|
|
||||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/query.json unmarshal_test.go
|
//go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/output/query.json unmarshal_test.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
awsStrings "github.com/aws/aws-sdk-go/internal/strings"
|
||||||
"github.com/aws/aws-sdk-go/private/protocol"
|
"github.com/aws/aws-sdk-go/private/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,7 +29,9 @@ var UnmarshalMetaHandler = request.NamedHandler{Name: "awssdk.rest.UnmarshalMeta
|
||||||
func Unmarshal(r *request.Request) {
|
func Unmarshal(r *request.Request) {
|
||||||
if r.DataFilled() {
|
if r.DataFilled() {
|
||||||
v := reflect.Indirect(reflect.ValueOf(r.Data))
|
v := reflect.Indirect(reflect.ValueOf(r.Data))
|
||||||
unmarshalBody(r, v)
|
if err := unmarshalBody(r, v); err != nil {
|
||||||
|
r.Error = err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,12 +43,21 @@ func UnmarshalMeta(r *request.Request) {
|
||||||
r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id")
|
r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id")
|
||||||
}
|
}
|
||||||
if r.DataFilled() {
|
if r.DataFilled() {
|
||||||
v := reflect.Indirect(reflect.ValueOf(r.Data))
|
if err := UnmarshalResponse(r.HTTPResponse, r.Data, aws.BoolValue(r.Config.LowerCaseHeaderMaps)); err != nil {
|
||||||
unmarshalLocationElements(r, v)
|
r.Error = err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalBody(r *request.Request, v reflect.Value) {
|
// UnmarshalResponse attempts to unmarshal the REST response headers to
|
||||||
|
// the data type passed in. The type must be a pointer. An error is returned
|
||||||
|
// with any error unmarshaling the response into the target datatype.
|
||||||
|
func UnmarshalResponse(resp *http.Response, data interface{}, lowerCaseHeaderMaps bool) error {
|
||||||
|
v := reflect.Indirect(reflect.ValueOf(data))
|
||||||
|
return unmarshalLocationElements(resp, v, lowerCaseHeaderMaps)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalBody(r *request.Request, v reflect.Value) error {
|
||||||
if field, ok := v.Type().FieldByName("_"); ok {
|
if field, ok := v.Type().FieldByName("_"); ok {
|
||||||
if payloadName := field.Tag.Get("payload"); payloadName != "" {
|
if payloadName := field.Tag.Get("payload"); payloadName != "" {
|
||||||
pfield, _ := v.Type().FieldByName(payloadName)
|
pfield, _ := v.Type().FieldByName(payloadName)
|
||||||
|
@ -57,35 +69,38 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
|
||||||
defer r.HTTPResponse.Body.Close()
|
defer r.HTTPResponse.Body.Close()
|
||||||
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
return awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||||
} else {
|
|
||||||
payload.Set(reflect.ValueOf(b))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
payload.Set(reflect.ValueOf(b))
|
||||||
|
|
||||||
case *string:
|
case *string:
|
||||||
defer r.HTTPResponse.Body.Close()
|
defer r.HTTPResponse.Body.Close()
|
||||||
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
return awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||||
} else {
|
}
|
||||||
|
|
||||||
str := string(b)
|
str := string(b)
|
||||||
payload.Set(reflect.ValueOf(&str))
|
payload.Set(reflect.ValueOf(&str))
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
switch payload.Type().String() {
|
switch payload.Type().String() {
|
||||||
case "io.ReadCloser":
|
case "io.ReadCloser":
|
||||||
payload.Set(reflect.ValueOf(r.HTTPResponse.Body))
|
payload.Set(reflect.ValueOf(r.HTTPResponse.Body))
|
||||||
|
|
||||||
case "io.ReadSeeker":
|
case "io.ReadSeeker":
|
||||||
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Error = awserr.New(request.ErrCodeSerialization,
|
return awserr.New(request.ErrCodeSerialization,
|
||||||
"failed to read response body", err)
|
"failed to read response body", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
payload.Set(reflect.ValueOf(ioutil.NopCloser(bytes.NewReader(b))))
|
payload.Set(reflect.ValueOf(ioutil.NopCloser(bytes.NewReader(b))))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
|
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
|
||||||
defer r.HTTPResponse.Body.Close()
|
r.HTTPResponse.Body.Close()
|
||||||
r.Error = awserr.New(request.ErrCodeSerialization,
|
return awserr.New(request.ErrCodeSerialization,
|
||||||
"failed to decode REST response",
|
"failed to decode REST response",
|
||||||
fmt.Errorf("unknown payload type %s", payload.Type()))
|
fmt.Errorf("unknown payload type %s", payload.Type()))
|
||||||
}
|
}
|
||||||
|
@ -94,9 +109,11 @@ func unmarshalBody(r *request.Request, v reflect.Value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalLocationElements(r *request.Request, v reflect.Value) {
|
func unmarshalLocationElements(resp *http.Response, v reflect.Value, lowerCaseHeaderMaps bool) error {
|
||||||
for i := 0; i < v.NumField(); i++ {
|
for i := 0; i < v.NumField(); i++ {
|
||||||
m, field := v.Field(i), v.Type().Field(i)
|
m, field := v.Field(i), v.Type().Field(i)
|
||||||
if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) {
|
if n := field.Name; n[0:1] == strings.ToLower(n[0:1]) {
|
||||||
|
@ -111,26 +128,25 @@ func unmarshalLocationElements(r *request.Request, v reflect.Value) {
|
||||||
|
|
||||||
switch field.Tag.Get("location") {
|
switch field.Tag.Get("location") {
|
||||||
case "statusCode":
|
case "statusCode":
|
||||||
unmarshalStatusCode(m, r.HTTPResponse.StatusCode)
|
unmarshalStatusCode(m, resp.StatusCode)
|
||||||
|
|
||||||
case "header":
|
case "header":
|
||||||
err := unmarshalHeader(m, r.HTTPResponse.Header.Get(name), field.Tag)
|
err := unmarshalHeader(m, resp.Header.Get(name), field.Tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
return awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case "headers":
|
case "headers":
|
||||||
prefix := field.Tag.Get("locationName")
|
prefix := field.Tag.Get("locationName")
|
||||||
err := unmarshalHeaderMap(m, r.HTTPResponse.Header, prefix)
|
err := unmarshalHeaderMap(m, resp.Header, prefix, lowerCaseHeaderMaps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
awserr.New(request.ErrCodeSerialization, "failed to decode REST response", err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if r.Error != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalStatusCode(v reflect.Value, statusCode int) {
|
func unmarshalStatusCode(v reflect.Value, statusCode int) {
|
||||||
|
@ -145,7 +161,7 @@ func unmarshalStatusCode(v reflect.Value, statusCode int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) error {
|
func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string, normalize bool) error {
|
||||||
if len(headers) == 0 {
|
if len(headers) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -153,8 +169,12 @@ func unmarshalHeaderMap(r reflect.Value, headers http.Header, prefix string) err
|
||||||
case map[string]*string: // we only support string map value types
|
case map[string]*string: // we only support string map value types
|
||||||
out := map[string]*string{}
|
out := map[string]*string{}
|
||||||
for k, v := range headers {
|
for k, v := range headers {
|
||||||
|
if awsStrings.HasPrefixFold(k, prefix) {
|
||||||
|
if normalize == true {
|
||||||
|
k = strings.ToLower(k)
|
||||||
|
} else {
|
||||||
k = http.CanonicalHeaderKey(k)
|
k = http.CanonicalHeaderKey(k)
|
||||||
if strings.HasPrefix(strings.ToLower(k), strings.ToLower(prefix)) {
|
}
|
||||||
out[k[len(prefix):]] = &v[0]
|
out[k[len(prefix):]] = &v[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
// requests and responses.
|
// requests and responses.
|
||||||
package restxml
|
package restxml
|
||||||
|
|
||||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/input/rest-xml.json build_test.go
|
//go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/input/rest-xml.json build_test.go
|
||||||
//go:generate go run -tags codegen ../../../models/protocol_tests/generate.go ../../../models/protocol_tests/output/rest-xml.json unmarshal_test.go
|
//go:generate go run -tags codegen ../../../private/model/cli/gen-protocol-tests ../../../models/protocol_tests/output/rest-xml.json unmarshal_test.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
|
@ -27,8 +27,8 @@ const (
|
||||||
// RFC3339 a subset of the ISO8601 timestamp format. e.g 2014-04-29T18:30:38Z
|
// RFC3339 a subset of the ISO8601 timestamp format. e.g 2014-04-29T18:30:38Z
|
||||||
ISO8601TimeFormat = "2006-01-02T15:04:05.999999999Z"
|
ISO8601TimeFormat = "2006-01-02T15:04:05.999999999Z"
|
||||||
|
|
||||||
// This format is used for output time without seconds precision
|
// This format is used for output time with fractional second precision up to milliseconds
|
||||||
ISO8601OutputTimeFormat = "2006-01-02T15:04:05Z"
|
ISO8601OutputTimeFormat = "2006-01-02T15:04:05.999999999Z"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsKnownTimestampFormat returns if the timestamp format name
|
// IsKnownTimestampFormat returns if the timestamp format name
|
||||||
|
@ -48,7 +48,7 @@ func IsKnownTimestampFormat(name string) bool {
|
||||||
|
|
||||||
// FormatTime returns a string value of the time.
|
// FormatTime returns a string value of the time.
|
||||||
func FormatTime(name string, t time.Time) string {
|
func FormatTime(name string, t time.Time) string {
|
||||||
t = t.UTC()
|
t = t.UTC().Truncate(time.Millisecond)
|
||||||
|
|
||||||
switch name {
|
switch name {
|
||||||
case RFC822TimeFormatName:
|
case RFC822TimeFormatName:
|
||||||
|
@ -56,7 +56,8 @@ func FormatTime(name string, t time.Time) string {
|
||||||
case ISO8601TimeFormatName:
|
case ISO8601TimeFormatName:
|
||||||
return t.Format(ISO8601OutputTimeFormat)
|
return t.Format(ISO8601OutputTimeFormat)
|
||||||
case UnixTimeFormatName:
|
case UnixTimeFormatName:
|
||||||
return strconv.FormatInt(t.Unix(), 10)
|
ms := t.UnixNano() / int64(time.Millisecond)
|
||||||
|
return strconv.FormatFloat(float64(ms)/1e3, 'f', -1, 64)
|
||||||
default:
|
default:
|
||||||
panic("unknown timestamp format name, " + name)
|
panic("unknown timestamp format name, " + name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,3 +19,9 @@ func UnmarshalDiscardBody(r *request.Request) {
|
||||||
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
|
io.Copy(ioutil.Discard, r.HTTPResponse.Body)
|
||||||
r.HTTPResponse.Body.Close()
|
r.HTTPResponse.Body.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResponseMetadata provides the SDK response metadata attributes.
|
||||||
|
type ResponseMetadata struct {
|
||||||
|
StatusCode int
|
||||||
|
RequestID string
|
||||||
|
}
|
||||||
|
|
65
vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal_error.go
generated
vendored
Normal file
65
vendor/github.com/aws/aws-sdk-go/private/protocol/unmarshal_error.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnmarshalErrorHandler provides unmarshaling errors API response errors for
|
||||||
|
// both typed and untyped errors.
|
||||||
|
type UnmarshalErrorHandler struct {
|
||||||
|
unmarshaler ErrorUnmarshaler
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorUnmarshaler is an abstract interface for concrete implementations to
|
||||||
|
// unmarshal protocol specific response errors.
|
||||||
|
type ErrorUnmarshaler interface {
|
||||||
|
UnmarshalError(*http.Response, ResponseMetadata) (error, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnmarshalErrorHandler returns an UnmarshalErrorHandler
|
||||||
|
// initialized for the set of exception names to the error unmarshalers
|
||||||
|
func NewUnmarshalErrorHandler(unmarshaler ErrorUnmarshaler) *UnmarshalErrorHandler {
|
||||||
|
return &UnmarshalErrorHandler{
|
||||||
|
unmarshaler: unmarshaler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalErrorHandlerName is the name of the named handler.
|
||||||
|
const UnmarshalErrorHandlerName = "awssdk.protocol.UnmarshalError"
|
||||||
|
|
||||||
|
// NamedHandler returns a NamedHandler for the unmarshaler using the set of
|
||||||
|
// errors the unmarshaler was initialized for.
|
||||||
|
func (u *UnmarshalErrorHandler) NamedHandler() request.NamedHandler {
|
||||||
|
return request.NamedHandler{
|
||||||
|
Name: UnmarshalErrorHandlerName,
|
||||||
|
Fn: u.UnmarshalError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalError will attempt to unmarshal the API response's error message
|
||||||
|
// into either a generic SDK error type, or a typed error corresponding to the
|
||||||
|
// errors exception name.
|
||||||
|
func (u *UnmarshalErrorHandler) UnmarshalError(r *request.Request) {
|
||||||
|
defer r.HTTPResponse.Body.Close()
|
||||||
|
|
||||||
|
respMeta := ResponseMetadata{
|
||||||
|
StatusCode: r.HTTPResponse.StatusCode,
|
||||||
|
RequestID: r.RequestID,
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := u.unmarshaler.UnmarshalError(r.HTTPResponse, respMeta)
|
||||||
|
if err != nil {
|
||||||
|
r.Error = awserr.NewRequestFailure(
|
||||||
|
awserr.New(request.ErrCodeSerialization,
|
||||||
|
"failed to unmarshal response error", err),
|
||||||
|
respMeta.StatusCode,
|
||||||
|
respMeta.RequestID,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Error = v
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/private/protocol"
|
"github.com/aws/aws-sdk-go/private/protocol"
|
||||||
|
@ -60,6 +61,14 @@ func (b *xmlBuilder) buildValue(value reflect.Value, current *XMLNode, tag refle
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xml := tag.Get("xml")
|
||||||
|
if len(xml) != 0 {
|
||||||
|
name := strings.SplitAfterN(xml, ",", 2)[0]
|
||||||
|
if name == "-" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
t := tag.Get("type")
|
t := tag.Get("type")
|
||||||
if t == "" {
|
if t == "" {
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
|
|
|
@ -64,6 +64,14 @@ func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
|
||||||
// parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
|
// parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
|
||||||
// will be used to determine the type from r.
|
// will be used to determine the type from r.
|
||||||
func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
|
||||||
|
xml := tag.Get("xml")
|
||||||
|
if len(xml) != 0 {
|
||||||
|
name := strings.SplitAfterN(xml, ",", 2)[0]
|
||||||
|
if name == "-" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rtype := r.Type()
|
rtype := r.Type()
|
||||||
if rtype.Kind() == reflect.Ptr {
|
if rtype.Kind() == reflect.Ptr {
|
||||||
rtype = rtype.Elem() // check kind of actual element type
|
rtype = rtype.Elem() // check kind of actual element type
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
"github.com/aws/aws-sdk-go/internal/sdkio"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -25,30 +24,6 @@ const (
|
||||||
appendMD5TxEncoding = "append-md5"
|
appendMD5TxEncoding = "append-md5"
|
||||||
)
|
)
|
||||||
|
|
||||||
// contentMD5 computes and sets the HTTP Content-MD5 header for requests that
|
|
||||||
// require it.
|
|
||||||
func contentMD5(r *request.Request) {
|
|
||||||
h := md5.New()
|
|
||||||
|
|
||||||
if !aws.IsReaderSeekable(r.Body) {
|
|
||||||
if r.Config.Logger != nil {
|
|
||||||
r.Config.Logger.Log(fmt.Sprintf(
|
|
||||||
"Unable to compute Content-MD5 for unseekable body, S3.%s",
|
|
||||||
r.Operation.Name))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := copySeekableBody(h, r.Body); err != nil {
|
|
||||||
r.Error = awserr.New("ContentMD5", "failed to compute body MD5", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode the md5 checksum in base64 and set the request header.
|
|
||||||
v := base64.StdEncoding.EncodeToString(h.Sum(nil))
|
|
||||||
r.HTTPRequest.Header.Set(contentMD5Header, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// computeBodyHashes will add Content MD5 and Content Sha256 hashes to the
|
// computeBodyHashes will add Content MD5 and Content Sha256 hashes to the
|
||||||
// request. If the body is not seekable or S3DisableContentMD5Validation set
|
// request. If the body is not seekable or S3DisableContentMD5Validation set
|
||||||
// this handler will be ignored.
|
// this handler will be ignored.
|
||||||
|
@ -90,7 +65,7 @@ func computeBodyHashes(r *request.Request) {
|
||||||
dst = io.MultiWriter(hashers...)
|
dst = io.MultiWriter(hashers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := copySeekableBody(dst, r.Body); err != nil {
|
if _, err := aws.CopySeekableBody(dst, r.Body); err != nil {
|
||||||
r.Error = awserr.New("BodyHashError", "failed to compute body hashes", err)
|
r.Error = awserr.New("BodyHashError", "failed to compute body hashes", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -119,28 +94,6 @@ const (
|
||||||
sha256HexEncLen = sha256.Size * 2 // hex.EncodedLen
|
sha256HexEncLen = sha256.Size * 2 // hex.EncodedLen
|
||||||
)
|
)
|
||||||
|
|
||||||
func copySeekableBody(dst io.Writer, src io.ReadSeeker) (int64, error) {
|
|
||||||
curPos, err := src.Seek(0, sdkio.SeekCurrent)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// hash the body. seek back to the first position after reading to reset
|
|
||||||
// the body for transmission. copy errors may be assumed to be from the
|
|
||||||
// body.
|
|
||||||
n, err := io.Copy(dst, src)
|
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = src.Seek(curPos, sdkio.SeekStart)
|
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds the x-amz-te: append_md5 header to the request. This requests the service
|
// Adds the x-amz-te: append_md5 header to the request. This requests the service
|
||||||
// responds with a trailing MD5 checksum.
|
// responds with a trailing MD5 checksum.
|
||||||
//
|
//
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws/client"
|
"github.com/aws/aws-sdk-go/aws/client"
|
||||||
"github.com/aws/aws-sdk-go/aws/request"
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
"github.com/aws/aws-sdk-go/internal/s3err"
|
"github.com/aws/aws-sdk-go/internal/s3err"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3/internal/arn"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -13,7 +14,7 @@ func init() {
|
||||||
|
|
||||||
func defaultInitClientFn(c *client.Client) {
|
func defaultInitClientFn(c *client.Client) {
|
||||||
// Support building custom endpoints based on config
|
// Support building custom endpoints based on config
|
||||||
c.Handlers.Build.PushFront(updateEndpointForS3Config)
|
c.Handlers.Build.PushFront(endpointHandler)
|
||||||
|
|
||||||
// Require SSL when using SSE keys
|
// Require SSL when using SSE keys
|
||||||
c.Handlers.Validate.PushBack(validateSSERequiresSSL)
|
c.Handlers.Validate.PushBack(validateSSERequiresSSL)
|
||||||
|
@ -27,17 +28,11 @@ func defaultInitClientFn(c *client.Client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultInitRequestFn(r *request.Request) {
|
func defaultInitRequestFn(r *request.Request) {
|
||||||
// Add reuest handlers for specific platforms.
|
// Add request handlers for specific platforms.
|
||||||
// e.g. 100-continue support for PUT requests using Go 1.6
|
// e.g. 100-continue support for PUT requests using Go 1.6
|
||||||
platformRequestHandlers(r)
|
platformRequestHandlers(r)
|
||||||
|
|
||||||
switch r.Operation.Name {
|
switch r.Operation.Name {
|
||||||
case opPutBucketCors, opPutBucketLifecycle, opPutBucketPolicy,
|
|
||||||
opPutBucketTagging, opDeleteObjects, opPutBucketLifecycleConfiguration,
|
|
||||||
opPutObjectLegalHold, opPutObjectRetention, opPutObjectLockConfiguration,
|
|
||||||
opPutBucketReplication:
|
|
||||||
// These S3 operations require Content-MD5 to be set
|
|
||||||
r.Handlers.Build.PushBack(contentMD5)
|
|
||||||
case opGetBucketLocation:
|
case opGetBucketLocation:
|
||||||
// GetBucketLocation has custom parsing logic
|
// GetBucketLocation has custom parsing logic
|
||||||
r.Handlers.Unmarshal.PushFront(buildGetBucketLocation)
|
r.Handlers.Unmarshal.PushFront(buildGetBucketLocation)
|
||||||
|
@ -73,3 +68,8 @@ type sseCustomerKeyGetter interface {
|
||||||
type copySourceSSECustomerKeyGetter interface {
|
type copySourceSSECustomerKeyGetter interface {
|
||||||
getCopySourceSSECustomerKey() string
|
getCopySourceSSECustomerKey() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type endpointARNGetter interface {
|
||||||
|
getEndpointARN() (arn.Resource, error)
|
||||||
|
hasEndpointARN() bool
|
||||||
|
}
|
||||||
|
|
|
@ -104,19 +104,6 @@
|
||||||
// content from S3. The Encryption and Decryption clients can be used concurrently
|
// content from S3. The Encryption and Decryption clients can be used concurrently
|
||||||
// once the client is created.
|
// once the client is created.
|
||||||
//
|
//
|
||||||
// sess := session.Must(session.NewSession())
|
|
||||||
//
|
|
||||||
// // Create the decryption client.
|
|
||||||
// svc := s3crypto.NewDecryptionClient(sess)
|
|
||||||
//
|
|
||||||
// // The object will be downloaded from S3 and decrypted locally. By metadata
|
|
||||||
// // about the object's encryption will instruct the decryption client how
|
|
||||||
// // decrypt the content of the object. By default KMS is used for keys.
|
|
||||||
// result, err := svc.GetObject(&s3.GetObjectInput {
|
|
||||||
// Bucket: aws.String(myBucket),
|
|
||||||
// Key: aws.String(myKey),
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// See the s3crypto package documentation for more information.
|
// See the s3crypto package documentation for more information.
|
||||||
// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3crypto/
|
// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3crypto/
|
||||||
//
|
//
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
package s3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
awsarn "github.com/aws/aws-sdk-go/aws/arn"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/private/protocol"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3/internal/arn"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Used by shapes with members decorated as endpoint ARN.
|
||||||
|
func parseEndpointARN(v string) (arn.Resource, error) {
|
||||||
|
return arn.ParseResource(v, accessPointResourceParser)
|
||||||
|
}
|
||||||
|
|
||||||
|
func accessPointResourceParser(a awsarn.ARN) (arn.Resource, error) {
|
||||||
|
resParts := arn.SplitResource(a.Resource)
|
||||||
|
switch resParts[0] {
|
||||||
|
case "accesspoint":
|
||||||
|
return arn.ParseAccessPointResource(a, resParts[1:])
|
||||||
|
default:
|
||||||
|
return nil, arn.InvalidARNError{ARN: a, Reason: "unknown resource type"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func endpointHandler(req *request.Request) {
|
||||||
|
endpoint, ok := req.Params.(endpointARNGetter)
|
||||||
|
if !ok || !endpoint.hasEndpointARN() {
|
||||||
|
updateBucketEndpointFromParams(req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resource, err := endpoint.getEndpointARN()
|
||||||
|
if err != nil {
|
||||||
|
req.Error = newInvalidARNError(nil, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resReq := resourceRequest{
|
||||||
|
Resource: resource,
|
||||||
|
Request: req,
|
||||||
|
}
|
||||||
|
|
||||||
|
if resReq.IsCrossPartition() {
|
||||||
|
req.Error = newClientPartitionMismatchError(resource,
|
||||||
|
req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !resReq.AllowCrossRegion() && resReq.IsCrossRegion() {
|
||||||
|
req.Error = newClientRegionMismatchError(resource,
|
||||||
|
req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if resReq.HasCustomEndpoint() {
|
||||||
|
req.Error = newInvalidARNWithCustomEndpointError(resource, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tv := resource.(type) {
|
||||||
|
case arn.AccessPointARN:
|
||||||
|
err = updateRequestAccessPointEndpoint(req, tv)
|
||||||
|
if err != nil {
|
||||||
|
req.Error = err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
req.Error = newInvalidARNError(resource, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type resourceRequest struct {
|
||||||
|
Resource arn.Resource
|
||||||
|
Request *request.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r resourceRequest) ARN() awsarn.ARN {
|
||||||
|
return r.Resource.GetARN()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r resourceRequest) AllowCrossRegion() bool {
|
||||||
|
return aws.BoolValue(r.Request.Config.S3UseARNRegion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r resourceRequest) UseFIPS() bool {
|
||||||
|
return isFIPS(aws.StringValue(r.Request.Config.Region))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r resourceRequest) IsCrossPartition() bool {
|
||||||
|
return r.Request.ClientInfo.PartitionID != r.Resource.GetARN().Partition
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r resourceRequest) IsCrossRegion() bool {
|
||||||
|
return isCrossRegion(r.Request, r.Resource.GetARN().Region)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r resourceRequest) HasCustomEndpoint() bool {
|
||||||
|
return len(aws.StringValue(r.Request.Config.Endpoint)) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFIPS(clientRegion string) bool {
|
||||||
|
return strings.HasPrefix(clientRegion, "fips-") || strings.HasSuffix(clientRegion, "-fips")
|
||||||
|
}
|
||||||
|
func isCrossRegion(req *request.Request, otherRegion string) bool {
|
||||||
|
return req.ClientInfo.SigningRegion != otherRegion
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateBucketEndpointFromParams(r *request.Request) {
|
||||||
|
bucket, ok := bucketNameFromReqParams(r.Params)
|
||||||
|
if !ok {
|
||||||
|
// Ignore operation requests if the bucket name was not provided
|
||||||
|
// if this is an input validation error the validation handler
|
||||||
|
// will report it.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updateEndpointForS3Config(r, bucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateRequestAccessPointEndpoint(req *request.Request, accessPoint arn.AccessPointARN) error {
|
||||||
|
// Accelerate not supported
|
||||||
|
if aws.BoolValue(req.Config.S3UseAccelerate) {
|
||||||
|
return newClientConfiguredForAccelerateError(accessPoint,
|
||||||
|
req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore the disable host prefix for access points since custom endpoints
|
||||||
|
// are not supported.
|
||||||
|
req.Config.DisableEndpointHostPrefix = aws.Bool(false)
|
||||||
|
|
||||||
|
if err := accessPointEndpointBuilder(accessPoint).Build(req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
removeBucketFromPath(req.HTTPRequest.URL)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeBucketFromPath(u *url.URL) {
|
||||||
|
u.Path = strings.Replace(u.Path, "/{Bucket}", "", -1)
|
||||||
|
if u.Path == "" {
|
||||||
|
u.Path = "/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type accessPointEndpointBuilder arn.AccessPointARN
|
||||||
|
|
||||||
|
const (
|
||||||
|
accessPointPrefixLabel = "accesspoint"
|
||||||
|
accountIDPrefixLabel = "accountID"
|
||||||
|
accesPointPrefixTemplate = "{" + accessPointPrefixLabel + "}-{" + accountIDPrefixLabel + "}."
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a accessPointEndpointBuilder) Build(req *request.Request) error {
|
||||||
|
resolveRegion := arn.AccessPointARN(a).Region
|
||||||
|
cfgRegion := aws.StringValue(req.Config.Region)
|
||||||
|
|
||||||
|
if isFIPS(cfgRegion) {
|
||||||
|
if aws.BoolValue(req.Config.S3UseARNRegion) && isCrossRegion(req, resolveRegion) {
|
||||||
|
// FIPS with cross region is not supported, the SDK must fail
|
||||||
|
// because there is no well defined method for SDK to construct a
|
||||||
|
// correct FIPS endpoint.
|
||||||
|
return newClientConfiguredForCrossRegionFIPSError(arn.AccessPointARN(a),
|
||||||
|
req.ClientInfo.PartitionID, cfgRegion, nil)
|
||||||
|
}
|
||||||
|
resolveRegion = cfgRegion
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint, err := resolveRegionalEndpoint(req, resolveRegion)
|
||||||
|
if err != nil {
|
||||||
|
return newFailedToResolveEndpointError(arn.AccessPointARN(a),
|
||||||
|
req.ClientInfo.PartitionID, cfgRegion, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = updateRequestEndpoint(req, endpoint.URL); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceEndpointLabel = "s3-accesspoint"
|
||||||
|
|
||||||
|
// dualstack provided by endpoint resolver
|
||||||
|
cfgHost := req.HTTPRequest.URL.Host
|
||||||
|
if strings.HasPrefix(cfgHost, "s3") {
|
||||||
|
req.HTTPRequest.URL.Host = serviceEndpointLabel + cfgHost[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol.HostPrefixBuilder{
|
||||||
|
Prefix: accesPointPrefixTemplate,
|
||||||
|
LabelsFn: a.hostPrefixLabelValues,
|
||||||
|
}.Build(req)
|
||||||
|
|
||||||
|
req.ClientInfo.SigningName = endpoint.SigningName
|
||||||
|
req.ClientInfo.SigningRegion = endpoint.SigningRegion
|
||||||
|
|
||||||
|
err = protocol.ValidateEndpointHost(req.Operation.Name, req.HTTPRequest.URL.Host)
|
||||||
|
if err != nil {
|
||||||
|
return newInvalidARNError(arn.AccessPointARN(a), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a accessPointEndpointBuilder) hostPrefixLabelValues() map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
accessPointPrefixLabel: arn.AccessPointARN(a).AccessPointName,
|
||||||
|
accountIDPrefixLabel: arn.AccessPointARN(a).AccountID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveRegionalEndpoint(r *request.Request, region string) (endpoints.ResolvedEndpoint, error) {
|
||||||
|
return r.Config.EndpointResolver.EndpointFor(EndpointsID, region, func(opts *endpoints.Options) {
|
||||||
|
opts.DisableSSL = aws.BoolValue(r.Config.DisableSSL)
|
||||||
|
opts.UseDualStack = aws.BoolValue(r.Config.UseDualStack)
|
||||||
|
opts.S3UsEast1RegionalEndpoint = endpoints.RegionalS3UsEast1Endpoint
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateRequestEndpoint(r *request.Request, endpoint string) (err error) {
|
||||||
|
endpoint = endpoints.AddScheme(endpoint, aws.BoolValue(r.Config.DisableSSL))
|
||||||
|
|
||||||
|
r.HTTPRequest.URL, err = url.Parse(endpoint + r.Operation.HTTPPath)
|
||||||
|
if err != nil {
|
||||||
|
return awserr.New(request.ErrCodeSerialization,
|
||||||
|
"failed to parse endpoint URL", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
package s3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3/internal/arn"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
invalidARNErrorErrCode = "InvalidARNError"
|
||||||
|
configurationErrorErrCode = "ConfigurationError"
|
||||||
|
)
|
||||||
|
|
||||||
|
type invalidARNError struct {
|
||||||
|
message string
|
||||||
|
resource arn.Resource
|
||||||
|
origErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e invalidARNError) Error() string {
|
||||||
|
var extra string
|
||||||
|
if e.resource != nil {
|
||||||
|
extra = "ARN: " + e.resource.String()
|
||||||
|
}
|
||||||
|
return awserr.SprintError(e.Code(), e.Message(), extra, e.origErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e invalidARNError) Code() string {
|
||||||
|
return invalidARNErrorErrCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e invalidARNError) Message() string {
|
||||||
|
return e.message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e invalidARNError) OrigErr() error {
|
||||||
|
return e.origErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInvalidARNError(resource arn.Resource, err error) invalidARNError {
|
||||||
|
return invalidARNError{
|
||||||
|
message: "invalid ARN",
|
||||||
|
origErr: err,
|
||||||
|
resource: resource,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInvalidARNWithCustomEndpointError(resource arn.Resource, err error) invalidARNError {
|
||||||
|
return invalidARNError{
|
||||||
|
message: "resource ARN not supported with custom client endpoints",
|
||||||
|
origErr: err,
|
||||||
|
resource: resource,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ARN not supported for the target partition
|
||||||
|
func newInvalidARNWithUnsupportedPartitionError(resource arn.Resource, err error) invalidARNError {
|
||||||
|
return invalidARNError{
|
||||||
|
message: "resource ARN not supported for the target ARN partition",
|
||||||
|
origErr: err,
|
||||||
|
resource: resource,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type configurationError struct {
|
||||||
|
message string
|
||||||
|
resource arn.Resource
|
||||||
|
clientPartitionID string
|
||||||
|
clientRegion string
|
||||||
|
origErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e configurationError) Error() string {
|
||||||
|
extra := fmt.Sprintf("ARN: %s, client partition: %s, client region: %s",
|
||||||
|
e.resource, e.clientPartitionID, e.clientRegion)
|
||||||
|
|
||||||
|
return awserr.SprintError(e.Code(), e.Message(), extra, e.origErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e configurationError) Code() string {
|
||||||
|
return configurationErrorErrCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e configurationError) Message() string {
|
||||||
|
return e.message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e configurationError) OrigErr() error {
|
||||||
|
return e.origErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClientPartitionMismatchError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
|
||||||
|
return configurationError{
|
||||||
|
message: "client partition does not match provided ARN partition",
|
||||||
|
origErr: err,
|
||||||
|
resource: resource,
|
||||||
|
clientPartitionID: clientPartitionID,
|
||||||
|
clientRegion: clientRegion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClientRegionMismatchError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
|
||||||
|
return configurationError{
|
||||||
|
message: "client region does not match provided ARN region",
|
||||||
|
origErr: err,
|
||||||
|
resource: resource,
|
||||||
|
clientPartitionID: clientPartitionID,
|
||||||
|
clientRegion: clientRegion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFailedToResolveEndpointError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
|
||||||
|
return configurationError{
|
||||||
|
message: "endpoint resolver failed to find an endpoint for the provided ARN region",
|
||||||
|
origErr: err,
|
||||||
|
resource: resource,
|
||||||
|
clientPartitionID: clientPartitionID,
|
||||||
|
clientRegion: clientRegion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClientConfiguredForFIPSError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
|
||||||
|
return configurationError{
|
||||||
|
message: "client configured for fips but cross-region resource ARN provided",
|
||||||
|
origErr: err,
|
||||||
|
resource: resource,
|
||||||
|
clientPartitionID: clientPartitionID,
|
||||||
|
clientRegion: clientRegion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClientConfiguredForAccelerateError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
|
||||||
|
return configurationError{
|
||||||
|
message: "client configured for S3 Accelerate but is supported with resource ARN",
|
||||||
|
origErr: err,
|
||||||
|
resource: resource,
|
||||||
|
clientPartitionID: clientPartitionID,
|
||||||
|
clientRegion: clientRegion,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClientConfiguredForCrossRegionFIPSError(resource arn.Resource, clientPartitionID, clientRegion string, err error) configurationError {
|
||||||
|
return configurationError{
|
||||||
|
message: "client configured for FIPS with cross-region enabled but is supported with cross-region resource ARN",
|
||||||
|
origErr: err,
|
||||||
|
resource: resource,
|
||||||
|
clientPartitionID: clientPartitionID,
|
||||||
|
clientRegion: clientRegion,
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,12 @@ const (
|
||||||
|
|
||||||
// ErrCodeBucketAlreadyOwnedByYou for service response error code
|
// ErrCodeBucketAlreadyOwnedByYou for service response error code
|
||||||
// "BucketAlreadyOwnedByYou".
|
// "BucketAlreadyOwnedByYou".
|
||||||
|
//
|
||||||
|
// The bucket you tried to create already exists, and you own it. Amazon S3
|
||||||
|
// returns this error in all AWS Regions except in the North Virginia Region.
|
||||||
|
// For legacy compatibility, if you re-create an existing bucket that you already
|
||||||
|
// own in the North Virginia Region, Amazon S3 returns 200 OK and resets the
|
||||||
|
// bucket access control lists (ACLs).
|
||||||
ErrCodeBucketAlreadyOwnedByYou = "BucketAlreadyOwnedByYou"
|
ErrCodeBucketAlreadyOwnedByYou = "BucketAlreadyOwnedByYou"
|
||||||
|
|
||||||
// ErrCodeNoSuchBucket for service response error code
|
// ErrCodeNoSuchBucket for service response error code
|
||||||
|
@ -36,13 +42,13 @@ const (
|
||||||
// ErrCodeObjectAlreadyInActiveTierError for service response error code
|
// ErrCodeObjectAlreadyInActiveTierError for service response error code
|
||||||
// "ObjectAlreadyInActiveTierError".
|
// "ObjectAlreadyInActiveTierError".
|
||||||
//
|
//
|
||||||
// This operation is not allowed against this storage tier
|
// This operation is not allowed against this storage tier.
|
||||||
ErrCodeObjectAlreadyInActiveTierError = "ObjectAlreadyInActiveTierError"
|
ErrCodeObjectAlreadyInActiveTierError = "ObjectAlreadyInActiveTierError"
|
||||||
|
|
||||||
// ErrCodeObjectNotInActiveTierError for service response error code
|
// ErrCodeObjectNotInActiveTierError for service response error code
|
||||||
// "ObjectNotInActiveTierError".
|
// "ObjectNotInActiveTierError".
|
||||||
//
|
//
|
||||||
// The source object of the COPY operation is not in the active tier and is
|
// The source object of the COPY operation is not in the active tier and is
|
||||||
// only stored in Amazon Glacier.
|
// only stored in Amazon S3 Glacier.
|
||||||
ErrCodeObjectNotInActiveTierError = "ObjectNotInActiveTierError"
|
ErrCodeObjectNotInActiveTierError = "ObjectNotInActiveTierError"
|
||||||
)
|
)
|
||||||
|
|
|
@ -30,10 +30,10 @@ var accelerateOpBlacklist = operationBlacklist{
|
||||||
opListBuckets, opCreateBucket, opDeleteBucket,
|
opListBuckets, opCreateBucket, opDeleteBucket,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request handler to automatically add the bucket name to the endpoint domain
|
// Automatically add the bucket name to the endpoint domain
|
||||||
// if possible. This style of bucket is valid for all bucket names which are
|
// if possible. This style of bucket is valid for all bucket names which are
|
||||||
// DNS compatible and do not contain "."
|
// DNS compatible and do not contain "."
|
||||||
func updateEndpointForS3Config(r *request.Request) {
|
func updateEndpointForS3Config(r *request.Request, bucketName string) {
|
||||||
forceHostStyle := aws.BoolValue(r.Config.S3ForcePathStyle)
|
forceHostStyle := aws.BoolValue(r.Config.S3ForcePathStyle)
|
||||||
accelerate := aws.BoolValue(r.Config.S3UseAccelerate)
|
accelerate := aws.BoolValue(r.Config.S3UseAccelerate)
|
||||||
|
|
||||||
|
@ -43,45 +43,29 @@ func updateEndpointForS3Config(r *request.Request) {
|
||||||
r.Config.Logger.Log("ERROR: aws.Config.S3UseAccelerate is not compatible with aws.Config.S3ForcePathStyle, ignoring S3ForcePathStyle.")
|
r.Config.Logger.Log("ERROR: aws.Config.S3UseAccelerate is not compatible with aws.Config.S3ForcePathStyle, ignoring S3ForcePathStyle.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateEndpointForAccelerate(r)
|
updateEndpointForAccelerate(r, bucketName)
|
||||||
} else if !forceHostStyle && r.Operation.Name != opGetBucketLocation {
|
} else if !forceHostStyle && r.Operation.Name != opGetBucketLocation {
|
||||||
updateEndpointForHostStyle(r)
|
updateEndpointForHostStyle(r, bucketName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateEndpointForHostStyle(r *request.Request) {
|
func updateEndpointForHostStyle(r *request.Request, bucketName string) {
|
||||||
bucket, ok := bucketNameFromReqParams(r.Params)
|
if !hostCompatibleBucketName(r.HTTPRequest.URL, bucketName) {
|
||||||
if !ok {
|
|
||||||
// Ignore operation requests if the bucketname was not provided
|
|
||||||
// if this is an input validation error the validation handler
|
|
||||||
// will report it.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) {
|
|
||||||
// bucket name must be valid to put into the host
|
// bucket name must be valid to put into the host
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
moveBucketToHost(r.HTTPRequest.URL, bucket)
|
moveBucketToHost(r.HTTPRequest.URL, bucketName)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
accelElem = []byte("s3-accelerate.dualstack.")
|
accelElem = []byte("s3-accelerate.dualstack.")
|
||||||
)
|
)
|
||||||
|
|
||||||
func updateEndpointForAccelerate(r *request.Request) {
|
func updateEndpointForAccelerate(r *request.Request, bucketName string) {
|
||||||
bucket, ok := bucketNameFromReqParams(r.Params)
|
if !hostCompatibleBucketName(r.HTTPRequest.URL, bucketName) {
|
||||||
if !ok {
|
|
||||||
// Ignore operation requests if the bucketname was not provided
|
|
||||||
// if this is an input validation error the validation handler
|
|
||||||
// will report it.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) {
|
|
||||||
r.Error = awserr.New("InvalidParameterException",
|
r.Error = awserr.New("InvalidParameterException",
|
||||||
fmt.Sprintf("bucket name %s is not compatible with S3 Accelerate", bucket),
|
fmt.Sprintf("bucket name %s is not compatible with S3 Accelerate", bucketName),
|
||||||
nil)
|
nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -106,7 +90,7 @@ func updateEndpointForAccelerate(r *request.Request) {
|
||||||
|
|
||||||
r.HTTPRequest.URL.Host = strings.Join(parts, ".")
|
r.HTTPRequest.URL.Host = strings.Join(parts, ".")
|
||||||
|
|
||||||
moveBucketToHost(r.HTTPRequest.URL, bucket)
|
moveBucketToHost(r.HTTPRequest.URL, bucketName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to retrieve the bucket name from the request input parameters.
|
// Attempts to retrieve the bucket name from the request input parameters.
|
||||||
|
@ -148,8 +132,5 @@ func dnsCompatibleBucketName(bucket string) bool {
|
||||||
// moveBucketToHost moves the bucket name from the URI path to URL host.
|
// moveBucketToHost moves the bucket name from the URI path to URL host.
|
||||||
func moveBucketToHost(u *url.URL, bucket string) {
|
func moveBucketToHost(u *url.URL, bucket string) {
|
||||||
u.Host = bucket + "." + u.Host
|
u.Host = bucket + "." + u.Host
|
||||||
u.Path = strings.Replace(u.Path, "/{Bucket}", "", -1)
|
removeBucketFromPath(u)
|
||||||
if u.Path == "" {
|
|
||||||
u.Path = "/"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
45
vendor/github.com/aws/aws-sdk-go/service/s3/internal/arn/accesspoint_arn.go
generated
vendored
Normal file
45
vendor/github.com/aws/aws-sdk-go/service/s3/internal/arn/accesspoint_arn.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package arn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/arn"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccessPointARN provides representation
|
||||||
|
type AccessPointARN struct {
|
||||||
|
arn.ARN
|
||||||
|
AccessPointName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetARN returns the base ARN for the Access Point resource
|
||||||
|
func (a AccessPointARN) GetARN() arn.ARN {
|
||||||
|
return a.ARN
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseAccessPointResource attempts to parse the ARN's resource as an
|
||||||
|
// AccessPoint resource.
|
||||||
|
func ParseAccessPointResource(a arn.ARN, resParts []string) (AccessPointARN, error) {
|
||||||
|
if len(a.Region) == 0 {
|
||||||
|
return AccessPointARN{}, InvalidARNError{a, "region not set"}
|
||||||
|
}
|
||||||
|
if len(a.AccountID) == 0 {
|
||||||
|
return AccessPointARN{}, InvalidARNError{a, "account-id not set"}
|
||||||
|
}
|
||||||
|
if len(resParts) == 0 {
|
||||||
|
return AccessPointARN{}, InvalidARNError{a, "resource-id not set"}
|
||||||
|
}
|
||||||
|
if len(resParts) > 1 {
|
||||||
|
return AccessPointARN{}, InvalidARNError{a, "sub resource not supported"}
|
||||||
|
}
|
||||||
|
|
||||||
|
resID := resParts[0]
|
||||||
|
if len(strings.TrimSpace(resID)) == 0 {
|
||||||
|
return AccessPointARN{}, InvalidARNError{a, "resource-id not set"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccessPointARN{
|
||||||
|
ARN: a,
|
||||||
|
AccessPointName: resID,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
package arn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/arn"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource provides the interfaces abstracting ARNs of specific resource
|
||||||
|
// types.
|
||||||
|
type Resource interface {
|
||||||
|
GetARN() arn.ARN
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceParser provides the function for parsing an ARN's resource
|
||||||
|
// component into a typed resource.
|
||||||
|
type ResourceParser func(arn.ARN) (Resource, error)
|
||||||
|
|
||||||
|
// ParseResource parses an AWS ARN into a typed resource for the S3 API.
|
||||||
|
func ParseResource(s string, resParser ResourceParser) (resARN Resource, err error) {
|
||||||
|
a, err := arn.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(a.Partition) == 0 {
|
||||||
|
return nil, InvalidARNError{a, "partition not set"}
|
||||||
|
}
|
||||||
|
if a.Service != "s3" {
|
||||||
|
return nil, InvalidARNError{a, "service is not S3"}
|
||||||
|
}
|
||||||
|
if len(a.Resource) == 0 {
|
||||||
|
return nil, InvalidARNError{a, "resource not set"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resParser(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitResource splits the resource components by the ARN resource delimiters.
|
||||||
|
func SplitResource(v string) []string {
|
||||||
|
var parts []string
|
||||||
|
var offset int
|
||||||
|
|
||||||
|
for offset <= len(v) {
|
||||||
|
idx := strings.IndexAny(v[offset:], "/:")
|
||||||
|
if idx < 0 {
|
||||||
|
parts = append(parts, v[offset:])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
parts = append(parts, v[offset:idx+offset])
|
||||||
|
offset += idx + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsARN returns whether the given string is an ARN
|
||||||
|
func IsARN(s string) bool {
|
||||||
|
return arn.IsARN(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidARNError provides the error for an invalid ARN error.
|
||||||
|
type InvalidARNError struct {
|
||||||
|
ARN arn.ARN
|
||||||
|
Reason string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e InvalidARNError) Error() string {
|
||||||
|
return "invalid Amazon S3 ARN, " + e.Reason + ", " + e.ARN.String()
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ var initRequest func(*request.Request)
|
||||||
const (
|
const (
|
||||||
ServiceName = "s3" // Name of service.
|
ServiceName = "s3" // Name of service.
|
||||||
EndpointsID = ServiceName // ID to lookup a service endpoint with.
|
EndpointsID = ServiceName // ID to lookup a service endpoint with.
|
||||||
ServiceID = "S3" // ServiceID is a unique identifer of a specific service.
|
ServiceID = "S3" // ServiceID is a unique identifier of a specific service.
|
||||||
)
|
)
|
||||||
|
|
||||||
// New creates a new instance of the S3 client with a session.
|
// New creates a new instance of the S3 client with a session.
|
||||||
|
@ -39,6 +39,8 @@ const (
|
||||||
// aws.Config parameter to add your extra config.
|
// aws.Config parameter to add your extra config.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
|
// mySession := session.Must(session.NewSession())
|
||||||
|
//
|
||||||
// // Create a S3 client from just a session.
|
// // Create a S3 client from just a session.
|
||||||
// svc := s3.New(mySession)
|
// svc := s3.New(mySession)
|
||||||
//
|
//
|
||||||
|
@ -46,11 +48,11 @@ const (
|
||||||
// svc := s3.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
// svc := s3.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *S3 {
|
func New(p client.ConfigProvider, cfgs ...*aws.Config) *S3 {
|
||||||
c := p.ClientConfig(EndpointsID, cfgs...)
|
c := p.ClientConfig(EndpointsID, cfgs...)
|
||||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
|
return newClient(*c.Config, c.Handlers, c.PartitionID, c.Endpoint, c.SigningRegion, c.SigningName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newClient creates, initializes and returns a new service client instance.
|
// newClient creates, initializes and returns a new service client instance.
|
||||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *S3 {
|
func newClient(cfg aws.Config, handlers request.Handlers, partitionID, endpoint, signingRegion, signingName string) *S3 {
|
||||||
svc := &S3{
|
svc := &S3{
|
||||||
Client: client.New(
|
Client: client.New(
|
||||||
cfg,
|
cfg,
|
||||||
|
@ -59,6 +61,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
|
||||||
ServiceID: ServiceID,
|
ServiceID: ServiceID,
|
||||||
SigningName: signingName,
|
SigningName: signingName,
|
||||||
SigningRegion: signingRegion,
|
SigningRegion: signingRegion,
|
||||||
|
PartitionID: partitionID,
|
||||||
Endpoint: endpoint,
|
Endpoint: endpoint,
|
||||||
APIVersion: "2006-03-01",
|
APIVersion: "2006-03-01",
|
||||||
},
|
},
|
||||||
|
@ -75,6 +78,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
|
||||||
svc.Handlers.UnmarshalMeta.PushBackNamed(restxml.UnmarshalMetaHandler)
|
svc.Handlers.UnmarshalMeta.PushBackNamed(restxml.UnmarshalMetaHandler)
|
||||||
svc.Handlers.UnmarshalError.PushBackNamed(restxml.UnmarshalErrorHandler)
|
svc.Handlers.UnmarshalError.PushBackNamed(restxml.UnmarshalErrorHandler)
|
||||||
|
|
||||||
|
svc.Handlers.BuildStream.PushBackNamed(restxml.BuildHandler)
|
||||||
svc.Handlers.UnmarshalStream.PushBackNamed(restxml.UnmarshalHandler)
|
svc.Handlers.UnmarshalStream.PushBackNamed(restxml.UnmarshalHandler)
|
||||||
|
|
||||||
// Run custom client initialization if present
|
// Run custom client initialization if present
|
||||||
|
|
|
@ -69,7 +69,7 @@ func computeKeyMD5(keyHeader, keyMD5Header, key string, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// In backwards compatiable, the header's value is not base64 encoded,
|
// In backwards compatible, the header's value is not base64 encoded,
|
||||||
// and needs to be encoded and updated by the SDK's customizations.
|
// and needs to be encoded and updated by the SDK's customizations.
|
||||||
b64Key := base64.StdEncoding.EncodeToString([]byte(key))
|
b64Key := base64.StdEncoding.EncodeToString([]byte(key))
|
||||||
r.Header.Set(keyHeader, b64Key)
|
r.Header.Set(keyHeader, b64Key)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package s3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
@ -24,17 +25,18 @@ func copyMultipartStatusOKUnmarhsalError(r *request.Request) {
|
||||||
r.HTTPResponse.Body = ioutil.NopCloser(body)
|
r.HTTPResponse.Body = ioutil.NopCloser(body)
|
||||||
defer body.Seek(0, sdkio.SeekStart)
|
defer body.Seek(0, sdkio.SeekStart)
|
||||||
|
|
||||||
if body.Len() == 0 {
|
|
||||||
// If there is no body don't attempt to parse the body.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
unmarshalError(r)
|
unmarshalError(r)
|
||||||
if err, ok := r.Error.(awserr.Error); ok && err != nil {
|
if err, ok := r.Error.(awserr.Error); ok && err != nil {
|
||||||
if err.Code() == request.ErrCodeSerialization {
|
if err.Code() == request.ErrCodeSerialization &&
|
||||||
|
err.OrigErr() != io.EOF {
|
||||||
r.Error = nil
|
r.Error = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// if empty payload
|
||||||
|
if err.OrigErr() == io.EOF {
|
||||||
|
r.HTTPResponse.StatusCode = http.StatusInternalServerError
|
||||||
|
} else {
|
||||||
r.HTTPResponse.StatusCode = http.StatusServiceUnavailable
|
r.HTTPResponse.StatusCode = http.StatusServiceUnavailable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package s3
|
package s3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -45,17 +46,24 @@ func unmarshalError(r *request.Request) {
|
||||||
|
|
||||||
// Attempt to parse error from body if it is known
|
// Attempt to parse error from body if it is known
|
||||||
var errResp xmlErrorResponse
|
var errResp xmlErrorResponse
|
||||||
err := xmlutil.UnmarshalXMLError(&errResp, r.HTTPResponse.Body)
|
var err error
|
||||||
if err == io.EOF {
|
if r.HTTPResponse.StatusCode >= 200 && r.HTTPResponse.StatusCode < 300 {
|
||||||
// Only capture the error if an unmarshal error occurs that is not EOF,
|
err = s3unmarshalXMLError(&errResp, r.HTTPResponse.Body)
|
||||||
// because S3 might send an error without a error message which causes
|
} else {
|
||||||
// the XML unmarshal to fail with EOF.
|
err = xmlutil.UnmarshalXMLError(&errResp, r.HTTPResponse.Body)
|
||||||
err = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var errorMsg string
|
||||||
|
if err == io.EOF {
|
||||||
|
errorMsg = "empty response payload"
|
||||||
|
} else {
|
||||||
|
errorMsg = "failed to unmarshal error message"
|
||||||
|
}
|
||||||
|
|
||||||
r.Error = awserr.NewRequestFailure(
|
r.Error = awserr.NewRequestFailure(
|
||||||
awserr.New(request.ErrCodeSerialization,
|
awserr.New(request.ErrCodeSerialization,
|
||||||
"failed to unmarshal error message", err),
|
errorMsg, err),
|
||||||
r.HTTPResponse.StatusCode,
|
r.HTTPResponse.StatusCode,
|
||||||
r.RequestID,
|
r.RequestID,
|
||||||
)
|
)
|
||||||
|
@ -86,3 +94,21 @@ type RequestFailure interface {
|
||||||
// Host ID is the S3 Host ID needed for debug, and contacting support
|
// Host ID is the S3 Host ID needed for debug, and contacting support
|
||||||
HostID() string
|
HostID() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// s3unmarshalXMLError is s3 specific xml error unmarshaler
|
||||||
|
// for 200 OK errors and response payloads.
|
||||||
|
// This function differs from the xmlUtil.UnmarshalXMLError
|
||||||
|
// func. It does not ignore the EOF error and passes it up.
|
||||||
|
// Related to bug fix for `s3 200 OK response with empty payload`
|
||||||
|
func s3unmarshalXMLError(v interface{}, stream io.Reader) error {
|
||||||
|
var errBuf bytes.Buffer
|
||||||
|
body := io.TeeReader(stream, &errBuf)
|
||||||
|
|
||||||
|
err := xml.NewDecoder(body).Decode(v)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return awserr.NewUnmarshalError(err,
|
||||||
|
"failed to unmarshal error message", errBuf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
@ -78,6 +78,8 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
|
||||||
// IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)
|
// IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
|
// Session Duration
|
||||||
|
//
|
||||||
// By default, the temporary security credentials created by AssumeRole last
|
// By default, the temporary security credentials created by AssumeRole last
|
||||||
// for one hour. However, you can use the optional DurationSeconds parameter
|
// for one hour. However, you can use the optional DurationSeconds parameter
|
||||||
// to specify the duration of your session. You can provide a value from 900
|
// to specify the duration of your session. You can provide a value from 900
|
||||||
|
@ -91,6 +93,8 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
|
||||||
// URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
|
// URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
|
// Permissions
|
||||||
|
//
|
||||||
// The temporary security credentials created by AssumeRole can be used to make
|
// The temporary security credentials created by AssumeRole can be used to make
|
||||||
// API calls to any AWS service with the following exception: You cannot call
|
// API calls to any AWS service with the following exception: You cannot call
|
||||||
// the AWS STS GetFederationToken or GetSessionToken API operations.
|
// the AWS STS GetFederationToken or GetSessionToken API operations.
|
||||||
|
@ -99,7 +103,7 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
|
||||||
// to this operation. You can pass a single JSON policy document to use as an
|
// to this operation. You can pass a single JSON policy document to use as an
|
||||||
// inline session policy. You can also specify up to 10 managed policies to
|
// inline session policy. You can also specify up to 10 managed policies to
|
||||||
// use as managed session policies. The plain text that you use for both inline
|
// use as managed session policies. The plain text that you use for both inline
|
||||||
// and managed session policies shouldn't exceed 2048 characters. Passing policies
|
// and managed session policies can't exceed 2,048 characters. Passing policies
|
||||||
// to this operation returns new temporary credentials. The resulting session's
|
// to this operation returns new temporary credentials. The resulting session's
|
||||||
// permissions are the intersection of the role's identity-based policy and
|
// permissions are the intersection of the role's identity-based policy and
|
||||||
// the session policies. You can use the role's temporary credentials in subsequent
|
// the session policies. You can use the role's temporary credentials in subsequent
|
||||||
|
@ -131,6 +135,24 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
|
||||||
// see IAM Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html)
|
// see IAM Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
|
// Tags
|
||||||
|
//
|
||||||
|
// (Optional) You can pass tag key-value pairs to your session. These tags are
|
||||||
|
// called session tags. For more information about session tags, see Passing
|
||||||
|
// Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// An administrator must grant you the permissions necessary to pass session
|
||||||
|
// tags. The administrator can also create granular permissions to allow you
|
||||||
|
// to pass only specific session tags. For more information, see Tutorial: Using
|
||||||
|
// Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You can set the session tags as transitive. Transitive tags persist during
|
||||||
|
// role chaining. For more information, see Chaining Roles with Session Tags
|
||||||
|
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
// Using MFA with AssumeRole
|
// Using MFA with AssumeRole
|
||||||
//
|
//
|
||||||
// (Optional) You can include multi-factor authentication (MFA) information
|
// (Optional) You can include multi-factor authentication (MFA) information
|
||||||
|
@ -165,9 +187,18 @@ func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, o
|
||||||
// message describes the specific error.
|
// message describes the specific error.
|
||||||
//
|
//
|
||||||
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
|
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
|
||||||
// The request was rejected because the policy document was too large. The error
|
// The request was rejected because the total packed size of the session policies
|
||||||
// message describes how big the policy document is, in packed form, as a percentage
|
// and session tags combined was too large. An AWS conversion compresses the
|
||||||
// of what the API allows.
|
// session policy document, session policy ARNs, and session tags into a packed
|
||||||
|
// binary format that has a separate limit. The error message indicates by percentage
|
||||||
|
// how close the policies and tags are to the upper size limit. For more information,
|
||||||
|
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You could receive this error even though you meet other defined session policy
|
||||||
|
// and session tag limits. For more information, see IAM and STS Entity Character
|
||||||
|
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// * ErrCodeRegionDisabledException "RegionDisabledException"
|
// * ErrCodeRegionDisabledException "RegionDisabledException"
|
||||||
// STS is not activated in the requested region for the account that is being
|
// STS is not activated in the requested region for the account that is being
|
||||||
|
@ -256,6 +287,8 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
|
||||||
// an access key ID, a secret access key, and a security token. Applications
|
// an access key ID, a secret access key, and a security token. Applications
|
||||||
// can use these temporary security credentials to sign calls to AWS services.
|
// can use these temporary security credentials to sign calls to AWS services.
|
||||||
//
|
//
|
||||||
|
// Session Duration
|
||||||
|
//
|
||||||
// By default, the temporary security credentials created by AssumeRoleWithSAML
|
// By default, the temporary security credentials created by AssumeRoleWithSAML
|
||||||
// last for one hour. However, you can use the optional DurationSeconds parameter
|
// last for one hour. However, you can use the optional DurationSeconds parameter
|
||||||
// to specify the duration of your session. Your role session lasts for the
|
// to specify the duration of your session. Your role session lasts for the
|
||||||
|
@ -271,6 +304,8 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
|
||||||
// URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
|
// URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
|
// Permissions
|
||||||
|
//
|
||||||
// The temporary security credentials created by AssumeRoleWithSAML can be used
|
// The temporary security credentials created by AssumeRoleWithSAML can be used
|
||||||
// to make API calls to any AWS service with the following exception: you cannot
|
// to make API calls to any AWS service with the following exception: you cannot
|
||||||
// call the STS GetFederationToken or GetSessionToken API operations.
|
// call the STS GetFederationToken or GetSessionToken API operations.
|
||||||
|
@ -279,7 +314,7 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
|
||||||
// to this operation. You can pass a single JSON policy document to use as an
|
// to this operation. You can pass a single JSON policy document to use as an
|
||||||
// inline session policy. You can also specify up to 10 managed policies to
|
// inline session policy. You can also specify up to 10 managed policies to
|
||||||
// use as managed session policies. The plain text that you use for both inline
|
// use as managed session policies. The plain text that you use for both inline
|
||||||
// and managed session policies shouldn't exceed 2048 characters. Passing policies
|
// and managed session policies can't exceed 2,048 characters. Passing policies
|
||||||
// to this operation returns new temporary credentials. The resulting session's
|
// to this operation returns new temporary credentials. The resulting session's
|
||||||
// permissions are the intersection of the role's identity-based policy and
|
// permissions are the intersection of the role's identity-based policy and
|
||||||
// the session policies. You can use the role's temporary credentials in subsequent
|
// the session policies. You can use the role's temporary credentials in subsequent
|
||||||
|
@ -289,12 +324,6 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
|
||||||
// information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
// information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// Before your application can call AssumeRoleWithSAML, you must configure your
|
|
||||||
// SAML identity provider (IdP) to issue the claims required by AWS. Additionally,
|
|
||||||
// you must use AWS Identity and Access Management (IAM) to create a SAML provider
|
|
||||||
// entity in your AWS account that represents your identity provider. You must
|
|
||||||
// also create an IAM role that specifies this SAML provider in its trust policy.
|
|
||||||
//
|
|
||||||
// Calling AssumeRoleWithSAML does not require the use of AWS security credentials.
|
// Calling AssumeRoleWithSAML does not require the use of AWS security credentials.
|
||||||
// The identity of the caller is validated by using keys in the metadata document
|
// The identity of the caller is validated by using keys in the metadata document
|
||||||
// that is uploaded for the SAML provider entity for your identity provider.
|
// that is uploaded for the SAML provider entity for your identity provider.
|
||||||
|
@ -302,8 +331,50 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
|
||||||
// Calling AssumeRoleWithSAML can result in an entry in your AWS CloudTrail
|
// Calling AssumeRoleWithSAML can result in an entry in your AWS CloudTrail
|
||||||
// logs. The entry includes the value in the NameID element of the SAML assertion.
|
// logs. The entry includes the value in the NameID element of the SAML assertion.
|
||||||
// We recommend that you use a NameIDType that is not associated with any personally
|
// We recommend that you use a NameIDType that is not associated with any personally
|
||||||
// identifiable information (PII). For example, you could instead use the Persistent
|
// identifiable information (PII). For example, you could instead use the persistent
|
||||||
// Identifier (urn:oasis:names:tc:SAML:2.0:nameid-format:persistent).
|
// identifier (urn:oasis:names:tc:SAML:2.0:nameid-format:persistent).
|
||||||
|
//
|
||||||
|
// Tags
|
||||||
|
//
|
||||||
|
// (Optional) You can configure your IdP to pass attributes into your SAML assertion
|
||||||
|
// as session tags. Each session tag consists of a key name and an associated
|
||||||
|
// value. For more information about session tags, see Passing Session Tags
|
||||||
|
// in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You can pass up to 50 session tags. The plain text session tag keys can’t
|
||||||
|
// exceed 128 characters and the values can’t exceed 256 characters. For these
|
||||||
|
// and additional limits, see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
|
// and tags for your request are to the upper size limit.
|
||||||
|
//
|
||||||
|
// You can pass a session tag with the same key as a tag that is attached to
|
||||||
|
// the role. When you do, session tags override the role's tags with the same
|
||||||
|
// key.
|
||||||
|
//
|
||||||
|
// An administrator must grant you the permissions necessary to pass session
|
||||||
|
// tags. The administrator can also create granular permissions to allow you
|
||||||
|
// to pass only specific session tags. For more information, see Tutorial: Using
|
||||||
|
// Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You can set the session tags as transitive. Transitive tags persist during
|
||||||
|
// role chaining. For more information, see Chaining Roles with Session Tags
|
||||||
|
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// SAML Configuration
|
||||||
|
//
|
||||||
|
// Before your application can call AssumeRoleWithSAML, you must configure your
|
||||||
|
// SAML identity provider (IdP) to issue the claims required by AWS. Additionally,
|
||||||
|
// you must use AWS Identity and Access Management (IAM) to create a SAML provider
|
||||||
|
// entity in your AWS account that represents your identity provider. You must
|
||||||
|
// also create an IAM role that specifies this SAML provider in its trust policy.
|
||||||
//
|
//
|
||||||
// For more information, see the following resources:
|
// For more information, see the following resources:
|
||||||
//
|
//
|
||||||
|
@ -332,9 +403,18 @@ func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *re
|
||||||
// message describes the specific error.
|
// message describes the specific error.
|
||||||
//
|
//
|
||||||
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
|
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
|
||||||
// The request was rejected because the policy document was too large. The error
|
// The request was rejected because the total packed size of the session policies
|
||||||
// message describes how big the policy document is, in packed form, as a percentage
|
// and session tags combined was too large. An AWS conversion compresses the
|
||||||
// of what the API allows.
|
// session policy document, session policy ARNs, and session tags into a packed
|
||||||
|
// binary format that has a separate limit. The error message indicates by percentage
|
||||||
|
// how close the policies and tags are to the upper size limit. For more information,
|
||||||
|
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You could receive this error even though you meet other defined session policy
|
||||||
|
// and session tag limits. For more information, see IAM and STS Entity Character
|
||||||
|
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// * ErrCodeIDPRejectedClaimException "IDPRejectedClaim"
|
// * ErrCodeIDPRejectedClaimException "IDPRejectedClaim"
|
||||||
// The identity provider (IdP) reported that authentication failed. This might
|
// The identity provider (IdP) reported that authentication failed. This might
|
||||||
|
@ -456,6 +536,8 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
|
||||||
// key ID, a secret access key, and a security token. Applications can use these
|
// key ID, a secret access key, and a security token. Applications can use these
|
||||||
// temporary security credentials to sign calls to AWS service API operations.
|
// temporary security credentials to sign calls to AWS service API operations.
|
||||||
//
|
//
|
||||||
|
// Session Duration
|
||||||
|
//
|
||||||
// By default, the temporary security credentials created by AssumeRoleWithWebIdentity
|
// By default, the temporary security credentials created by AssumeRoleWithWebIdentity
|
||||||
// last for one hour. However, you can use the optional DurationSeconds parameter
|
// last for one hour. However, you can use the optional DurationSeconds parameter
|
||||||
// to specify the duration of your session. You can provide a value from 900
|
// to specify the duration of your session. You can provide a value from 900
|
||||||
|
@ -469,6 +551,8 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
|
||||||
// URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
|
// URL. For more information, see Using IAM Roles (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
|
// Permissions
|
||||||
|
//
|
||||||
// The temporary security credentials created by AssumeRoleWithWebIdentity can
|
// The temporary security credentials created by AssumeRoleWithWebIdentity can
|
||||||
// be used to make API calls to any AWS service with the following exception:
|
// be used to make API calls to any AWS service with the following exception:
|
||||||
// you cannot call the STS GetFederationToken or GetSessionToken API operations.
|
// you cannot call the STS GetFederationToken or GetSessionToken API operations.
|
||||||
|
@ -477,7 +561,7 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
|
||||||
// to this operation. You can pass a single JSON policy document to use as an
|
// to this operation. You can pass a single JSON policy document to use as an
|
||||||
// inline session policy. You can also specify up to 10 managed policies to
|
// inline session policy. You can also specify up to 10 managed policies to
|
||||||
// use as managed session policies. The plain text that you use for both inline
|
// use as managed session policies. The plain text that you use for both inline
|
||||||
// and managed session policies shouldn't exceed 2048 characters. Passing policies
|
// and managed session policies can't exceed 2,048 characters. Passing policies
|
||||||
// to this operation returns new temporary credentials. The resulting session's
|
// to this operation returns new temporary credentials. The resulting session's
|
||||||
// permissions are the intersection of the role's identity-based policy and
|
// permissions are the intersection of the role's identity-based policy and
|
||||||
// the session policies. You can use the role's temporary credentials in subsequent
|
// the session policies. You can use the role's temporary credentials in subsequent
|
||||||
|
@ -487,6 +571,42 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
|
||||||
// information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
// information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
|
// Tags
|
||||||
|
//
|
||||||
|
// (Optional) You can configure your IdP to pass attributes into your web identity
|
||||||
|
// token as session tags. Each session tag consists of a key name and an associated
|
||||||
|
// value. For more information about session tags, see Passing Session Tags
|
||||||
|
// in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You can pass up to 50 session tags. The plain text session tag keys can’t
|
||||||
|
// exceed 128 characters and the values can’t exceed 256 characters. For these
|
||||||
|
// and additional limits, see IAM and STS Character Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
|
// and tags for your request are to the upper size limit.
|
||||||
|
//
|
||||||
|
// You can pass a session tag with the same key as a tag that is attached to
|
||||||
|
// the role. When you do, the session tag overrides the role tag with the same
|
||||||
|
// key.
|
||||||
|
//
|
||||||
|
// An administrator must grant you the permissions necessary to pass session
|
||||||
|
// tags. The administrator can also create granular permissions to allow you
|
||||||
|
// to pass only specific session tags. For more information, see Tutorial: Using
|
||||||
|
// Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You can set the session tags as transitive. Transitive tags persist during
|
||||||
|
// role chaining. For more information, see Chaining Roles with Session Tags
|
||||||
|
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// Identities
|
||||||
|
//
|
||||||
// Before your application can call AssumeRoleWithWebIdentity, you must have
|
// Before your application can call AssumeRoleWithWebIdentity, you must have
|
||||||
// an identity token from a supported identity provider and create a role that
|
// an identity token from a supported identity provider and create a role that
|
||||||
// the application can assume. The role that your application assumes must trust
|
// the application can assume. The role that your application assumes must trust
|
||||||
|
@ -514,8 +634,8 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
|
||||||
// * AWS SDK for iOS Developer Guide (http://aws.amazon.com/sdkforios/) and
|
// * AWS SDK for iOS Developer Guide (http://aws.amazon.com/sdkforios/) and
|
||||||
// AWS SDK for Android Developer Guide (http://aws.amazon.com/sdkforandroid/).
|
// AWS SDK for Android Developer Guide (http://aws.amazon.com/sdkforandroid/).
|
||||||
// These toolkits contain sample apps that show how to invoke the identity
|
// These toolkits contain sample apps that show how to invoke the identity
|
||||||
// providers, and then how to use the information from these providers to
|
// providers. The toolkits then show how to use the information from these
|
||||||
// get and use temporary security credentials.
|
// providers to get and use temporary security credentials.
|
||||||
//
|
//
|
||||||
// * Web Identity Federation with Mobile Applications (http://aws.amazon.com/articles/web-identity-federation-with-mobile-applications).
|
// * Web Identity Federation with Mobile Applications (http://aws.amazon.com/articles/web-identity-federation-with-mobile-applications).
|
||||||
// This article discusses web identity federation and shows an example of
|
// This article discusses web identity federation and shows an example of
|
||||||
|
@ -535,9 +655,18 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
|
||||||
// message describes the specific error.
|
// message describes the specific error.
|
||||||
//
|
//
|
||||||
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
|
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
|
||||||
// The request was rejected because the policy document was too large. The error
|
// The request was rejected because the total packed size of the session policies
|
||||||
// message describes how big the policy document is, in packed form, as a percentage
|
// and session tags combined was too large. An AWS conversion compresses the
|
||||||
// of what the API allows.
|
// session policy document, session policy ARNs, and session tags into a packed
|
||||||
|
// binary format that has a separate limit. The error message indicates by percentage
|
||||||
|
// how close the policies and tags are to the upper size limit. For more information,
|
||||||
|
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You could receive this error even though you meet other defined session policy
|
||||||
|
// and session tag limits. For more information, see IAM and STS Entity Character
|
||||||
|
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// * ErrCodeIDPRejectedClaimException "IDPRejectedClaim"
|
// * ErrCodeIDPRejectedClaimException "IDPRejectedClaim"
|
||||||
// The identity provider (IdP) reported that authentication failed. This might
|
// The identity provider (IdP) reported that authentication failed. This might
|
||||||
|
@ -547,11 +676,11 @@ func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityI
|
||||||
// can also mean that the claim has expired or has been explicitly revoked.
|
// can also mean that the claim has expired or has been explicitly revoked.
|
||||||
//
|
//
|
||||||
// * ErrCodeIDPCommunicationErrorException "IDPCommunicationError"
|
// * ErrCodeIDPCommunicationErrorException "IDPCommunicationError"
|
||||||
// The request could not be fulfilled because the non-AWS identity provider
|
// The request could not be fulfilled because the identity provider (IDP) that
|
||||||
// (IDP) that was asked to verify the incoming identity token could not be reached.
|
// was asked to verify the incoming identity token could not be reached. This
|
||||||
// This is often a transient error caused by network conditions. Retry the request
|
// is often a transient error caused by network conditions. Retry the request
|
||||||
// a limited number of times so that you don't exceed the request rate. If the
|
// a limited number of times so that you don't exceed the request rate. If the
|
||||||
// error persists, the non-AWS identity provider might be down or not responding.
|
// error persists, the identity provider might be down or not responding.
|
||||||
//
|
//
|
||||||
// * ErrCodeInvalidIdentityTokenException "InvalidIdentityToken"
|
// * ErrCodeInvalidIdentityTokenException "InvalidIdentityToken"
|
||||||
// The web identity token that was passed could not be validated by AWS. Get
|
// The web identity token that was passed could not be validated by AWS. Get
|
||||||
|
@ -763,7 +892,8 @@ func (c *STS) GetAccessKeyInfoRequest(input *GetAccessKeyInfoInput) (req *reques
|
||||||
// pull a credentials report (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html)
|
// pull a credentials report (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_getting-report.html)
|
||||||
// to learn which IAM user owns the keys. To learn who requested the temporary
|
// to learn which IAM user owns the keys. To learn who requested the temporary
|
||||||
// credentials for an ASIA access key, view the STS events in your CloudTrail
|
// credentials for an ASIA access key, view the STS events in your CloudTrail
|
||||||
// logs (https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html).
|
// logs (https://docs.aws.amazon.com/IAM/latest/UserGuide/cloudtrail-integration.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// This operation does not indicate the state of the access key. The key might
|
// This operation does not indicate the state of the access key. The key might
|
||||||
// be active, inactive, or deleted. Active keys might not have permissions to
|
// be active, inactive, or deleted. Active keys might not have permissions to
|
||||||
|
@ -850,7 +980,8 @@ func (c *STS) GetCallerIdentityRequest(input *GetCallerIdentityInput) (req *requ
|
||||||
// sts:GetCallerIdentity action, you can still perform this operation. Permissions
|
// sts:GetCallerIdentity action, you can still perform this operation. Permissions
|
||||||
// are not required because the same information is returned when an IAM user
|
// are not required because the same information is returned when an IAM user
|
||||||
// or role is denied access. To view an example response, see I Am Not Authorized
|
// or role is denied access. To view an example response, see I Am Not Authorized
|
||||||
// to Perform: iam:DeleteVirtualMFADevice (https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_general.html#troubleshoot_general_access-denied-delete-mfa).
|
// to Perform: iam:DeleteVirtualMFADevice (https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_general.html#troubleshoot_general_access-denied-delete-mfa)
|
||||||
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// Returns awserr.Error for service API and SDK errors. Use runtime type assertions
|
// Returns awserr.Error for service API and SDK errors. Use runtime type assertions
|
||||||
// with awserr.Error's Code and Message methods to get detailed information about
|
// with awserr.Error's Code and Message methods to get detailed information about
|
||||||
|
@ -942,7 +1073,8 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re
|
||||||
// or an OpenID Connect-compatible identity provider. In this case, we recommend
|
// or an OpenID Connect-compatible identity provider. In this case, we recommend
|
||||||
// that you use Amazon Cognito (http://aws.amazon.com/cognito/) or AssumeRoleWithWebIdentity.
|
// that you use Amazon Cognito (http://aws.amazon.com/cognito/) or AssumeRoleWithWebIdentity.
|
||||||
// For more information, see Federation Through a Web-based Identity Provider
|
// For more information, see Federation Through a Web-based Identity Provider
|
||||||
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity).
|
// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity)
|
||||||
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// You can also call GetFederationToken using the security credentials of an
|
// You can also call GetFederationToken using the security credentials of an
|
||||||
// AWS account root user, but we do not recommend it. Instead, we recommend
|
// AWS account root user, but we do not recommend it. Instead, we recommend
|
||||||
|
@ -952,41 +1084,67 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re
|
||||||
// Practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
|
// Practices (https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
|
// Session duration
|
||||||
|
//
|
||||||
// The temporary credentials are valid for the specified duration, from 900
|
// The temporary credentials are valid for the specified duration, from 900
|
||||||
// seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours). The default
|
// seconds (15 minutes) up to a maximum of 129,600 seconds (36 hours). The default
|
||||||
// is 43,200 seconds (12 hours). Temporary credentials that are obtained by
|
// session duration is 43,200 seconds (12 hours). Temporary credentials that
|
||||||
// using AWS account root user credentials have a maximum duration of 3,600
|
// are obtained by using AWS account root user credentials have a maximum duration
|
||||||
// seconds (1 hour).
|
// of 3,600 seconds (1 hour).
|
||||||
//
|
|
||||||
// The temporary security credentials created by GetFederationToken can be used
|
|
||||||
// to make API calls to any AWS service with the following exceptions:
|
|
||||||
//
|
|
||||||
// * You cannot use these credentials to call any IAM API operations.
|
|
||||||
//
|
|
||||||
// * You cannot call any STS API operations except GetCallerIdentity.
|
|
||||||
//
|
//
|
||||||
// Permissions
|
// Permissions
|
||||||
//
|
//
|
||||||
|
// You can use the temporary credentials created by GetFederationToken in any
|
||||||
|
// AWS service except the following:
|
||||||
|
//
|
||||||
|
// * You cannot call any IAM operations using the AWS CLI or the AWS API.
|
||||||
|
//
|
||||||
|
// * You cannot call any STS operations except GetCallerIdentity.
|
||||||
|
//
|
||||||
// You must pass an inline or managed session policy (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
// You must pass an inline or managed session policy (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
||||||
// to this operation. You can pass a single JSON policy document to use as an
|
// to this operation. You can pass a single JSON policy document to use as an
|
||||||
// inline session policy. You can also specify up to 10 managed policies to
|
// inline session policy. You can also specify up to 10 managed policies to
|
||||||
// use as managed session policies. The plain text that you use for both inline
|
// use as managed session policies. The plain text that you use for both inline
|
||||||
// and managed session policies shouldn't exceed 2048 characters.
|
// and managed session policies can't exceed 2,048 characters.
|
||||||
//
|
//
|
||||||
// Though the session policy parameters are optional, if you do not pass a policy,
|
// Though the session policy parameters are optional, if you do not pass a policy,
|
||||||
// then the resulting federated user session has no permissions. The only exception
|
// then the resulting federated user session has no permissions. When you pass
|
||||||
// is when the credentials are used to access a resource that has a resource-based
|
// session policies, the session permissions are the intersection of the IAM
|
||||||
// policy that specifically references the federated user session in the Principal
|
// user policies and the session policies that you pass. This gives you a way
|
||||||
// element of the policy. When you pass session policies, the session permissions
|
// to further restrict the permissions for a federated user. You cannot use
|
||||||
// are the intersection of the IAM user policies and the session policies that
|
// session policies to grant more permissions than those that are defined in
|
||||||
// you pass. This gives you a way to further restrict the permissions for a
|
// the permissions policy of the IAM user. For more information, see Session
|
||||||
// federated user. You cannot use session policies to grant more permissions
|
// Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
||||||
// than those that are defined in the permissions policy of the IAM user. For
|
|
||||||
// more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
|
||||||
// in the IAM User Guide. For information about using GetFederationToken to
|
// in the IAM User Guide. For information about using GetFederationToken to
|
||||||
// create temporary security credentials, see GetFederationToken—Federation
|
// create temporary security credentials, see GetFederationToken—Federation
|
||||||
// Through a Custom Identity Broker (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getfederationtoken).
|
// Through a Custom Identity Broker (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getfederationtoken).
|
||||||
//
|
//
|
||||||
|
// You can use the credentials to access a resource that has a resource-based
|
||||||
|
// policy. If that policy specifically references the federated user session
|
||||||
|
// in the Principal element of the policy, the session has the permissions allowed
|
||||||
|
// by the policy. These permissions are granted in addition to the permissions
|
||||||
|
// granted by the session policies.
|
||||||
|
//
|
||||||
|
// Tags
|
||||||
|
//
|
||||||
|
// (Optional) You can pass tag key-value pairs to your session. These are called
|
||||||
|
// session tags. For more information about session tags, see Passing Session
|
||||||
|
// Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// An administrator must grant you the permissions necessary to pass session
|
||||||
|
// tags. The administrator can also create granular permissions to allow you
|
||||||
|
// to pass only specific session tags. For more information, see Tutorial: Using
|
||||||
|
// Tags for Attribute-Based Access Control (https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// Tag key–value pairs are not case sensitive, but case is preserved. This
|
||||||
|
// means that you cannot have separate Department and department tag keys. Assume
|
||||||
|
// that the user that you are federating has the Department=Marketing tag and
|
||||||
|
// you pass the department=engineering session tag. Department and department
|
||||||
|
// are not saved as separate tags, and the session tag passed in the request
|
||||||
|
// takes precedence over the user tag.
|
||||||
|
//
|
||||||
// Returns awserr.Error for service API and SDK errors. Use runtime type assertions
|
// Returns awserr.Error for service API and SDK errors. Use runtime type assertions
|
||||||
// with awserr.Error's Code and Message methods to get detailed information about
|
// with awserr.Error's Code and Message methods to get detailed information about
|
||||||
// the error.
|
// the error.
|
||||||
|
@ -1000,9 +1158,18 @@ func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *re
|
||||||
// message describes the specific error.
|
// message describes the specific error.
|
||||||
//
|
//
|
||||||
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
|
// * ErrCodePackedPolicyTooLargeException "PackedPolicyTooLarge"
|
||||||
// The request was rejected because the policy document was too large. The error
|
// The request was rejected because the total packed size of the session policies
|
||||||
// message describes how big the policy document is, in packed form, as a percentage
|
// and session tags combined was too large. An AWS conversion compresses the
|
||||||
// of what the API allows.
|
// session policy document, session policy ARNs, and session tags into a packed
|
||||||
|
// binary format that has a separate limit. The error message indicates by percentage
|
||||||
|
// how close the policies and tags are to the upper size limit. For more information,
|
||||||
|
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You could receive this error even though you meet other defined session policy
|
||||||
|
// and session tag limits. For more information, see IAM and STS Entity Character
|
||||||
|
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// * ErrCodeRegionDisabledException "RegionDisabledException"
|
// * ErrCodeRegionDisabledException "RegionDisabledException"
|
||||||
// STS is not activated in the requested region for the account that is being
|
// STS is not activated in the requested region for the account that is being
|
||||||
|
@ -1091,6 +1258,8 @@ func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.
|
||||||
// and Comparing the AWS STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison)
|
// and Comparing the AWS STS API operations (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#stsapi_comparison)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
|
// Session Duration
|
||||||
|
//
|
||||||
// The GetSessionToken operation must be called by using the long-term AWS security
|
// The GetSessionToken operation must be called by using the long-term AWS security
|
||||||
// credentials of the AWS account root user or an IAM user. Credentials that
|
// credentials of the AWS account root user or an IAM user. Credentials that
|
||||||
// are created by IAM users are valid for the duration that you specify. This
|
// are created by IAM users are valid for the duration that you specify. This
|
||||||
|
@ -1099,6 +1268,8 @@ func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.
|
||||||
// based on account credentials can range from 900 seconds (15 minutes) up to
|
// based on account credentials can range from 900 seconds (15 minutes) up to
|
||||||
// 3,600 seconds (1 hour), with a default of 1 hour.
|
// 3,600 seconds (1 hour), with a default of 1 hour.
|
||||||
//
|
//
|
||||||
|
// Permissions
|
||||||
|
//
|
||||||
// The temporary security credentials created by GetSessionToken can be used
|
// The temporary security credentials created by GetSessionToken can be used
|
||||||
// to make API calls to any AWS service with the following exceptions:
|
// to make API calls to any AWS service with the following exceptions:
|
||||||
//
|
//
|
||||||
|
@ -1213,16 +1384,16 @@ type AssumeRoleInput struct {
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// The plain text that you use for both inline and managed session policies
|
// The plain text that you use for both inline and managed session policies
|
||||||
// shouldn't exceed 2048 characters. The JSON policy characters can be any ASCII
|
// can't exceed 2,048 characters. The JSON policy characters can be any ASCII
|
||||||
// character from the space character to the end of the valid character list
|
// character from the space character to the end of the valid character list
|
||||||
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
|
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
|
||||||
// and carriage return (\u000D) characters.
|
// and carriage return (\u000D) characters.
|
||||||
//
|
//
|
||||||
// The characters in this parameter count towards the 2048 character session
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
// policy guideline. However, an AWS conversion compresses the session policies
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
// into a packed binary format that has a separate limit. This is the enforced
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
// limit. The PackedPolicySize response element indicates by percentage how
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
// close the policy is to the upper size limit.
|
// and tags for your request are to the upper size limit.
|
||||||
Policy *string `min:"1" type:"string"`
|
Policy *string `min:"1" type:"string"`
|
||||||
|
|
||||||
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want
|
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want
|
||||||
|
@ -1231,15 +1402,15 @@ type AssumeRoleInput struct {
|
||||||
//
|
//
|
||||||
// This parameter is optional. You can provide up to 10 managed policy ARNs.
|
// This parameter is optional. You can provide up to 10 managed policy ARNs.
|
||||||
// However, the plain text that you use for both inline and managed session
|
// However, the plain text that you use for both inline and managed session
|
||||||
// policies shouldn't exceed 2048 characters. For more information about ARNs,
|
// policies can't exceed 2,048 characters. For more information about ARNs,
|
||||||
// see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
|
// see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
|
||||||
// in the AWS General Reference.
|
// in the AWS General Reference.
|
||||||
//
|
//
|
||||||
// The characters in this parameter count towards the 2048 character session
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
// policy guideline. However, an AWS conversion compresses the session policies
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
// into a packed binary format that has a separate limit. This is the enforced
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
// limit. The PackedPolicySize response element indicates by percentage how
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
// close the policy is to the upper size limit.
|
// and tags for your request are to the upper size limit.
|
||||||
//
|
//
|
||||||
// Passing policies to this operation returns new temporary credentials. The
|
// Passing policies to this operation returns new temporary credentials. The
|
||||||
// resulting session's permissions are the intersection of the role's identity-based
|
// resulting session's permissions are the intersection of the role's identity-based
|
||||||
|
@ -1284,6 +1455,41 @@ type AssumeRoleInput struct {
|
||||||
// also include underscores or any of the following characters: =,.@-
|
// also include underscores or any of the following characters: =,.@-
|
||||||
SerialNumber *string `min:"9" type:"string"`
|
SerialNumber *string `min:"9" type:"string"`
|
||||||
|
|
||||||
|
// A list of session tags that you want to pass. Each session tag consists of
|
||||||
|
// a key name and an associated value. For more information about session tags,
|
||||||
|
// see Tagging AWS STS Sessions (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// This parameter is optional. You can pass up to 50 session tags. The plain
|
||||||
|
// text session tag keys can’t exceed 128 characters, and the values can’t
|
||||||
|
// exceed 256 characters. For these and additional limits, see IAM and STS Character
|
||||||
|
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
|
// and tags for your request are to the upper size limit.
|
||||||
|
//
|
||||||
|
// You can pass a session tag with the same key as a tag that is already attached
|
||||||
|
// to the role. When you do, session tags override a role tag with the same
|
||||||
|
// key.
|
||||||
|
//
|
||||||
|
// Tag key–value pairs are not case sensitive, but case is preserved. This
|
||||||
|
// means that you cannot have separate Department and department tag keys. Assume
|
||||||
|
// that the role has the Department=Marketing tag and you pass the department=engineering
|
||||||
|
// session tag. Department and department are not saved as separate tags, and
|
||||||
|
// the session tag passed in the request takes precedence over the role tag.
|
||||||
|
//
|
||||||
|
// Additionally, if you used temporary credentials to perform this operation,
|
||||||
|
// the new session inherits any transitive session tags from the calling session.
|
||||||
|
// If you pass a session tag with the same key as an inherited tag, the operation
|
||||||
|
// fails. To view the inherited tags for a session, see the AWS CloudTrail logs.
|
||||||
|
// For more information, see Viewing Session Tags in CloudTrail (https://docs.aws.amazon.com/IAM/latest/UserGuide/session-tags.html#id_session-tags_ctlogs)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
Tags []*Tag `type:"list"`
|
||||||
|
|
||||||
// The value provided by the MFA device, if the trust policy of the role being
|
// The value provided by the MFA device, if the trust policy of the role being
|
||||||
// assumed requires MFA (that is, if the policy includes a condition that tests
|
// assumed requires MFA (that is, if the policy includes a condition that tests
|
||||||
// for MFA). If the role being assumed requires MFA and if the TokenCode value
|
// for MFA). If the role being assumed requires MFA and if the TokenCode value
|
||||||
|
@ -1292,6 +1498,19 @@ type AssumeRoleInput struct {
|
||||||
// The format for this parameter, as described by its regex pattern, is a sequence
|
// The format for this parameter, as described by its regex pattern, is a sequence
|
||||||
// of six numeric digits.
|
// of six numeric digits.
|
||||||
TokenCode *string `min:"6" type:"string"`
|
TokenCode *string `min:"6" type:"string"`
|
||||||
|
|
||||||
|
// A list of keys for session tags that you want to set as transitive. If you
|
||||||
|
// set a tag key as transitive, the corresponding key and value passes to subsequent
|
||||||
|
// sessions in a role chain. For more information, see Chaining Roles with Session
|
||||||
|
// Tags (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// This parameter is optional. When you set session tags as transitive, the
|
||||||
|
// session policy and session tags packed binary limit is not affected.
|
||||||
|
//
|
||||||
|
// If you choose not to specify a transitive tag key, then no tags are passed
|
||||||
|
// from this session to any subsequent sessions.
|
||||||
|
TransitiveTagKeys []*string `type:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation
|
// String returns the string representation
|
||||||
|
@ -1344,6 +1563,16 @@ func (s *AssumeRoleInput) Validate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if s.Tags != nil {
|
||||||
|
for i, v := range s.Tags {
|
||||||
|
if v == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := v.Validate(); err != nil {
|
||||||
|
invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Tags", i), err.(request.ErrInvalidParams))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if invalidParams.Len() > 0 {
|
if invalidParams.Len() > 0 {
|
||||||
return invalidParams
|
return invalidParams
|
||||||
|
@ -1393,12 +1622,24 @@ func (s *AssumeRoleInput) SetSerialNumber(v string) *AssumeRoleInput {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTags sets the Tags field's value.
|
||||||
|
func (s *AssumeRoleInput) SetTags(v []*Tag) *AssumeRoleInput {
|
||||||
|
s.Tags = v
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// SetTokenCode sets the TokenCode field's value.
|
// SetTokenCode sets the TokenCode field's value.
|
||||||
func (s *AssumeRoleInput) SetTokenCode(v string) *AssumeRoleInput {
|
func (s *AssumeRoleInput) SetTokenCode(v string) *AssumeRoleInput {
|
||||||
s.TokenCode = &v
|
s.TokenCode = &v
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTransitiveTagKeys sets the TransitiveTagKeys field's value.
|
||||||
|
func (s *AssumeRoleInput) SetTransitiveTagKeys(v []*string) *AssumeRoleInput {
|
||||||
|
s.TransitiveTagKeys = v
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// Contains the response to a successful AssumeRole request, including temporary
|
// Contains the response to a successful AssumeRole request, including temporary
|
||||||
// AWS credentials that can be used to make AWS requests.
|
// AWS credentials that can be used to make AWS requests.
|
||||||
type AssumeRoleOutput struct {
|
type AssumeRoleOutput struct {
|
||||||
|
@ -1418,9 +1659,10 @@ type AssumeRoleOutput struct {
|
||||||
// We strongly recommend that you make no assumptions about the maximum size.
|
// We strongly recommend that you make no assumptions about the maximum size.
|
||||||
Credentials *Credentials `type:"structure"`
|
Credentials *Credentials `type:"structure"`
|
||||||
|
|
||||||
// A percentage value that indicates the size of the policy in packed form.
|
// A percentage value that indicates the packed size of the session policies
|
||||||
// The service rejects any policy with a packed size greater than 100 percent,
|
// and session tags combined passed in the request. The request fails if the
|
||||||
// which means the policy exceeded the allowed space.
|
// packed size is greater than 100 percent, which means the policies and tags
|
||||||
|
// exceeded the allowed space.
|
||||||
PackedPolicySize *int64 `type:"integer"`
|
PackedPolicySize *int64 `type:"integer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1491,16 +1733,16 @@ type AssumeRoleWithSAMLInput struct {
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// The plain text that you use for both inline and managed session policies
|
// The plain text that you use for both inline and managed session policies
|
||||||
// shouldn't exceed 2048 characters. The JSON policy characters can be any ASCII
|
// can't exceed 2,048 characters. The JSON policy characters can be any ASCII
|
||||||
// character from the space character to the end of the valid character list
|
// character from the space character to the end of the valid character list
|
||||||
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
|
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
|
||||||
// and carriage return (\u000D) characters.
|
// and carriage return (\u000D) characters.
|
||||||
//
|
//
|
||||||
// The characters in this parameter count towards the 2048 character session
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
// policy guideline. However, an AWS conversion compresses the session policies
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
// into a packed binary format that has a separate limit. This is the enforced
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
// limit. The PackedPolicySize response element indicates by percentage how
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
// close the policy is to the upper size limit.
|
// and tags for your request are to the upper size limit.
|
||||||
Policy *string `min:"1" type:"string"`
|
Policy *string `min:"1" type:"string"`
|
||||||
|
|
||||||
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want
|
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want
|
||||||
|
@ -1509,15 +1751,15 @@ type AssumeRoleWithSAMLInput struct {
|
||||||
//
|
//
|
||||||
// This parameter is optional. You can provide up to 10 managed policy ARNs.
|
// This parameter is optional. You can provide up to 10 managed policy ARNs.
|
||||||
// However, the plain text that you use for both inline and managed session
|
// However, the plain text that you use for both inline and managed session
|
||||||
// policies shouldn't exceed 2048 characters. For more information about ARNs,
|
// policies can't exceed 2,048 characters. For more information about ARNs,
|
||||||
// see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
|
// see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
|
||||||
// in the AWS General Reference.
|
// in the AWS General Reference.
|
||||||
//
|
//
|
||||||
// The characters in this parameter count towards the 2048 character session
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
// policy guideline. However, an AWS conversion compresses the session policies
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
// into a packed binary format that has a separate limit. This is the enforced
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
// limit. The PackedPolicySize response element indicates by percentage how
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
// close the policy is to the upper size limit.
|
// and tags for your request are to the upper size limit.
|
||||||
//
|
//
|
||||||
// Passing policies to this operation returns new temporary credentials. The
|
// Passing policies to this operation returns new temporary credentials. The
|
||||||
// resulting session's permissions are the intersection of the role's identity-based
|
// resulting session's permissions are the intersection of the role's identity-based
|
||||||
|
@ -1546,7 +1788,7 @@ type AssumeRoleWithSAMLInput struct {
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// SAMLAssertion is a required field
|
// SAMLAssertion is a required field
|
||||||
SAMLAssertion *string `min:"4" type:"string" required:"true"`
|
SAMLAssertion *string `min:"4" type:"string" required:"true" sensitive:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation
|
// String returns the string representation
|
||||||
|
@ -1673,9 +1915,10 @@ type AssumeRoleWithSAMLOutput struct {
|
||||||
// ) )
|
// ) )
|
||||||
NameQualifier *string `type:"string"`
|
NameQualifier *string `type:"string"`
|
||||||
|
|
||||||
// A percentage value that indicates the size of the policy in packed form.
|
// A percentage value that indicates the packed size of the session policies
|
||||||
// The service rejects any policy with a packed size greater than 100 percent,
|
// and session tags combined passed in the request. The request fails if the
|
||||||
// which means the policy exceeded the allowed space.
|
// packed size is greater than 100 percent, which means the policies and tags
|
||||||
|
// exceeded the allowed space.
|
||||||
PackedPolicySize *int64 `type:"integer"`
|
PackedPolicySize *int64 `type:"integer"`
|
||||||
|
|
||||||
// The value of the NameID element in the Subject element of the SAML assertion.
|
// The value of the NameID element in the Subject element of the SAML assertion.
|
||||||
|
@ -1786,16 +2029,16 @@ type AssumeRoleWithWebIdentityInput struct {
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// The plain text that you use for both inline and managed session policies
|
// The plain text that you use for both inline and managed session policies
|
||||||
// shouldn't exceed 2048 characters. The JSON policy characters can be any ASCII
|
// can't exceed 2,048 characters. The JSON policy characters can be any ASCII
|
||||||
// character from the space character to the end of the valid character list
|
// character from the space character to the end of the valid character list
|
||||||
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
|
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
|
||||||
// and carriage return (\u000D) characters.
|
// and carriage return (\u000D) characters.
|
||||||
//
|
//
|
||||||
// The characters in this parameter count towards the 2048 character session
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
// policy guideline. However, an AWS conversion compresses the session policies
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
// into a packed binary format that has a separate limit. This is the enforced
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
// limit. The PackedPolicySize response element indicates by percentage how
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
// close the policy is to the upper size limit.
|
// and tags for your request are to the upper size limit.
|
||||||
Policy *string `min:"1" type:"string"`
|
Policy *string `min:"1" type:"string"`
|
||||||
|
|
||||||
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want
|
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want
|
||||||
|
@ -1804,15 +2047,15 @@ type AssumeRoleWithWebIdentityInput struct {
|
||||||
//
|
//
|
||||||
// This parameter is optional. You can provide up to 10 managed policy ARNs.
|
// This parameter is optional. You can provide up to 10 managed policy ARNs.
|
||||||
// However, the plain text that you use for both inline and managed session
|
// However, the plain text that you use for both inline and managed session
|
||||||
// policies shouldn't exceed 2048 characters. For more information about ARNs,
|
// policies can't exceed 2,048 characters. For more information about ARNs,
|
||||||
// see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
|
// see Amazon Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
|
||||||
// in the AWS General Reference.
|
// in the AWS General Reference.
|
||||||
//
|
//
|
||||||
// The characters in this parameter count towards the 2048 character session
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
// policy guideline. However, an AWS conversion compresses the session policies
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
// into a packed binary format that has a separate limit. This is the enforced
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
// limit. The PackedPolicySize response element indicates by percentage how
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
// close the policy is to the upper size limit.
|
// and tags for your request are to the upper size limit.
|
||||||
//
|
//
|
||||||
// Passing policies to this operation returns new temporary credentials. The
|
// Passing policies to this operation returns new temporary credentials. The
|
||||||
// resulting session's permissions are the intersection of the role's identity-based
|
// resulting session's permissions are the intersection of the role's identity-based
|
||||||
|
@ -1857,7 +2100,7 @@ type AssumeRoleWithWebIdentityInput struct {
|
||||||
// the application makes an AssumeRoleWithWebIdentity call.
|
// the application makes an AssumeRoleWithWebIdentity call.
|
||||||
//
|
//
|
||||||
// WebIdentityToken is a required field
|
// WebIdentityToken is a required field
|
||||||
WebIdentityToken *string `min:"4" type:"string" required:"true"`
|
WebIdentityToken *string `min:"4" type:"string" required:"true" sensitive:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation
|
// String returns the string representation
|
||||||
|
@ -1983,9 +2226,10 @@ type AssumeRoleWithWebIdentityOutput struct {
|
||||||
// We strongly recommend that you make no assumptions about the maximum size.
|
// We strongly recommend that you make no assumptions about the maximum size.
|
||||||
Credentials *Credentials `type:"structure"`
|
Credentials *Credentials `type:"structure"`
|
||||||
|
|
||||||
// A percentage value that indicates the size of the policy in packed form.
|
// A percentage value that indicates the packed size of the session policies
|
||||||
// The service rejects any policy with a packed size greater than 100 percent,
|
// and session tags combined passed in the request. The request fails if the
|
||||||
// which means the policy exceeded the allowed space.
|
// packed size is greater than 100 percent, which means the policies and tags
|
||||||
|
// exceeded the allowed space.
|
||||||
PackedPolicySize *int64 `type:"integer"`
|
PackedPolicySize *int64 `type:"integer"`
|
||||||
|
|
||||||
// The issuing authority of the web identity token presented. For OpenID Connect
|
// The issuing authority of the web identity token presented. For OpenID Connect
|
||||||
|
@ -2057,7 +2301,7 @@ type AssumedRoleUser struct {
|
||||||
// The ARN of the temporary security credentials that are returned from the
|
// The ARN of the temporary security credentials that are returned from the
|
||||||
// AssumeRole action. For more information about ARNs and how to use them in
|
// AssumeRole action. For more information about ARNs and how to use them in
|
||||||
// policies, see IAM Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html)
|
// policies, see IAM Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html)
|
||||||
// in Using IAM.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// Arn is a required field
|
// Arn is a required field
|
||||||
Arn *string `min:"20" type:"string" required:"true"`
|
Arn *string `min:"20" type:"string" required:"true"`
|
||||||
|
@ -2225,7 +2469,7 @@ type FederatedUser struct {
|
||||||
// The ARN that specifies the federated user that is associated with the credentials.
|
// The ARN that specifies the federated user that is associated with the credentials.
|
||||||
// For more information about ARNs and how to use them in policies, see IAM
|
// For more information about ARNs and how to use them in policies, see IAM
|
||||||
// Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html)
|
// Identifiers (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html)
|
||||||
// in Using IAM.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// Arn is a required field
|
// Arn is a required field
|
||||||
Arn *string `min:"20" type:"string" required:"true"`
|
Arn *string `min:"20" type:"string" required:"true"`
|
||||||
|
@ -2265,7 +2509,7 @@ type GetAccessKeyInfoInput struct {
|
||||||
// The identifier of an access key.
|
// The identifier of an access key.
|
||||||
//
|
//
|
||||||
// This parameter allows (through its regex pattern) a string of characters
|
// This parameter allows (through its regex pattern) a string of characters
|
||||||
// that can consist of any upper- or lowercased letter or digit.
|
// that can consist of any upper- or lowercase letter or digit.
|
||||||
//
|
//
|
||||||
// AccessKeyId is a required field
|
// AccessKeyId is a required field
|
||||||
AccessKeyId *string `min:"16" type:"string" required:"true"`
|
AccessKeyId *string `min:"16" type:"string" required:"true"`
|
||||||
|
@ -2418,10 +2662,7 @@ type GetFederationTokenInput struct {
|
||||||
// use as managed session policies.
|
// use as managed session policies.
|
||||||
//
|
//
|
||||||
// This parameter is optional. However, if you do not pass any session policies,
|
// This parameter is optional. However, if you do not pass any session policies,
|
||||||
// then the resulting federated user session has no permissions. The only exception
|
// then the resulting federated user session has no permissions.
|
||||||
// is when the credentials are used to access a resource that has a resource-based
|
|
||||||
// policy that specifically references the federated user session in the Principal
|
|
||||||
// element of the policy.
|
|
||||||
//
|
//
|
||||||
// When you pass session policies, the session permissions are the intersection
|
// When you pass session policies, the session permissions are the intersection
|
||||||
// of the IAM user policies and the session policies that you pass. This gives
|
// of the IAM user policies and the session policies that you pass. This gives
|
||||||
|
@ -2431,17 +2672,23 @@ type GetFederationTokenInput struct {
|
||||||
// Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
// Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
|
// The resulting credentials can be used to access a resource that has a resource-based
|
||||||
|
// policy. If that policy specifically references the federated user session
|
||||||
|
// in the Principal element of the policy, the session has the permissions allowed
|
||||||
|
// by the policy. These permissions are granted in addition to the permissions
|
||||||
|
// that are granted by the session policies.
|
||||||
|
//
|
||||||
// The plain text that you use for both inline and managed session policies
|
// The plain text that you use for both inline and managed session policies
|
||||||
// shouldn't exceed 2048 characters. The JSON policy characters can be any ASCII
|
// can't exceed 2,048 characters. The JSON policy characters can be any ASCII
|
||||||
// character from the space character to the end of the valid character list
|
// character from the space character to the end of the valid character list
|
||||||
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
|
// (\u0020 through \u00FF). It can also include the tab (\u0009), linefeed (\u000A),
|
||||||
// and carriage return (\u000D) characters.
|
// and carriage return (\u000D) characters.
|
||||||
//
|
//
|
||||||
// The characters in this parameter count towards the 2048 character session
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
// policy guideline. However, an AWS conversion compresses the session policies
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
// into a packed binary format that has a separate limit. This is the enforced
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
// limit. The PackedPolicySize response element indicates by percentage how
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
// close the policy is to the upper size limit.
|
// and tags for your request are to the upper size limit.
|
||||||
Policy *string `min:"1" type:"string"`
|
Policy *string `min:"1" type:"string"`
|
||||||
|
|
||||||
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want
|
// The Amazon Resource Names (ARNs) of the IAM managed policies that you want
|
||||||
|
@ -2452,16 +2699,13 @@ type GetFederationTokenInput struct {
|
||||||
// to this operation. You can pass a single JSON policy document to use as an
|
// to this operation. You can pass a single JSON policy document to use as an
|
||||||
// inline session policy. You can also specify up to 10 managed policies to
|
// inline session policy. You can also specify up to 10 managed policies to
|
||||||
// use as managed session policies. The plain text that you use for both inline
|
// use as managed session policies. The plain text that you use for both inline
|
||||||
// and managed session policies shouldn't exceed 2048 characters. You can provide
|
// and managed session policies can't exceed 2,048 characters. You can provide
|
||||||
// up to 10 managed policy ARNs. For more information about ARNs, see Amazon
|
// up to 10 managed policy ARNs. For more information about ARNs, see Amazon
|
||||||
// Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
|
// Resource Names (ARNs) and AWS Service Namespaces (https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
|
||||||
// in the AWS General Reference.
|
// in the AWS General Reference.
|
||||||
//
|
//
|
||||||
// This parameter is optional. However, if you do not pass any session policies,
|
// This parameter is optional. However, if you do not pass any session policies,
|
||||||
// then the resulting federated user session has no permissions. The only exception
|
// then the resulting federated user session has no permissions.
|
||||||
// is when the credentials are used to access a resource that has a resource-based
|
|
||||||
// policy that specifically references the federated user session in the Principal
|
|
||||||
// element of the policy.
|
|
||||||
//
|
//
|
||||||
// When you pass session policies, the session permissions are the intersection
|
// When you pass session policies, the session permissions are the intersection
|
||||||
// of the IAM user policies and the session policies that you pass. This gives
|
// of the IAM user policies and the session policies that you pass. This gives
|
||||||
|
@ -2471,12 +2715,46 @@ type GetFederationTokenInput struct {
|
||||||
// Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
// Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
|
||||||
// in the IAM User Guide.
|
// in the IAM User Guide.
|
||||||
//
|
//
|
||||||
// The characters in this parameter count towards the 2048 character session
|
// The resulting credentials can be used to access a resource that has a resource-based
|
||||||
// policy guideline. However, an AWS conversion compresses the session policies
|
// policy. If that policy specifically references the federated user session
|
||||||
// into a packed binary format that has a separate limit. This is the enforced
|
// in the Principal element of the policy, the session has the permissions allowed
|
||||||
// limit. The PackedPolicySize response element indicates by percentage how
|
// by the policy. These permissions are granted in addition to the permissions
|
||||||
// close the policy is to the upper size limit.
|
// that are granted by the session policies.
|
||||||
|
//
|
||||||
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
|
// and tags for your request are to the upper size limit.
|
||||||
PolicyArns []*PolicyDescriptorType `type:"list"`
|
PolicyArns []*PolicyDescriptorType `type:"list"`
|
||||||
|
|
||||||
|
// A list of session tags. Each session tag consists of a key name and an associated
|
||||||
|
// value. For more information about session tags, see Passing Session Tags
|
||||||
|
// in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// This parameter is optional. You can pass up to 50 session tags. The plain
|
||||||
|
// text session tag keys can’t exceed 128 characters and the values can’t
|
||||||
|
// exceed 256 characters. For these and additional limits, see IAM and STS Character
|
||||||
|
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// An AWS conversion compresses the passed session policies and session tags
|
||||||
|
// into a packed binary format that has a separate limit. Your request can fail
|
||||||
|
// for this limit even if your plain text meets the other requirements. The
|
||||||
|
// PackedPolicySize response element indicates by percentage how close the policies
|
||||||
|
// and tags for your request are to the upper size limit.
|
||||||
|
//
|
||||||
|
// You can pass a session tag with the same key as a tag that is already attached
|
||||||
|
// to the user you are federating. When you do, session tags override a user
|
||||||
|
// tag with the same key.
|
||||||
|
//
|
||||||
|
// Tag key–value pairs are not case sensitive, but case is preserved. This
|
||||||
|
// means that you cannot have separate Department and department tag keys. Assume
|
||||||
|
// that the role has the Department=Marketing tag and you pass the department=engineering
|
||||||
|
// session tag. Department and department are not saved as separate tags, and
|
||||||
|
// the session tag passed in the request takes precedence over the role tag.
|
||||||
|
Tags []*Tag `type:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation
|
// String returns the string representation
|
||||||
|
@ -2514,6 +2792,16 @@ func (s *GetFederationTokenInput) Validate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if s.Tags != nil {
|
||||||
|
for i, v := range s.Tags {
|
||||||
|
if v == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := v.Validate(); err != nil {
|
||||||
|
invalidParams.AddNested(fmt.Sprintf("%s[%v]", "Tags", i), err.(request.ErrInvalidParams))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if invalidParams.Len() > 0 {
|
if invalidParams.Len() > 0 {
|
||||||
return invalidParams
|
return invalidParams
|
||||||
|
@ -2545,6 +2833,12 @@ func (s *GetFederationTokenInput) SetPolicyArns(v []*PolicyDescriptorType) *GetF
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTags sets the Tags field's value.
|
||||||
|
func (s *GetFederationTokenInput) SetTags(v []*Tag) *GetFederationTokenInput {
|
||||||
|
s.Tags = v
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// Contains the response to a successful GetFederationToken request, including
|
// Contains the response to a successful GetFederationToken request, including
|
||||||
// temporary AWS credentials that can be used to make AWS requests.
|
// temporary AWS credentials that can be used to make AWS requests.
|
||||||
type GetFederationTokenOutput struct {
|
type GetFederationTokenOutput struct {
|
||||||
|
@ -2563,9 +2857,10 @@ type GetFederationTokenOutput struct {
|
||||||
// an Amazon S3 bucket policy.
|
// an Amazon S3 bucket policy.
|
||||||
FederatedUser *FederatedUser `type:"structure"`
|
FederatedUser *FederatedUser `type:"structure"`
|
||||||
|
|
||||||
// A percentage value indicating the size of the policy in packed form. The
|
// A percentage value that indicates the packed size of the session policies
|
||||||
// service rejects policies for which the packed size is greater than 100 percent
|
// and session tags combined passed in the request. The request fails if the
|
||||||
// of the allowed value.
|
// packed size is greater than 100 percent, which means the policies and tags
|
||||||
|
// exceeded the allowed space.
|
||||||
PackedPolicySize *int64 `type:"integer"`
|
PackedPolicySize *int64 `type:"integer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2748,3 +3043,73 @@ func (s *PolicyDescriptorType) SetArn(v string) *PolicyDescriptorType {
|
||||||
s.Arn = &v
|
s.Arn = &v
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// You can pass custom key-value pair attributes when you assume a role or federate
|
||||||
|
// a user. These are called session tags. You can then use the session tags
|
||||||
|
// to control access to resources. For more information, see Tagging AWS STS
|
||||||
|
// Sessions (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
type Tag struct {
|
||||||
|
_ struct{} `type:"structure"`
|
||||||
|
|
||||||
|
// The key for a session tag.
|
||||||
|
//
|
||||||
|
// You can pass up to 50 session tags. The plain text session tag keys can’t
|
||||||
|
// exceed 128 characters. For these and additional limits, see IAM and STS Character
|
||||||
|
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// Key is a required field
|
||||||
|
Key *string `min:"1" type:"string" required:"true"`
|
||||||
|
|
||||||
|
// The value for a session tag.
|
||||||
|
//
|
||||||
|
// You can pass up to 50 session tags. The plain text session tag values can’t
|
||||||
|
// exceed 256 characters. For these and additional limits, see IAM and STS Character
|
||||||
|
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html#reference_iam-limits-entity-length)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// Value is a required field
|
||||||
|
Value *string `type:"string" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation
|
||||||
|
func (s Tag) String() string {
|
||||||
|
return awsutil.Prettify(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GoString returns the string representation
|
||||||
|
func (s Tag) GoString() string {
|
||||||
|
return s.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate inspects the fields of the type to determine if they are valid.
|
||||||
|
func (s *Tag) Validate() error {
|
||||||
|
invalidParams := request.ErrInvalidParams{Context: "Tag"}
|
||||||
|
if s.Key == nil {
|
||||||
|
invalidParams.Add(request.NewErrParamRequired("Key"))
|
||||||
|
}
|
||||||
|
if s.Key != nil && len(*s.Key) < 1 {
|
||||||
|
invalidParams.Add(request.NewErrParamMinLen("Key", 1))
|
||||||
|
}
|
||||||
|
if s.Value == nil {
|
||||||
|
invalidParams.Add(request.NewErrParamRequired("Value"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if invalidParams.Len() > 0 {
|
||||||
|
return invalidParams
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetKey sets the Key field's value.
|
||||||
|
func (s *Tag) SetKey(v string) *Tag {
|
||||||
|
s.Key = &v
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValue sets the Value field's value.
|
||||||
|
func (s *Tag) SetValue(v string) *Tag {
|
||||||
|
s.Value = &v
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@ const (
|
||||||
// ErrCodeIDPCommunicationErrorException for service response error code
|
// ErrCodeIDPCommunicationErrorException for service response error code
|
||||||
// "IDPCommunicationError".
|
// "IDPCommunicationError".
|
||||||
//
|
//
|
||||||
// The request could not be fulfilled because the non-AWS identity provider
|
// The request could not be fulfilled because the identity provider (IDP) that
|
||||||
// (IDP) that was asked to verify the incoming identity token could not be reached.
|
// was asked to verify the incoming identity token could not be reached. This
|
||||||
// This is often a transient error caused by network conditions. Retry the request
|
// is often a transient error caused by network conditions. Retry the request
|
||||||
// a limited number of times so that you don't exceed the request rate. If the
|
// a limited number of times so that you don't exceed the request rate. If the
|
||||||
// error persists, the non-AWS identity provider might be down or not responding.
|
// error persists, the identity provider might be down or not responding.
|
||||||
ErrCodeIDPCommunicationErrorException = "IDPCommunicationError"
|
ErrCodeIDPCommunicationErrorException = "IDPCommunicationError"
|
||||||
|
|
||||||
// ErrCodeIDPRejectedClaimException for service response error code
|
// ErrCodeIDPRejectedClaimException for service response error code
|
||||||
|
@ -56,9 +56,18 @@ const (
|
||||||
// ErrCodePackedPolicyTooLargeException for service response error code
|
// ErrCodePackedPolicyTooLargeException for service response error code
|
||||||
// "PackedPolicyTooLarge".
|
// "PackedPolicyTooLarge".
|
||||||
//
|
//
|
||||||
// The request was rejected because the policy document was too large. The error
|
// The request was rejected because the total packed size of the session policies
|
||||||
// message describes how big the policy document is, in packed form, as a percentage
|
// and session tags combined was too large. An AWS conversion compresses the
|
||||||
// of what the API allows.
|
// session policy document, session policy ARNs, and session tags into a packed
|
||||||
|
// binary format that has a separate limit. The error message indicates by percentage
|
||||||
|
// how close the policies and tags are to the upper size limit. For more information,
|
||||||
|
// see Passing Session Tags in STS (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
|
//
|
||||||
|
// You could receive this error even though you meet other defined session policy
|
||||||
|
// and session tag limits. For more information, see IAM and STS Entity Character
|
||||||
|
// Limits (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
|
||||||
|
// in the IAM User Guide.
|
||||||
ErrCodePackedPolicyTooLargeException = "PackedPolicyTooLarge"
|
ErrCodePackedPolicyTooLargeException = "PackedPolicyTooLarge"
|
||||||
|
|
||||||
// ErrCodeRegionDisabledException for service response error code
|
// ErrCodeRegionDisabledException for service response error code
|
||||||
|
|
|
@ -31,7 +31,7 @@ var initRequest func(*request.Request)
|
||||||
const (
|
const (
|
||||||
ServiceName = "sts" // Name of service.
|
ServiceName = "sts" // Name of service.
|
||||||
EndpointsID = ServiceName // ID to lookup a service endpoint with.
|
EndpointsID = ServiceName // ID to lookup a service endpoint with.
|
||||||
ServiceID = "STS" // ServiceID is a unique identifer of a specific service.
|
ServiceID = "STS" // ServiceID is a unique identifier of a specific service.
|
||||||
)
|
)
|
||||||
|
|
||||||
// New creates a new instance of the STS client with a session.
|
// New creates a new instance of the STS client with a session.
|
||||||
|
@ -39,6 +39,8 @@ const (
|
||||||
// aws.Config parameter to add your extra config.
|
// aws.Config parameter to add your extra config.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
|
// mySession := session.Must(session.NewSession())
|
||||||
|
//
|
||||||
// // Create a STS client from just a session.
|
// // Create a STS client from just a session.
|
||||||
// svc := sts.New(mySession)
|
// svc := sts.New(mySession)
|
||||||
//
|
//
|
||||||
|
@ -46,11 +48,11 @@ const (
|
||||||
// svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
// svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
|
||||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS {
|
func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS {
|
||||||
c := p.ClientConfig(EndpointsID, cfgs...)
|
c := p.ClientConfig(EndpointsID, cfgs...)
|
||||||
return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion, c.SigningName)
|
return newClient(*c.Config, c.Handlers, c.PartitionID, c.Endpoint, c.SigningRegion, c.SigningName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newClient creates, initializes and returns a new service client instance.
|
// newClient creates, initializes and returns a new service client instance.
|
||||||
func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion, signingName string) *STS {
|
func newClient(cfg aws.Config, handlers request.Handlers, partitionID, endpoint, signingRegion, signingName string) *STS {
|
||||||
svc := &STS{
|
svc := &STS{
|
||||||
Client: client.New(
|
Client: client.New(
|
||||||
cfg,
|
cfg,
|
||||||
|
@ -59,6 +61,7 @@ func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegio
|
||||||
ServiceID: ServiceID,
|
ServiceID: ServiceID,
|
||||||
SigningName: signingName,
|
SigningName: signingName,
|
||||||
SigningRegion: signingRegion,
|
SigningRegion: signingRegion,
|
||||||
|
PartitionID: partitionID,
|
||||||
Endpoint: endpoint,
|
Endpoint: endpoint,
|
||||||
APIVersion: "2011-06-15",
|
APIVersion: "2011-06-15",
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,6 +9,13 @@
|
||||||
|
|
||||||
# go fmt will enforce this, but in case a user has not called "go fmt" allow GIT to catch this:
|
# go fmt will enforce this, but in case a user has not called "go fmt" allow GIT to catch this:
|
||||||
*.go text eol=lf core.whitespace whitespace=indent-with-non-tab,trailing-space,tabwidth=4
|
*.go text eol=lf core.whitespace whitespace=indent-with-non-tab,trailing-space,tabwidth=4
|
||||||
|
go.mod text eol=lf
|
||||||
|
go.sum text eol=lf
|
||||||
|
|
||||||
|
*.txt text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.tpl text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.htm text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.html text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.md text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
*.yml text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
*.yml text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
.git* text eol=auto core.whitespace whitespace=trailing-space
|
.git* text eol=auto core.whitespace whitespace=trailing-space
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue