mirror of https://github.com/kubernetes/kops.git
Merge pull request #805 from justinsb/aws_sdk_152
Update aws-sdk-go to 1.5.2
This commit is contained in:
commit
181aa16555
|
|
@ -1 +1 @@
|
|||
Subproject commit 5fbcfa00ec930ccaa641b404adece72bf96e3667
|
||||
Subproject commit 45d21707a58c6bfdf7cf12197d054769d88f7d13
|
||||
|
|
@ -1696,3 +1696,213 @@ func (m *MockEC2) UnmonitorInstances(*ec2.UnmonitorInstancesInput) (*ec2.Unmonit
|
|||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) AcceptReservedInstancesExchangeQuoteRequest(*ec2.AcceptReservedInstancesExchangeQuoteInput) (*request.Request, *ec2.AcceptReservedInstancesExchangeQuoteOutput) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) AcceptReservedInstancesExchangeQuote(*ec2.AcceptReservedInstancesExchangeQuoteInput) (*ec2.AcceptReservedInstancesExchangeQuoteOutput, error) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) DescribeHostReservationOfferingsRequest(*ec2.DescribeHostReservationOfferingsInput) (*request.Request, *ec2.DescribeHostReservationOfferingsOutput) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) DescribeHostReservationOfferings(*ec2.DescribeHostReservationOfferingsInput) (*ec2.DescribeHostReservationOfferingsOutput, error) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) DescribeHostReservationsRequest(*ec2.DescribeHostReservationsInput) (*request.Request, *ec2.DescribeHostReservationsOutput) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) DescribeHostReservations(*ec2.DescribeHostReservationsInput) (*ec2.DescribeHostReservationsOutput, error) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) GetHostReservationPurchasePreviewRequest(*ec2.GetHostReservationPurchasePreviewInput) (*request.Request, *ec2.GetHostReservationPurchasePreviewOutput) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) GetHostReservationPurchasePreview(*ec2.GetHostReservationPurchasePreviewInput) (*ec2.GetHostReservationPurchasePreviewOutput, error) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) PurchaseHostReservationRequest(*ec2.PurchaseHostReservationInput) (*request.Request, *ec2.PurchaseHostReservationOutput) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) PurchaseHostReservation(*ec2.PurchaseHostReservationInput) (*ec2.PurchaseHostReservationOutput, error) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) GetReservedInstancesExchangeQuoteRequest(*ec2.GetReservedInstancesExchangeQuoteInput) (*request.Request, *ec2.GetReservedInstancesExchangeQuoteOutput) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) GetReservedInstancesExchangeQuote(*ec2.GetReservedInstancesExchangeQuoteInput) (*ec2.GetReservedInstancesExchangeQuoteOutput, error) {
|
||||
panic("Not implemented")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilBundleTaskComplete(*ec2.DescribeBundleTasksInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilConversionTaskCancelled(*ec2.DescribeConversionTasksInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilConversionTaskCompleted(*ec2.DescribeConversionTasksInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilConversionTaskDeleted(*ec2.DescribeConversionTasksInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilCustomerGatewayAvailable(*ec2.DescribeCustomerGatewaysInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilExportTaskCancelled(*ec2.DescribeExportTasksInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilExportTaskCompleted(*ec2.DescribeExportTasksInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilImageAvailable(*ec2.DescribeImagesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilImageExists(*ec2.DescribeImagesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilInstanceExists(*ec2.DescribeInstancesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilInstanceRunning(*ec2.DescribeInstancesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilInstanceStatusOk(*ec2.DescribeInstanceStatusInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilInstanceStopped(*ec2.DescribeInstancesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilInstanceTerminated(*ec2.DescribeInstancesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilKeyPairExists(*ec2.DescribeKeyPairsInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilNatGatewayAvailable(*ec2.DescribeNatGatewaysInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilNetworkInterfaceAvailable(*ec2.DescribeNetworkInterfacesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilPasswordDataAvailable(*ec2.GetPasswordDataInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilSnapshotCompleted(*ec2.DescribeSnapshotsInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilSpotInstanceRequestFulfilled(*ec2.DescribeSpotInstanceRequestsInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilSubnetAvailable(*ec2.DescribeSubnetsInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilSystemStatusOk(*ec2.DescribeInstanceStatusInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilVolumeAvailable(*ec2.DescribeVolumesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilVolumeDeleted(*ec2.DescribeVolumesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilVolumeInUse(*ec2.DescribeVolumesInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilVpcAvailable(*ec2.DescribeVpcsInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilVpcExists(*ec2.DescribeVpcsInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilVpcPeeringConnectionExists(*ec2.DescribeVpcPeeringConnectionsInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilVpnConnectionAvailable(*ec2.DescribeVpnConnectionsInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockEC2) WaitUntilVpnConnectionDeleted(*ec2.DescribeVpnConnectionsInput) error {
|
||||
panic("Not implemented")
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ go:
|
|||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- tip
|
||||
|
||||
# Use Go 1.5's vendoring experiment for 1.5 tests. 1.4 tests will use the tip of the dependencies repo.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
Release v1.5.2 (2016-11-03)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
`service/directconnect`: Updates service API and documentation
|
||||
|
||||
Release v1.5.1 (2016-11-02)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
`service/email`: Updates service API and documentation
|
||||
|
||||
Release v1.5.0 (2016-11-01)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
`service/cloudformation`: Updates service API and documentation
|
||||
`service/ecr`: Updates service paginators
|
||||
|
||||
SDK Feature Updates
|
||||
---
|
||||
* `private/model/api`: Add generated setters for API parameters (#918)
|
||||
* Adds setters to the SDK's API parameter types, and are a convenience method that reduce the need to use `aws.String` and like utility.
|
||||
|
||||
Release v1.4.22 (2016-10-25)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/elasticloadbalancingv2`: Updates service documentation.
|
||||
* `service/autoscaling`: Updates service documentation.
|
||||
|
||||
Release v1.4.21 (2016-10-24)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/sms`: AWS Server Migration Service (SMS) is an agentless service which makes it easier and faster for you to migrate thousands of on-premises workloads to AWS. AWS SMS allows you to automate, schedule, and track incremental replications of live server volumes, making it easier for you to coordinate large-scale server migrations.
|
||||
* `service/ecs`: Updates documentation.
|
||||
|
||||
SDK Feature Updates
|
||||
---
|
||||
* `private/models/api`: Improve code generation of documentation.
|
||||
|
||||
Release v1.4.20 (2016-10-20)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/budgets`: Adds new service, AWS Budgets.
|
||||
* `service/waf`: Updates service documentation.
|
||||
|
||||
Release v1.4.19 (2016-10-18)
|
||||
===
|
||||
|
||||
Service Client Updates
|
||||
---
|
||||
* `service/cloudfront`: Updates service API and documentation.
|
||||
* Ability to use Amazon CloudFront to deliver your content both via IPv6 and IPv4 using HTTP/HTTPS.
|
||||
* `service/configservice`: Update service API and documentation.
|
||||
* `service/iot`: Updates service API and documentation.
|
||||
* `service/kinesisanalytics`: Updates service API and documentation.
|
||||
* Whenever Amazon Kinesis Analytics is not able to detect schema for the given streaming source on DiscoverInputSchema API, we would return the raw records that was sampled to detect the schema.
|
||||
* `service/rds`: Updates service API and documentation.
|
||||
* Amazon Aurora integrates with other AWS services to allow you to extend your Aurora DB cluster to utilize other capabilities in the AWS cloud. Permission to access other AWS services is granted by creating an IAM role with the necessary permissions, and then associating the role with your DB cluster.
|
||||
|
||||
SDK Feature Updates
|
||||
---
|
||||
* `service/dynamodb/dynamodbattribute`: Add UnmarshalListOfMaps #897
|
||||
* Adds support for unmarshalling a list of maps. This is useful for unmarshalling the DynamoDB AttributeValue list of maps returned by APIs like Query and Scan.
|
||||
|
||||
Release v1.4.18 (2016-10-17)
|
||||
===
|
||||
|
||||
Service Model Updates
|
||||
---
|
||||
* `service/route53`: Updates service API and documentation.
|
||||
|
||||
Release v1.4.17
|
||||
===
|
||||
|
||||
Service Model Updates
|
||||
---
|
||||
* `service/acm`: Update service API, and documentation.
|
||||
* This change allows users to import third-party SSL/TLS certificates into ACM.
|
||||
* `service/elasticbeanstalk`: Update service API, documentation, and pagination.
|
||||
* Elastic Beanstalk DescribeApplicationVersions API is being updated to support pagination.
|
||||
* `service/gamelift`: Update service API, and documentation.
|
||||
* New APIs to protect game developer resource (builds, alias, fleets, instances, game sessions and player sessions) against abuse.
|
||||
|
||||
SDK Features
|
||||
---
|
||||
* `service/s3`: Add support for accelerate with dualstack [#887](https://github.com/aws/aws-sdk-go/issues/887)
|
||||
|
||||
Release v1.4.16 (2016-10-13)
|
||||
===
|
||||
|
||||
Service Model Updates
|
||||
---
|
||||
* `service/ecr`: Update Amazon EC2 Container Registry service model
|
||||
* DescribeImages is a new api used to expose image metadata which today includes image size and image creation timestamp.
|
||||
* `service/elasticache`: Update Amazon ElastiCache service model
|
||||
* Elasticache is launching a new major engine release of Redis, 3.2 (providing stability updates and new command sets over 2.8), as well as ElasticSupport for enabling Redis Cluster in 3.2, which provides support for multiple node groups to horizontally scale data, as well as superior engine failover capabilities
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* `aws/session`: Skip shared config on read errors [#883](https://github.com/aws/aws-sdk-go/issues/883)
|
||||
* `aws/signer/v4`: Add support for URL.EscapedPath to signer [#885](https://github.com/aws/aws-sdk-go/issues/885)
|
||||
|
||||
SDK Features
|
||||
---
|
||||
* `private/model/api`: Add docs for errors to API operations [#881](https://github.com/aws/aws-sdk-go/issues/881)
|
||||
* `private/model/api`: Improve field and waiter doc strings [#879](https://github.com/aws/aws-sdk-go/issues/879)
|
||||
* `service/dynamodb/dynamodbattribute`: Allow multiple struct tag elements [#886](https://github.com/aws/aws-sdk-go/issues/886)
|
||||
* Add build tags to internal SDK tools [#880](https://github.com/aws/aws-sdk-go/issues/880)
|
||||
|
||||
Release v1.4.15 (2016-10-06)
|
||||
===
|
||||
|
||||
Service Model Updates
|
||||
---
|
||||
* `service/cognitoidentityprovider`: Update Amazon Cognito Identity Provider service model
|
||||
* `service/devicefarm`: Update AWS Device Farm documentation
|
||||
* `service/opsworks`: Update AWS OpsWorks service model
|
||||
* `service/s3`: Update Amazon Simple Storage Service model
|
||||
* `service/waf`: Update AWS WAF service model
|
||||
|
||||
SDK Bug Fixes
|
||||
---
|
||||
* `aws/request`: Fix HTTP Request Body race condition [#874](https://github.com/aws/aws-sdk-go/issues/874)
|
||||
|
||||
SDK Feature Updates
|
||||
---
|
||||
* `aws/ec2metadata`: Add support for EC2 User Data [#872](https://github.com/aws/aws-sdk-go/issues/872)
|
||||
* `aws/signer/v4`: Remove logic determining if request needs to be resigned [#876](https://github.com/aws/aws-sdk-go/issues/876)
|
||||
|
||||
Release v1.4.14 (2016-09-29)
|
||||
===
|
||||
* `service/ec2`: api, documentation, and paginators updates.
|
||||
* `service/s3`: api and documentation updates.
|
||||
|
||||
Release v1.4.13 (2016-09-27)
|
||||
===
|
||||
* `service/codepipeline`: documentation updates.
|
||||
* `service/cloudformation`: api and documentation updates.
|
||||
* `service/kms`: documentation updates.
|
||||
* `service/elasticfilesystem`: documentation updates.
|
||||
* `service/snowball`: documentation updates.
|
||||
|
|
@ -5,10 +5,13 @@ LINTIGNORESTUTTER='service/[^/]+/(api|service)\.go:.+(and that stutters)'
|
|||
LINTIGNOREINFLECT='service/[^/]+/(api|service)\.go:.+method .+ should be '
|
||||
LINTIGNOREINFLECTS3UPLOAD='service/s3/s3manager/upload\.go:.+struct field SSEKMSKeyId should be '
|
||||
LINTIGNOREDEPS='vendor/.+\.go'
|
||||
UNIT_TEST_TAGS="example codegen"
|
||||
|
||||
SDK_WITH_VENDOR_PKGS=$(shell go list ./... | grep -v "/vendor/src")
|
||||
SDK_WITH_VENDOR_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/src")
|
||||
SDK_ONLY_PKGS=$(shell go list ./... | grep -v "/vendor/")
|
||||
SDK_UNIT_TEST_ONLY_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/")
|
||||
SDK_GO_1_4=$(shell go version | grep "go1.4")
|
||||
SDK_GO_1_5=$(shell go version | grep "go1.5")
|
||||
SDK_GO_VERSION=$(shell go version | awk '''{print $$3}''' | tr -d '''\n''')
|
||||
|
||||
all: get-deps generate unit
|
||||
|
|
@ -50,11 +53,11 @@ build:
|
|||
|
||||
unit: get-deps-tests build verify
|
||||
@echo "go test SDK and vendor packages"
|
||||
@go test -tags $(SDK_ONLY_PKGS)
|
||||
@go test -tags ${UNIT_TEST_TAGS} $(SDK_UNIT_TEST_ONLY_PKGS)
|
||||
|
||||
unit-with-race-cover: get-deps-tests build verify
|
||||
@echo "go test SDK and vendor packages"
|
||||
@go test -tags -race -cpu=1,2,4 $(SDK_ONLY_PKGS)
|
||||
@go test -tags ${UNIT_TEST_TAGS} -race -cpu=1,2,4 $(SDK_UNIT_TEST_ONLY_PKGS)
|
||||
|
||||
integration: get-deps-tests integ-custom smoke-tests performance
|
||||
|
||||
|
|
@ -101,20 +104,18 @@ verify: get-deps-verify lint vet
|
|||
|
||||
lint:
|
||||
@echo "go lint SDK and vendor packages"
|
||||
@lint=`if [ -z "${SDK_GO_1_4}" ]; then golint ./...; else echo "skipping golint"; fi`; \
|
||||
@lint=`if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then golint ./...; else echo "skipping golint"; fi`; \
|
||||
lint=`echo "$$lint" | grep -E -v -e ${LINTIGNOREDOT} -e ${LINTIGNOREDOC} -e ${LINTIGNORECONST} -e ${LINTIGNORESTUTTER} -e ${LINTIGNOREINFLECT} -e ${LINTIGNOREDEPS} -e ${LINTIGNOREINFLECTS3UPLOAD}`; \
|
||||
echo "$$lint"; \
|
||||
if [ "$$lint" != "" ] && [ "$$lint" != "skipping golint" ]; then exit 1; fi
|
||||
|
||||
SDK_BASE_FOLDERS=$(shell ls -d */ | grep -v vendor | grep -v awsmigrate)
|
||||
ifneq (,$(findstring go1.5, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=go tool vet --all -shadow
|
||||
ifneq (,$(findstring go1.4, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=echo skipping go vet, ${SDK_GO_VERSION}
|
||||
else ifneq (,$(findstring go1.6, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=go tool vet --all -shadow -example=false
|
||||
else ifneq (,$(findstring devel, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=go tool vet --all -shadow -tests=false
|
||||
else
|
||||
GO_VET_CMD=echo skipping go vet, ${SDK_GO_VERSION}
|
||||
GO_VET_CMD=go tool vet --all -shadow
|
||||
endif
|
||||
|
||||
vet:
|
||||
|
|
@ -126,13 +127,14 @@ get-deps: get-deps-tests get-deps-verify
|
|||
|
||||
get-deps-tests:
|
||||
@echo "go get SDK testing dependencies"
|
||||
go get github.com/lsegal/gucumber/cmd/gucumber
|
||||
go get github.com/gucumber/gucumber/cmd/gucumber
|
||||
go get github.com/stretchr/testify
|
||||
go get github.com/smartystreets/goconvey
|
||||
go get golang.org/x/net/html
|
||||
|
||||
get-deps-verify:
|
||||
@echo "go get SDK verification utilities"
|
||||
@if [ -z "${SDK_GO_1_4}" ]; then go get github.com/golang/lint/golint; else echo "skipped getting golint"; fi
|
||||
@if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then go get github.com/golang/lint/golint; else echo "skipped getting golint"; fi
|
||||
|
||||
bench:
|
||||
@echo "go bench SDK packages"
|
||||
|
|
@ -144,9 +146,12 @@ bench-protocol:
|
|||
|
||||
docs:
|
||||
@echo "generate SDK docs"
|
||||
rm -rf doc && bundle install && bundle exec yard
|
||||
@# This env variable, DOCS, is for internal use
|
||||
@if [ -n "$(AWS_DOC_GEN_TOOL)" ]; then echo "For internal use. Subject to change."; $(AWS_DOC_GEN_TOOL) `pwd`; fi
|
||||
@if [ -z ${AWS_DOC_GEN_TOOL} ]; then\
|
||||
rm -rf doc && bundle install && bundle exec yard;\
|
||||
else\
|
||||
$(AWS_DOC_GEN_TOOL) `pwd`;\
|
||||
fi
|
||||
|
||||
api_info:
|
||||
@go run private/model/cli/api-info/api-info.go
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ If you are using Go 1.5 with the `GO15VENDOREXPERIMENT=1` vendoring flag, or 1.6
|
|||
|
||||
go get -u github.com/aws/aws-sdk-go
|
||||
|
||||
Otherwise if your Go environment does not have vendoring support enabled, or you do not want to include the vendored SDK's dependencies you can use the following command to retrieve the SDK and its non-testing dependencies using `go get`.
|
||||
Otherwise if your Go environment does not have vendoring support enabled, or you do not want to include the vendored SDK's dependencies you can use the following command to retrieve the SDK and its non-testing dependencies using `go get`.
|
||||
|
||||
go get -u github.com/aws/aws-sdk-go/aws/...
|
||||
go get -u github.com/aws/aws-sdk-go/service/...
|
||||
|
|
@ -25,7 +25,7 @@ Otherwise if your Go environment does not have vendoring support enabled, or you
|
|||
If you're looking to retrieve just the SDK without any dependencies use the following command.
|
||||
|
||||
go get -d github.com/aws/aws-sdk-go/
|
||||
|
||||
|
||||
These two processes will still include the `vendor` folder and it should be deleted if its not going to be used by your environment.
|
||||
|
||||
rm -rf $GOPATH/src/github.com/aws/aws-sdk-go/vendor
|
||||
|
|
@ -61,8 +61,8 @@ AWS_ACCESS_KEY_ID=AKID1234567890
|
|||
AWS_SECRET_ACCESS_KEY=MY-SECRET-KEY
|
||||
```
|
||||
|
||||
### AWS CLI config file (`~/.aws/config`)
|
||||
The AWS SDK for Go does not support the AWS CLI's config file. The SDK will not use any contents from this file. The SDK only supports the shared credentials file (`~/.aws/credentials`). #384 tracks this feature request discussion.
|
||||
### AWS shared config file (`~/.aws/config`)
|
||||
The AWS SDK for Go added support the shared config file in release [v1.3.0](https://github.com/aws/aws-sdk-go/releases/tag/v1.3.0). You can opt into enabling support for the shared config by setting the environment variable `AWS_SDK_LOAD_CONFIG` to a truthy value. See the [Session](https://github.com/aws/aws-sdk-go/wiki/sessions) wiki for more information about this feature.
|
||||
|
||||
## Using the Go SDK
|
||||
|
||||
|
|
@ -84,10 +84,15 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create an EC2 service object in the "us-west-2" region
|
||||
// Note that you can also configure your region globally by
|
||||
// exporting the AWS_REGION environment variable
|
||||
svc := ec2.New(session.New(), &aws.Config{Region: aws.String("us-west-2")})
|
||||
svc := ec2.New(sess, &aws.Config{Region: aws.String("us-west-2")})
|
||||
|
||||
// Call the DescribeInstances Operation
|
||||
resp, err := svc.DescribeInstances(nil)
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ type Error interface {
|
|||
|
||||
// BatchError is a batch of errors which also wraps lower level errors with
|
||||
// code, message, and original errors. Calling Error() will include all errors
|
||||
// that occured in the batch.
|
||||
// that occurred in the batch.
|
||||
//
|
||||
// Deprecated: Replaced with BatchedErrors. Only defined for backwards
|
||||
// compatibility.
|
||||
|
|
@ -64,7 +64,7 @@ type BatchError interface {
|
|||
|
||||
// BatchedErrors is a batch of errors which also wraps lower level errors with
|
||||
// code, message, and original errors. Calling Error() will include all errors
|
||||
// that occured in the batch.
|
||||
// that occurred in the batch.
|
||||
//
|
||||
// Replaces BatchError
|
||||
type BatchedErrors interface {
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func (b baseError) OrigErr() error {
|
|||
return NewBatchError(err.Code(), err.Message(), b.errs[1:])
|
||||
}
|
||||
return NewBatchError("BatchedErrors",
|
||||
"multiple errors occured", b.errs)
|
||||
"multiple errors occurred", b.errs)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package awsutil
|
|||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Copy deeply copies a src structure to dst. Useful for copying request and
|
||||
|
|
@ -49,7 +50,14 @@ func rcopy(dst, src reflect.Value, root bool) {
|
|||
} else {
|
||||
e := src.Type().Elem()
|
||||
if dst.CanSet() && !src.IsNil() {
|
||||
dst.Set(reflect.New(e))
|
||||
if _, ok := src.Interface().(*time.Time); !ok {
|
||||
dst.Set(reflect.New(e))
|
||||
} else {
|
||||
tempValue := reflect.New(e)
|
||||
tempValue.Elem().Set(src.Elem())
|
||||
// Sets time.Time's unexported values
|
||||
dst.Set(tempValue)
|
||||
}
|
||||
}
|
||||
if src.Elem().IsValid() {
|
||||
// Keep the current root state since the depth hasn't changed
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -36,11 +37,19 @@ func ExampleCopy() {
|
|||
// }
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
func TestCopy1(t *testing.T) {
|
||||
type Bar struct {
|
||||
a *int
|
||||
B *int
|
||||
c int
|
||||
D int
|
||||
}
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
D *time.Time
|
||||
E *Bar
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
|
|
@ -48,6 +57,9 @@ func TestCopy(t *testing.T) {
|
|||
str2 := "bye bye"
|
||||
int1 := 1
|
||||
int2 := 2
|
||||
intPtr1 := 1
|
||||
intPtr2 := 2
|
||||
now := time.Now()
|
||||
f1 := &Foo{
|
||||
A: 1,
|
||||
B: []*string{&str1, &str2},
|
||||
|
|
@ -55,6 +67,13 @@ func TestCopy(t *testing.T) {
|
|||
"A": &int1,
|
||||
"B": &int2,
|
||||
},
|
||||
D: &now,
|
||||
E: &Bar{
|
||||
&intPtr1,
|
||||
&intPtr2,
|
||||
2,
|
||||
3,
|
||||
},
|
||||
}
|
||||
|
||||
// Do the copy
|
||||
|
|
@ -65,16 +84,29 @@ func TestCopy(t *testing.T) {
|
|||
assert.Equal(t, f2.A, f1.A)
|
||||
assert.Equal(t, f2.B, f1.B)
|
||||
assert.Equal(t, f2.C, f1.C)
|
||||
assert.Equal(t, f2.D, f1.D)
|
||||
assert.Equal(t, f2.E.B, f1.E.B)
|
||||
assert.Equal(t, f2.E.D, f1.E.D)
|
||||
|
||||
// But pointers are not!
|
||||
str3 := "nothello"
|
||||
int3 := 57
|
||||
f2.A = 100
|
||||
f2.B[0] = &str3
|
||||
f2.C["B"] = &int3
|
||||
*f2.B[0] = str3
|
||||
*f2.C["B"] = int3
|
||||
*f2.D = time.Now()
|
||||
f2.E.a = &int3
|
||||
*f2.E.B = int3
|
||||
f2.E.c = 5
|
||||
f2.E.D = 5
|
||||
assert.NotEqual(t, f2.A, f1.A)
|
||||
assert.NotEqual(t, f2.B, f1.B)
|
||||
assert.NotEqual(t, f2.C, f1.C)
|
||||
assert.NotEqual(t, f2.D, f1.D)
|
||||
assert.NotEqual(t, f2.E.a, f1.E.a)
|
||||
assert.NotEqual(t, f2.E.B, f1.E.B)
|
||||
assert.NotEqual(t, f2.E.c, f1.E.c)
|
||||
assert.NotEqual(t, f2.E.D, f1.E.D)
|
||||
}
|
||||
|
||||
func TestCopyNestedWithUnexported(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -106,8 +106,8 @@ func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTer
|
|||
|
||||
if indexStar || index != nil {
|
||||
nextvals = []reflect.Value{}
|
||||
for _, value := range values {
|
||||
value := reflect.Indirect(value)
|
||||
for _, valItem := range values {
|
||||
value := reflect.Indirect(valItem)
|
||||
if value.Kind() != reflect.Slice {
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package client
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
|
|
@ -87,16 +86,24 @@ const logReqMsg = `DEBUG: Request %s/%s Details:
|
|||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
const logReqErrMsg = `DEBUG ERROR: Request %s/%s:
|
||||
---[ REQUEST DUMP ERROR ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logRequest(r *request.Request) {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
dumpedBody, err := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
if logBody {
|
||||
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||
// client reader.
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
|
||||
r.ResetBody()
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
|
||||
|
|
@ -107,11 +114,21 @@ const logRespMsg = `DEBUG: Response %s/%s Details:
|
|||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
const logRespErrMsg = `DEBUG ERROR: Response %s/%s:
|
||||
---[ RESPONSE DUMP ERROR ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
func logResponse(r *request.Request) {
|
||||
var msg = "no response data"
|
||||
if r.HTTPResponse != nil {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
|
||||
dumpedBody, err := httputil.DumpResponse(r.HTTPResponse, logBody)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
msg = string(dumpedBody)
|
||||
} else if r.Error != nil {
|
||||
msg = r.Error.Error()
|
||||
|
|
|
|||
|
|
@ -7,24 +7,36 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
// UseServiceDefaultRetries instructs the config to use the service's own default
|
||||
// number of retries. This will be the default action if Config.MaxRetries
|
||||
// is nil also.
|
||||
// UseServiceDefaultRetries instructs the config to use the service's own
|
||||
// default number of retries. This will be the default action if
|
||||
// Config.MaxRetries is nil also.
|
||||
const UseServiceDefaultRetries = -1
|
||||
|
||||
// RequestRetryer is an alias for a type that implements the request.Retryer interface.
|
||||
// RequestRetryer is an alias for a type that implements the request.Retryer
|
||||
// interface.
|
||||
type RequestRetryer interface{}
|
||||
|
||||
// A Config provides service configuration for service clients. By default,
|
||||
// all clients will use the {defaults.DefaultConfig} structure.
|
||||
// all clients will use the defaults.DefaultConfig tructure.
|
||||
//
|
||||
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess, err := session.NewSession(&aws.Config{
|
||||
// MaxRetries: aws.Int(3),
|
||||
// })
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
// Region: aws.String("us-west-2"),
|
||||
// })
|
||||
type Config struct {
|
||||
// Enables verbose error printing of all credential chain errors.
|
||||
// Should be used when wanting to see all errors while attempting to retreive
|
||||
// credentials.
|
||||
// Should be used when wanting to see all errors while attempting to
|
||||
// retrieve credentials.
|
||||
CredentialsChainVerboseErrors *bool
|
||||
|
||||
// The credentials object to use when signing requests. Defaults to
|
||||
// a chain of credential providers to search for credentials in environment
|
||||
// The credentials object to use when signing requests. Defaults to a
|
||||
// chain of credential providers to search for credentials in environment
|
||||
// variables, shared credential file, and EC2 Instance Roles.
|
||||
Credentials *credentials.Credentials
|
||||
|
||||
|
|
@ -63,11 +75,12 @@ type Config struct {
|
|||
Logger Logger
|
||||
|
||||
// The maximum number of times that a request will be retried for failures.
|
||||
// Defaults to -1, which defers the max retry setting to the service specific
|
||||
// configuration.
|
||||
// Defaults to -1, which defers the max retry setting to the service
|
||||
// specific configuration.
|
||||
MaxRetries *int
|
||||
|
||||
// Retryer guides how HTTP requests should be retried in case of recoverable failures.
|
||||
// Retryer guides how HTTP requests should be retried in case of
|
||||
// recoverable failures.
|
||||
//
|
||||
// When nil or the value does not implement the request.Retryer interface,
|
||||
// the request.DefaultRetryer will be used.
|
||||
|
|
@ -82,8 +95,8 @@ type Config struct {
|
|||
//
|
||||
Retryer RequestRetryer
|
||||
|
||||
// Disables semantic parameter validation, which validates input for missing
|
||||
// required fields and/or other semantic request input errors.
|
||||
// Disables semantic parameter validation, which validates input for
|
||||
// missing required fields and/or other semantic request input errors.
|
||||
DisableParamValidation *bool
|
||||
|
||||
// Disables the computation of request and response checksums, e.g.,
|
||||
|
|
@ -91,8 +104,8 @@ type Config struct {
|
|||
DisableComputeChecksums *bool
|
||||
|
||||
// Set this to `true` to force the request to use path-style addressing,
|
||||
// i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client will
|
||||
// use virtual hosted bucket addressing when possible
|
||||
// i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client
|
||||
// will use virtual hosted bucket addressing when possible
|
||||
// (`http://BUCKET.s3.amazonaws.com/KEY`).
|
||||
//
|
||||
// @note This configuration option is specific to the Amazon S3 service.
|
||||
|
|
@ -109,36 +122,60 @@ type Config struct {
|
|||
// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html
|
||||
//
|
||||
// 100-Continue is only enabled for Go 1.6 and above. See `http.Transport`'s
|
||||
// `ExpectContinueTimeout` for information on adjusting the continue wait timeout.
|
||||
// https://golang.org/pkg/net/http/#Transport
|
||||
// `ExpectContinueTimeout` for information on adjusting the continue wait
|
||||
// timeout. https://golang.org/pkg/net/http/#Transport
|
||||
//
|
||||
// You should use this flag to disble 100-Continue if you experiance issues
|
||||
// with proxies or thrid party S3 compatible services.
|
||||
// You should use this flag to disble 100-Continue if you experience issues
|
||||
// with proxies or third party S3 compatible services.
|
||||
S3Disable100Continue *bool
|
||||
|
||||
// Set this to `true` to enable S3 Accelerate feature. For all operations compatible
|
||||
// with S3 Accelerate will use the accelerate endpoint for requests. Requests not compatible
|
||||
// will fall back to normal S3 requests.
|
||||
// Set this to `true` to enable S3 Accelerate feature. For all operations
|
||||
// compatible with S3 Accelerate will use the accelerate endpoint for
|
||||
// requests. Requests not compatible will fall back to normal S3 requests.
|
||||
//
|
||||
// The bucket must be enable for accelerate to be used with S3 client with accelerate
|
||||
// enabled. If the bucket is not enabled for accelerate an error will be returned.
|
||||
// The bucket name must be DNS compatible to also work with accelerate.
|
||||
// The bucket must be enable for accelerate to be used with S3 client with
|
||||
// accelerate enabled. If the bucket is not enabled for accelerate an error
|
||||
// will be returned. The bucket name must be DNS compatible to also work
|
||||
// with accelerate.
|
||||
S3UseAccelerate *bool
|
||||
|
||||
// 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 EC2Metadata
|
||||
// client to create a new http.Client. This options is only meaningful if you're not
|
||||
// already using a custom HTTP client with the SDK. Enabled by default.
|
||||
// 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
|
||||
// meaningful if you're not already using a custom HTTP client with the
|
||||
// SDK. Enabled by default.
|
||||
//
|
||||
// Must be set and provided to the session.New() in order to disable the EC2Metadata
|
||||
// overriding the timeout for default credentials chain.
|
||||
// Must be set and provided to the session.NewSession() in order to disable
|
||||
// the EC2Metadata overriding the timeout for default credentials chain.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.New(aws.NewConfig().WithEC2MetadataDiableTimeoutOverride(true))
|
||||
// sess, err := session.NewSession(aws.NewConfig().WithEC2MetadataDiableTimeoutOverride(true))
|
||||
//
|
||||
// svc := s3.New(sess)
|
||||
//
|
||||
EC2MetadataDisableTimeoutOverride *bool
|
||||
|
||||
// Instructs the endpiont to be generated for a service client to
|
||||
// be the dual stack endpoint. The dual stack endpoint will support
|
||||
// both IPv4 and IPv6 addressing.
|
||||
//
|
||||
// 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
|
||||
// as it will apply to all service clients created with the session. Even
|
||||
// services which don't support dual stack endpoints.
|
||||
//
|
||||
// If the Endpoint config value is also provided the UseDualStack flag
|
||||
// will be ignored.
|
||||
//
|
||||
// Only supported with.
|
||||
//
|
||||
// sess, err := session.NewSession()
|
||||
//
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
// UseDualStack: aws.Bool(true),
|
||||
// })
|
||||
UseDualStack *bool
|
||||
|
||||
// SleepDelay is an override for the func the SDK will call when sleeping
|
||||
// during the lifecycle of a request. Specifically this will be used for
|
||||
// request delays. This value should only be used for testing. To adjust
|
||||
|
|
@ -147,11 +184,19 @@ type Config struct {
|
|||
SleepDelay func(time.Duration)
|
||||
}
|
||||
|
||||
// NewConfig returns a new Config pointer that can be chained with builder methods to
|
||||
// set multiple configuration values inline without using pointers.
|
||||
// NewConfig returns a new Config pointer that can be chained with builder
|
||||
// methods to set multiple configuration values inline without using pointers.
|
||||
//
|
||||
// sess := session.New(aws.NewConfig().WithRegion("us-west-2").WithMaxRetries(10))
|
||||
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess, err := session.NewSession(aws.NewConfig().
|
||||
// WithMaxRetries(3),
|
||||
// )
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, aws.NewConfig().
|
||||
// WithRegion("us-west-2"),
|
||||
// )
|
||||
func NewConfig() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
|
|
@ -254,6 +299,13 @@ func (c *Config) WithS3UseAccelerate(enable bool) *Config {
|
|||
return c
|
||||
}
|
||||
|
||||
// WithUseDualStack sets a config UseDualStack value returning a Config
|
||||
// pointer for chaining.
|
||||
func (c *Config) WithUseDualStack(enable bool) *Config {
|
||||
c.UseDualStack = &enable
|
||||
return c
|
||||
}
|
||||
|
||||
// WithEC2MetadataDisableTimeoutOverride sets a config EC2MetadataDisableTimeoutOverride value
|
||||
// returning a Config pointer for chaining.
|
||||
func (c *Config) WithEC2MetadataDisableTimeoutOverride(enable bool) *Config {
|
||||
|
|
@ -340,6 +392,10 @@ func mergeInConfig(dst *Config, other *Config) {
|
|||
dst.S3UseAccelerate = other.S3UseAccelerate
|
||||
}
|
||||
|
||||
if other.UseDualStack != nil {
|
||||
dst.UseDualStack = other.UseDualStack
|
||||
}
|
||||
|
||||
if other.EC2MetadataDisableTimeoutOverride != nil {
|
||||
dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@ import (
|
|||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
|
|
@ -67,6 +69,34 @@ var SDKVersionUserAgentHandler = request.NamedHandler{
|
|||
|
||||
var reStatusCode = regexp.MustCompile(`^(\d{3})`)
|
||||
|
||||
// ValidateReqSigHandler is a request handler to ensure that the request's
|
||||
// signature doesn't expire before it is sent. This can happen when a request
|
||||
// is built and signed signficantly before it is sent. Or signficant delays
|
||||
// occur whne retrying requests that would cause the signature to expire.
|
||||
var ValidateReqSigHandler = request.NamedHandler{
|
||||
Name: "core.ValidateReqSigHandler",
|
||||
Fn: func(r *request.Request) {
|
||||
// Unsigned requests are not signed
|
||||
if r.Config.Credentials == credentials.AnonymousCredentials {
|
||||
return
|
||||
}
|
||||
|
||||
signedTime := r.Time
|
||||
if !r.LastSignedAt.IsZero() {
|
||||
signedTime = r.LastSignedAt
|
||||
}
|
||||
|
||||
// 10 minutes to allow for some clock skew/delays in transmission.
|
||||
// Would be improved with aws/aws-sdk-go#423
|
||||
if signedTime.Add(10 * time.Minute).After(time.Now()) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("request expired, resigning")
|
||||
r.Sign()
|
||||
},
|
||||
}
|
||||
|
||||
// SendHandler is a request handler to send service request using HTTP client.
|
||||
var SendHandler = request.NamedHandler{Name: "core.SendHandler", Fn: func(r *request.Request) {
|
||||
var err error
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
|
|
@ -117,11 +118,52 @@ func TestSendHandlerError(t *testing.T) {
|
|||
assert.NotNil(t, r.HTTPResponse)
|
||||
}
|
||||
|
||||
func TestValidateReqSigHandler(t *testing.T) {
|
||||
cases := []struct {
|
||||
Req *request.Request
|
||||
Resign bool
|
||||
}{
|
||||
{
|
||||
Req: &request.Request{
|
||||
Config: aws.Config{Credentials: credentials.AnonymousCredentials},
|
||||
Time: time.Now().Add(-15 * time.Minute),
|
||||
},
|
||||
Resign: false,
|
||||
},
|
||||
{
|
||||
Req: &request.Request{
|
||||
Time: time.Now().Add(-15 * time.Minute),
|
||||
},
|
||||
Resign: true,
|
||||
},
|
||||
{
|
||||
Req: &request.Request{
|
||||
Time: time.Now().Add(-1 * time.Minute),
|
||||
},
|
||||
Resign: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
resigned := false
|
||||
c.Req.Handlers.Sign.PushBack(func(r *request.Request) {
|
||||
resigned = true
|
||||
})
|
||||
|
||||
corehandlers.ValidateReqSigHandler.Fn(c.Req)
|
||||
|
||||
assert.NoError(t, c.Req.Error, "%d, expect no error", i)
|
||||
assert.Equal(t, c.Resign, resigned, "%d, expected resigning to match", i)
|
||||
}
|
||||
}
|
||||
|
||||
func setupContentLengthTestServer(t *testing.T, hasContentLength bool, contentLength int64) *httptest.Server {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, ok := r.Header["Content-Length"]
|
||||
assert.Equal(t, hasContentLength, ok, "expect content length to be set, %t", hasContentLength)
|
||||
assert.Equal(t, contentLength, r.ContentLength)
|
||||
if hasContentLength {
|
||||
assert.Equal(t, contentLength, r.ContentLength)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
assert.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/kinesis"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
@ -242,7 +242,7 @@ func BenchmarkValidateAny(b *testing.B) {
|
|||
input.Records = append(input.Records, record)
|
||||
}
|
||||
|
||||
req, _ := kinesis.New(session.New()).PutRecordsRequest(input)
|
||||
req, _ := kinesis.New(unit.Session).PutRecordsRequest(input)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ var (
|
|||
//
|
||||
// Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider.
|
||||
// In this example EnvProvider will first check if any credentials are available
|
||||
// vai the environment variables. If there are none ChainProvider will check
|
||||
// via the environment variables. If there are none ChainProvider will check
|
||||
// the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider
|
||||
// does not return any credentials ChainProvider will return the error
|
||||
// ErrNoValidProvidersFoundInChain
|
||||
|
|
|
|||
12
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider_test.go
generated
vendored
12
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider_test.go
generated
vendored
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
)
|
||||
|
||||
const credsRespTmpl = `{
|
||||
|
|
@ -55,7 +55,7 @@ func TestEC2RoleProvider(t *testing.T) {
|
|||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
|
||||
creds, err := p.Retrieve()
|
||||
|
|
@ -71,7 +71,7 @@ func TestEC2RoleProviderFailAssume(t *testing.T) {
|
|||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
|
||||
creds, err := p.Retrieve()
|
||||
|
|
@ -92,7 +92,7 @@ func TestEC2RoleProviderIsExpired(t *testing.T) {
|
|||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
p.CurrentTime = func() time.Time {
|
||||
return time.Date(2014, 12, 15, 21, 26, 0, 0, time.UTC)
|
||||
|
|
@ -117,7 +117,7 @@ func TestEC2RoleProviderExpiryWindowIsExpired(t *testing.T) {
|
|||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
ExpiryWindow: time.Hour * 1,
|
||||
}
|
||||
p.CurrentTime = func() time.Time {
|
||||
|
|
@ -143,7 +143,7 @@ func BenchmarkEC3RoleProvider(b *testing.B) {
|
|||
defer server.Close()
|
||||
|
||||
p := &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
Client: ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
|
||||
}
|
||||
_, err := p.Retrieve()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -30,13 +30,22 @@ func NewStaticCredentials(id, secret, token string) *Credentials {
|
|||
}})
|
||||
}
|
||||
|
||||
// NewStaticCredentialsFromCreds returns a pointer to a new Credentials object
|
||||
// wrapping the static credentials value provide. Same as NewStaticCredentials
|
||||
// but takes the creds Value instead of individual fields
|
||||
func NewStaticCredentialsFromCreds(creds Value) *Credentials {
|
||||
return NewCredentials(&StaticProvider{Value: creds})
|
||||
}
|
||||
|
||||
// Retrieve returns the credentials or error if the credentials are invalid.
|
||||
func (s *StaticProvider) Retrieve() (Value, error) {
|
||||
if s.AccessKeyID == "" || s.SecretAccessKey == "" {
|
||||
return Value{ProviderName: StaticProviderName}, ErrStaticCredentialsEmpty
|
||||
}
|
||||
|
||||
s.Value.ProviderName = StaticProviderName
|
||||
if len(s.Value.ProviderName) == 0 {
|
||||
s.Value.ProviderName = StaticProviderName
|
||||
}
|
||||
return s.Value, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ func Handlers() request.Handlers {
|
|||
handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler)
|
||||
handlers.Build.AfterEachFn = request.HandlerListStopOnError
|
||||
handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.ValidateReqSigHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
|
||||
|
|
@ -90,12 +91,14 @@ func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credenti
|
|||
Providers: []credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
remoteCredProvider(*cfg, handlers),
|
||||
RemoteCredProvider(*cfg, handlers),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func remoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||
// RemoteCredProvider returns a credenitials provider for the default remote
|
||||
// endpoints such as EC2 or ECS Roles.
|
||||
func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||
ecsCredURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI")
|
||||
|
||||
if len(ecsCredURI) > 0 {
|
||||
|
|
@ -118,7 +121,7 @@ func ecsCredProvider(cfg aws.Config, handlers request.Handlers, uri string) cred
|
|||
|
||||
func ec2RoleProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||
endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName,
|
||||
aws.StringValue(cfg.Region), true)
|
||||
aws.StringValue(cfg.Region), true, false)
|
||||
|
||||
return &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.NewClient(cfg, handlers, endpoint, signingRegion),
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ func TestECSCredProvider(t *testing.T) {
|
|||
defer os.Clearenv()
|
||||
os.Setenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/abc/123")
|
||||
|
||||
provider := remoteCredProvider(aws.Config{}, request.Handlers{})
|
||||
provider := RemoteCredProvider(aws.Config{}, request.Handlers{})
|
||||
|
||||
assert.NotNil(t, provider)
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ func TestECSCredProvider(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDefaultEC2RoleProvider(t *testing.T) {
|
||||
provider := remoteCredProvider(aws.Config{}, request.Handlers{})
|
||||
provider := RemoteCredProvider(aws.Config{}, request.Handlers{})
|
||||
|
||||
assert.NotNil(t, provider)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package ec2metadata
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -27,6 +28,27 @@ func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
|||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// GetUserData 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) GetUserData() (string, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetUserData",
|
||||
HTTPMethod: "GET",
|
||||
HTTPPath: path.Join("/", "user-data"),
|
||||
}
|
||||
|
||||
output := &metadataOutput{}
|
||||
req := c.NewRequest(op, nil, output)
|
||||
req.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
|
||||
if r.HTTPResponse.StatusCode == http.StatusNotFound {
|
||||
r.Error = awserr.New("NotFoundError", "user-data not found", r.Error)
|
||||
}
|
||||
})
|
||||
|
||||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// GetDynamicData 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.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package ec2metadata_test
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
|
@ -15,7 +17,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
)
|
||||
|
||||
const instanceIdentityDocument = `{
|
||||
|
|
@ -61,7 +63,7 @@ func initTestServer(path string, resp string) *httptest.Server {
|
|||
}
|
||||
|
||||
func TestEndpoint(t *testing.T) {
|
||||
c := ec2metadata.New(session.New())
|
||||
c := ec2metadata.New(unit.Session)
|
||||
op := &request.Operation{
|
||||
Name: "GetMetadata",
|
||||
HTTPMethod: "GET",
|
||||
|
|
@ -79,7 +81,7 @@ func TestGetMetadata(t *testing.T) {
|
|||
"success", // real response includes suffix
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
resp, err := c.GetMetadata("some/path")
|
||||
|
||||
|
|
@ -87,13 +89,58 @@ func TestGetMetadata(t *testing.T) {
|
|||
assert.Equal(t, "success", resp)
|
||||
}
|
||||
|
||||
func TestGetUserData(t *testing.T) {
|
||||
server := initTestServer(
|
||||
"/latest/user-data",
|
||||
"success", // real response includes suffix
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
resp, err := c.GetUserData()
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "success", resp)
|
||||
}
|
||||
|
||||
func TestGetUserData_Error(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
reader := strings.NewReader(`<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>404 - Not Found</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>404 - Not Found</h1>
|
||||
</body>
|
||||
</html>`)
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", reader.Len()))
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
io.Copy(w, reader)
|
||||
}))
|
||||
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
resp, err := c.GetUserData()
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, resp)
|
||||
|
||||
aerr, ok := err.(awserr.Error)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "NotFoundError", aerr.Code())
|
||||
}
|
||||
|
||||
func TestGetRegion(t *testing.T) {
|
||||
server := initTestServer(
|
||||
"/latest/meta-data/placement/availability-zone",
|
||||
"us-west-2a", // real response includes suffix
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
region, err := c.Region()
|
||||
|
||||
|
|
@ -107,7 +154,7 @@ func TestMetadataAvailable(t *testing.T) {
|
|||
"instance-id",
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
available := c.Available()
|
||||
|
||||
|
|
@ -120,7 +167,7 @@ func TestMetadataIAMInfo_success(t *testing.T) {
|
|||
validIamInfo,
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
iamInfo, err := c.IAMInfo()
|
||||
assert.NoError(t, err)
|
||||
|
|
@ -135,7 +182,7 @@ func TestMetadataIAMInfo_failure(t *testing.T) {
|
|||
unsuccessfulIamInfo,
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
iamInfo, err := c.IAMInfo()
|
||||
assert.NotNil(t, err)
|
||||
|
|
@ -145,7 +192,7 @@ func TestMetadataIAMInfo_failure(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMetadataNotAvailable(t *testing.T) {
|
||||
c := ec2metadata.New(session.New())
|
||||
c := ec2metadata.New(unit.Session)
|
||||
c.Handlers.Send.Clear()
|
||||
c.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse = &http.Response{
|
||||
|
|
@ -163,7 +210,7 @@ func TestMetadataNotAvailable(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMetadataErrorResponse(t *testing.T) {
|
||||
c := ec2metadata.New(session.New())
|
||||
c := ec2metadata.New(unit.Session)
|
||||
c.Handlers.Send.Clear()
|
||||
c.Handlers.Send.PushBack(func(r *request.Request) {
|
||||
r.HTTPResponse = &http.Response{
|
||||
|
|
@ -185,7 +232,7 @@ func TestEC2RoleProviderInstanceIdentity(t *testing.T) {
|
|||
instanceIdentityDocument,
|
||||
)
|
||||
defer server.Close()
|
||||
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
c := ec2metadata.New(unit.Session, &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
|
||||
|
||||
doc, err := c.GetInstanceIdentityDocument()
|
||||
assert.Nil(t, err, "Expect no error, %v", err)
|
||||
|
|
|
|||
|
|
@ -9,25 +9,24 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestClientOverrideDefaultHTTPClientTimeout(t *testing.T) {
|
||||
svc := ec2metadata.New(session.New())
|
||||
svc := ec2metadata.New(unit.Session)
|
||||
|
||||
assert.NotEqual(t, http.DefaultClient, svc.Config.HTTPClient)
|
||||
assert.Equal(t, 5*time.Second, svc.Config.HTTPClient.Timeout)
|
||||
}
|
||||
|
||||
func TestClientNotOverrideDefaultHTTPClientTimeout(t *testing.T) {
|
||||
origClient := *http.DefaultClient
|
||||
http.DefaultClient.Transport = &http.Transport{}
|
||||
defer func() {
|
||||
http.DefaultClient = &origClient
|
||||
http.DefaultClient.Transport = nil
|
||||
}()
|
||||
|
||||
svc := ec2metadata.New(session.New())
|
||||
svc := ec2metadata.New(unit.Session)
|
||||
|
||||
assert.Equal(t, http.DefaultClient, svc.Config.HTTPClient)
|
||||
|
||||
|
|
@ -38,7 +37,7 @@ func TestClientNotOverrideDefaultHTTPClientTimeout(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClientDisableOverrideDefaultHTTPClientTimeout(t *testing.T) {
|
||||
svc := ec2metadata.New(session.New(aws.NewConfig().WithEC2MetadataDisableTimeoutOverride(true)))
|
||||
svc := ec2metadata.New(unit.Session, aws.NewConfig().WithEC2MetadataDisableTimeoutOverride(true))
|
||||
|
||||
assert.Equal(t, http.DefaultClient, svc.Config.HTTPClient)
|
||||
}
|
||||
|
|
@ -69,7 +68,7 @@ func runEC2MetadataClients(t *testing.T, cfg *aws.Config, atOnce int) {
|
|||
wg.Add(atOnce)
|
||||
for i := 0; i < atOnce; i++ {
|
||||
go func() {
|
||||
svc := ec2metadata.New(session.New(), cfg)
|
||||
svc := ec2metadata.New(unit.Session, cfg)
|
||||
_, err := svc.Region()
|
||||
assert.NoError(t, err)
|
||||
wg.Done()
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ func TestStopHandlers(t *testing.T) {
|
|||
called++
|
||||
}})
|
||||
l.PushBackNamed(request.NamedHandler{Name: "name3", Fn: func(r *request.Request) {
|
||||
assert.Fail(t, "thrid handler should not be called")
|
||||
assert.Fail(t, "third handler should not be called")
|
||||
}})
|
||||
l.Run(&request.Request{})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
// +build go1.5
|
||||
|
||||
package request
|
||||
|
||||
import (
|
||||
|
|
@ -9,20 +7,13 @@ import (
|
|||
)
|
||||
|
||||
func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request {
|
||||
req := &http.Request{
|
||||
URL: &url.URL{},
|
||||
Header: http.Header{},
|
||||
Close: r.Close,
|
||||
Body: body,
|
||||
Host: r.Host,
|
||||
Method: r.Method,
|
||||
Proto: r.Proto,
|
||||
ContentLength: r.ContentLength,
|
||||
// Cancel will be deprecated in 1.7 and will be replaced with Context
|
||||
Cancel: r.Cancel,
|
||||
}
|
||||
|
||||
req := new(http.Request)
|
||||
*req = *r
|
||||
req.URL = &url.URL{}
|
||||
*req.URL = *r.URL
|
||||
req.Body = body
|
||||
|
||||
req.Header = http.Header{}
|
||||
for k, v := range r.Header {
|
||||
for _, vv := range v {
|
||||
req.Header.Add(k, vv)
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
// +build !go1.5
|
||||
|
||||
package request
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func copyHTTPRequest(r *http.Request, body io.ReadCloser) *http.Request {
|
||||
req := &http.Request{
|
||||
URL: &url.URL{},
|
||||
Header: http.Header{},
|
||||
Close: r.Close,
|
||||
Body: body,
|
||||
Host: r.Host,
|
||||
Method: r.Method,
|
||||
Proto: r.Proto,
|
||||
ContentLength: r.ContentLength,
|
||||
}
|
||||
|
||||
*req.URL = *r.URL
|
||||
for k, v := range r.Header {
|
||||
for _, vv := range v {
|
||||
req.Header.Add(k, vv)
|
||||
}
|
||||
}
|
||||
|
||||
return req
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
"github.com/aws/aws-sdk-go/awstesting/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ func TestRequestCancelRetry(t *testing.T) {
|
|||
c := make(chan struct{})
|
||||
|
||||
reqNum := 0
|
||||
s := awstesting.NewMockClient(aws.NewConfig().WithMaxRetries(10))
|
||||
s := mock.NewMockClient(aws.NewConfig().WithMaxRetries(10))
|
||||
s.Handlers.Validate.Clear()
|
||||
s.Handlers.Unmarshal.Clear()
|
||||
s.Handlers.UnmarshalMeta.Clear()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
// with retrying requests
|
||||
type offsetReader struct {
|
||||
buf io.ReadSeeker
|
||||
lock sync.RWMutex
|
||||
lock sync.Mutex
|
||||
closed bool
|
||||
}
|
||||
|
||||
|
|
@ -21,7 +21,8 @@ func newOffsetReader(buf io.ReadSeeker, offset int64) *offsetReader {
|
|||
return reader
|
||||
}
|
||||
|
||||
// Close is a thread-safe close. Uses the write lock.
|
||||
// Close will close the instance of the offset reader's access to
|
||||
// the underlying io.ReadSeeker.
|
||||
func (o *offsetReader) Close() error {
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
|
@ -29,10 +30,10 @@ func (o *offsetReader) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Read is a thread-safe read using a read lock.
|
||||
// Read is a thread-safe read of the underlying io.ReadSeeker
|
||||
func (o *offsetReader) Read(p []byte) (int, error) {
|
||||
o.lock.RLock()
|
||||
defer o.lock.RUnlock()
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
||||
if o.closed {
|
||||
return 0, io.EOF
|
||||
|
|
@ -41,6 +42,14 @@ func (o *offsetReader) Read(p []byte) (int, error) {
|
|||
return o.buf.Read(p)
|
||||
}
|
||||
|
||||
// Seek is a thread-safe seeking operation.
|
||||
func (o *offsetReader) Seek(offset int64, whence int) (int64, error) {
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
|
||||
return o.buf.Seek(offset, whence)
|
||||
}
|
||||
|
||||
// CloseAndCopy will return a new offsetReader with a copy of the old buffer
|
||||
// and close the old buffer.
|
||||
func (o *offsetReader) CloseAndCopy(offset int64) *offsetReader {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,23 @@ func TestOffsetReaderRead(t *testing.T) {
|
|||
assert.Equal(t, buf, tempBuf)
|
||||
}
|
||||
|
||||
func TestOffsetReaderSeek(t *testing.T) {
|
||||
buf := []byte("testData")
|
||||
reader := newOffsetReader(bytes.NewReader(buf), 0)
|
||||
|
||||
orig, err := reader.Seek(0, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(0), orig)
|
||||
|
||||
n, err := reader.Seek(0, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(len(buf)), n)
|
||||
|
||||
n, err = reader.Seek(orig, 0)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(0), n)
|
||||
}
|
||||
|
||||
func TestOffsetReaderClose(t *testing.T) {
|
||||
buf := []byte("testData")
|
||||
reader := &offsetReader{buf: bytes.NewReader(buf)}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
|
|
@ -42,6 +41,12 @@ type Request struct {
|
|||
LastSignedAt time.Time
|
||||
|
||||
built bool
|
||||
|
||||
// Need to persist an intermideant body betweend the input Body and HTTP
|
||||
// request body because the HTTP Client's transport can maintain a reference
|
||||
// to the HTTP request's body after the client has returned. This value is
|
||||
// safe to use concurrently and rewraps the input Body for each HTTP request.
|
||||
safeBody *offsetReader
|
||||
}
|
||||
|
||||
// An Operation is the service API operation to be made.
|
||||
|
|
@ -135,8 +140,8 @@ func (r *Request) SetStringBody(s string) {
|
|||
|
||||
// SetReaderBody will set the request's body reader.
|
||||
func (r *Request) SetReaderBody(reader io.ReadSeeker) {
|
||||
r.HTTPRequest.Body = newOffsetReader(reader, 0)
|
||||
r.Body = reader
|
||||
r.ResetBody()
|
||||
}
|
||||
|
||||
// Presign returns the request's signed URL. Error will be returned
|
||||
|
|
@ -220,6 +225,24 @@ func (r *Request) Sign() error {
|
|||
return r.Error
|
||||
}
|
||||
|
||||
// ResetBody rewinds the request body backto its starting position, and
|
||||
// set's the HTTP Request body reference. When the body is read prior
|
||||
// to being sent in the HTTP request it will need to be rewound.
|
||||
func (r *Request) ResetBody() {
|
||||
if r.safeBody != nil {
|
||||
r.safeBody.Close()
|
||||
}
|
||||
|
||||
r.safeBody = newOffsetReader(r.Body, r.BodyStart)
|
||||
r.HTTPRequest.Body = r.safeBody
|
||||
}
|
||||
|
||||
// GetBody will return an io.ReadSeeker of the Request's underlying
|
||||
// input body with a concurrency safe wrapper.
|
||||
func (r *Request) GetBody() io.ReadSeeker {
|
||||
return r.safeBody
|
||||
}
|
||||
|
||||
// Send will send the request returning error if errors are encountered.
|
||||
//
|
||||
// Send will sign the request prior to sending. All Send Handlers will
|
||||
|
|
@ -231,6 +254,8 @@ func (r *Request) Sign() error {
|
|||
//
|
||||
// readLoop() and getConn(req *Request, cm connectMethod)
|
||||
// https://github.com/golang/go/blob/master/src/net/http/transport.go
|
||||
//
|
||||
// Send will not close the request.Request's body.
|
||||
func (r *Request) Send() error {
|
||||
for {
|
||||
if aws.BoolValue(r.Retryable) {
|
||||
|
|
@ -239,21 +264,15 @@ func (r *Request) Send() error {
|
|||
r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount))
|
||||
}
|
||||
|
||||
var body io.ReadCloser
|
||||
if reader, ok := r.HTTPRequest.Body.(*offsetReader); ok {
|
||||
body = reader.CloseAndCopy(r.BodyStart)
|
||||
} else {
|
||||
if r.Config.Logger != nil {
|
||||
r.Config.Logger.Log("Request body type has been overwritten. May cause race conditions")
|
||||
}
|
||||
r.Body.Seek(r.BodyStart, 0)
|
||||
body = ioutil.NopCloser(r.Body)
|
||||
}
|
||||
// The previous http.Request will have a reference to the r.Body
|
||||
// and the HTTP Client's Transport may still be reading from
|
||||
// the request's body even though the Client's Do returned.
|
||||
r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, nil)
|
||||
r.ResetBody()
|
||||
|
||||
r.HTTPRequest = copyHTTPRequest(r.HTTPRequest, body)
|
||||
// Closing response body to ensure that no response body is leaked
|
||||
// between retry attempts.
|
||||
if r.HTTPResponse != nil && r.HTTPResponse.Body != nil {
|
||||
// Closing response body. Since we are setting a new request to send off, this
|
||||
// response will get squashed and leaked.
|
||||
r.HTTPResponse.Body.Close()
|
||||
}
|
||||
}
|
||||
|
|
@ -281,7 +300,6 @@ func (r *Request) Send() error {
|
|||
debugLogReqError(r, "Send Request", true, err)
|
||||
continue
|
||||
}
|
||||
|
||||
r.Handlers.UnmarshalMeta.Run(r)
|
||||
r.Handlers.ValidateResponse.Run(r)
|
||||
if r.Error != nil {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import (
|
|||
// go version 1.4 and 1.5 do not return an error. Version 1.5 will url encode
|
||||
// the uri while 1.4 will not
|
||||
func TestRequestInvalidEndpoint(t *testing.T) {
|
||||
endpoint, _ := endpoints.NormalizeEndpoint("localhost:80 ", "test-service", "test-region", false)
|
||||
endpoint, _ := endpoints.NormalizeEndpoint("localhost:80 ", "test-service", "test-region", false, false)
|
||||
r := request.New(
|
||||
aws.Config{},
|
||||
metadata.ClientInfo{Endpoint: endpoint},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
Package session provides configuration for the SDK's service clients.
|
||||
|
||||
Sessions can be shared across all service clients that share the same base
|
||||
configuration. The Session is built from the SDK's default configuration and
|
||||
request handlers.
|
||||
|
||||
Sessions should be cached when possible, because creating a new Session will
|
||||
load all configuration values from the environment, and config files each time
|
||||
the Session is created. Sharing the Session value across all of your service
|
||||
clients will ensure the configuration is loaded the fewest number of times possible.
|
||||
|
||||
Concurrency
|
||||
|
||||
Sessions are safe to use concurrently as long as the Session is not being
|
||||
modified. The SDK will not modify the Session once the Session has been created.
|
||||
Creating service clients concurrently from a shared Session is safe.
|
||||
|
||||
Sessions from Shared Config
|
||||
|
||||
Sessions can be created using the method above that will only load the
|
||||
additional config if the AWS_SDK_LOAD_CONFIG environment variable is set.
|
||||
Alternatively you can explicitly create a Session with shared config enabled.
|
||||
To do this you can use NewSessionWithOptions to configure how the Session will
|
||||
be created. Using the NewSessionWithOptions with SharedConfigState set to
|
||||
SharedConfigEnabled will create the session as if the AWS_SDK_LOAD_CONFIG
|
||||
environment variable was set.
|
||||
|
||||
Creating Sessions
|
||||
|
||||
When creating Sessions optional aws.Config values can be passed in that will
|
||||
override the default, or loaded config values the Session is being created
|
||||
with. This allows you to provide additional, or case based, configuration
|
||||
as needed.
|
||||
|
||||
By default NewSession will only load credentials from the shared credentials
|
||||
file (~/.aws/credentials). If the AWS_SDK_LOAD_CONFIG environment variable is
|
||||
set to a truthy value the Session will be created from the configuration
|
||||
values from the shared config (~/.aws/config) and shared credentials
|
||||
(~/.aws/credentials) files. See the section Sessions from Shared Config for
|
||||
more information.
|
||||
|
||||
Create a Session with the default config and request handlers. With credentials
|
||||
region, and profile loaded from the environment and shared config automatically.
|
||||
Requires the AWS_PROFILE to be set, or "default" is used.
|
||||
|
||||
// Create Session
|
||||
sess, err := session.NewSession()
|
||||
|
||||
// Create a Session with a custom region
|
||||
sess, err := session.NewSession(&aws.Config{Region: aws.String("us-east-1")})
|
||||
|
||||
// Create a S3 client instance from a session
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
// Handle Session creation error
|
||||
}
|
||||
svc := s3.New(sess)
|
||||
|
||||
Create Session With Option Overrides
|
||||
|
||||
In addition to NewSession, Sessions can be created using NewSessionWithOptions.
|
||||
This func allows you to control and override how the Session will be created
|
||||
through code instead of being driven by environment variables only.
|
||||
|
||||
Use NewSessionWithOptions when you want to provide the config profile, or
|
||||
override the shared config state (AWS_SDK_LOAD_CONFIG).
|
||||
|
||||
// Equivalent to session.NewSession()
|
||||
sess, err := session.NewSessionWithOptions(session.Options{})
|
||||
|
||||
// Specify profile to load for the session's config
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Profile: "profile_name",
|
||||
})
|
||||
|
||||
// Specify profile for config and region for requests
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Config: aws.Config{Region: aws.String("us-east-1")},
|
||||
Profile: "profile_name",
|
||||
})
|
||||
|
||||
// Force enable Shared Config support
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
SharedConfigState: SharedConfigEnable,
|
||||
})
|
||||
|
||||
Adding Handlers
|
||||
|
||||
You can add handlers to a session for processing HTTP requests. All service
|
||||
clients that use the session inherit the handlers. For example, the following
|
||||
handler logs every request and its payload made by a service client:
|
||||
|
||||
// Create a session, and add additional handlers for all service
|
||||
// clients created with the Session to inherit. Adds logging handler.
|
||||
sess, err := session.NewSession()
|
||||
sess.Handlers.Send.PushFront(func(r *request.Request) {
|
||||
// Log every request made and its payload
|
||||
logger.Println("Request: %s/%s, Payload: %s",
|
||||
r.ClientInfo.ServiceName, r.Operation, r.Params)
|
||||
})
|
||||
|
||||
Deprecated "New" function
|
||||
|
||||
The New session function has been deprecated because it does not provide good
|
||||
way to return errors that occur when loading the configuration files and values.
|
||||
Because of this, NewSession was created so errors can be retrieved when
|
||||
creating a session fails.
|
||||
|
||||
Shared Config Fields
|
||||
|
||||
By default the SDK will only load the shared credentials file's (~/.aws/credentials)
|
||||
credentials values, and all other config is provided by the environment variables,
|
||||
SDK defaults, and user provided aws.Config values.
|
||||
|
||||
If the AWS_SDK_LOAD_CONFIG environment variable is set, or SharedConfigEnable
|
||||
option is used to create the Session the full shared config values will be
|
||||
loaded. This includes credentials, region, and support for assume role. In
|
||||
addition the Session will load its configuration from both the shared config
|
||||
file (~/.aws/config) and shared credentials file (~/.aws/credentials). Both
|
||||
files have the same format.
|
||||
|
||||
If both config files are present the configuration from both files will be
|
||||
read. The Session will be created from configuration values from the shared
|
||||
credentials file (~/.aws/credentials) over those in the shared credentials
|
||||
file (~/.aws/config).
|
||||
|
||||
Credentials are the values the SDK should use for authenticating requests with
|
||||
AWS Services. They arfrom a configuration file will need to include both
|
||||
aws_access_key_id and aws_secret_access_key must be provided together in the
|
||||
same file to be considered valid. The values will be ignored if not a complete
|
||||
group. aws_session_token is an optional field that can be provided if both of
|
||||
the other two fields are also provided.
|
||||
|
||||
aws_access_key_id = AKID
|
||||
aws_secret_access_key = SECRET
|
||||
aws_session_token = TOKEN
|
||||
|
||||
Assume Role values allow you to configure the SDK to assume an IAM role using
|
||||
a set of credentials provided in a config file via the source_profile field.
|
||||
Both "role_arn" and "source_profile" are required. The SDK does not support
|
||||
assuming a role with MFA token Via the Session's constructor. You can use the
|
||||
stscreds.AssumeRoleProvider credentials provider to specify custom
|
||||
configuration and support for MFA.
|
||||
|
||||
role_arn = arn:aws:iam::<account_number>:role/<role_name>
|
||||
source_profile = profile_with_creds
|
||||
external_id = 1234
|
||||
mfa_serial = not supported!
|
||||
role_session_name = session_name
|
||||
|
||||
Region is the region the SDK should use for looking up AWS service endpoints
|
||||
and signing requests.
|
||||
|
||||
region = us-east-1
|
||||
|
||||
Environment Variables
|
||||
|
||||
When a Session is created several environment variables can be set to adjust
|
||||
how the SDK functions, and what configuration data it loads when creating
|
||||
Sessions. All environment values are optional, but some values like credentials
|
||||
require multiple of the values to set or the partial values will be ignored.
|
||||
All environment variable values are strings unless otherwise noted.
|
||||
|
||||
Environment configuration values. If set both Access Key ID and Secret Access
|
||||
Key must be provided. Session Token and optionally also be provided, but is
|
||||
not required.
|
||||
|
||||
# Access Key ID
|
||||
AWS_ACCESS_KEY_ID=AKID
|
||||
AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.
|
||||
|
||||
# Secret Access Key
|
||||
AWS_SECRET_ACCESS_KEY=SECRET
|
||||
AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.
|
||||
|
||||
# Session Token
|
||||
AWS_SESSION_TOKEN=TOKEN
|
||||
|
||||
Region value will instruct the SDK where to make service API requests to. If is
|
||||
not provided in the environment the region must be provided before a service
|
||||
client request is made.
|
||||
|
||||
AWS_REGION=us-east-1
|
||||
|
||||
# AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||
# and AWS_REGION is not also set.
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
|
||||
Profile name the SDK should load use when loading shared config from the
|
||||
configuration files. If not provided "default" will be used as the profile name.
|
||||
|
||||
AWS_PROFILE=my_profile
|
||||
|
||||
# AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||
# and AWS_PROFILE is not also set.
|
||||
AWS_DEFAULT_PROFILE=my_profile
|
||||
|
||||
SDK load config instructs the SDK to load the shared config in addition to
|
||||
shared credentials. This also expands the configuration loaded so the shared
|
||||
credentials will have parity with the shared config file. This also enables
|
||||
Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE
|
||||
env values as well.
|
||||
|
||||
AWS_SDK_LOAD_CONFIG=1
|
||||
|
||||
Shared credentials file path can be set to instruct the SDK to use an alternative
|
||||
file for the shared credentials. If not set the file will be loaded from
|
||||
$HOME/.aws/credentials on Linux/Unix based systems, and
|
||||
%USERPROFILE%\.aws\credentials on Windows.
|
||||
|
||||
AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials
|
||||
|
||||
Shared config file path can be set to instruct the SDK to use an alternative
|
||||
file for the shared config. If not set the file will be loaded from
|
||||
$HOME/.aws/config on Linux/Unix based systems, and
|
||||
%USERPROFILE%\.aws\config on Windows.
|
||||
|
||||
AWS_CONFIG_FILE=$HOME/my_shared_config
|
||||
|
||||
|
||||
*/
|
||||
package session
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
// envConfig is a collection of environment values the SDK will read
|
||||
// setup config from. All environment values are optional. But some values
|
||||
// such as credentials require multiple values to be complete or the values
|
||||
// will be ignored.
|
||||
type envConfig struct {
|
||||
// Environment configuration values. If set both Access Key ID and Secret Access
|
||||
// Key must be provided. Session Token and optionally also be provided, but is
|
||||
// not required.
|
||||
//
|
||||
// # Access Key ID
|
||||
// AWS_ACCESS_KEY_ID=AKID
|
||||
// AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.
|
||||
//
|
||||
// # Secret Access Key
|
||||
// AWS_SECRET_ACCESS_KEY=SECRET
|
||||
// AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.
|
||||
//
|
||||
// # Session Token
|
||||
// AWS_SESSION_TOKEN=TOKEN
|
||||
Creds credentials.Value
|
||||
|
||||
// Region value will instruct the SDK where to make service API requests to. If is
|
||||
// not provided in the environment the region must be provided before a service
|
||||
// client request is made.
|
||||
//
|
||||
// AWS_REGION=us-east-1
|
||||
//
|
||||
// # AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||
// # and AWS_REGION is not also set.
|
||||
// AWS_DEFAULT_REGION=us-east-1
|
||||
Region string
|
||||
|
||||
// Profile name the SDK should load use when loading shared configuration from the
|
||||
// shared configuration files. If not provided "default" will be used as the
|
||||
// profile name.
|
||||
//
|
||||
// AWS_PROFILE=my_profile
|
||||
//
|
||||
// # AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set,
|
||||
// # and AWS_PROFILE is not also set.
|
||||
// AWS_DEFAULT_PROFILE=my_profile
|
||||
Profile string
|
||||
|
||||
// SDK load config instructs the SDK to load the shared config in addition to
|
||||
// shared credentials. This also expands the configuration loaded from the shared
|
||||
// credentials to have parity with the shared config file. This also enables
|
||||
// Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE
|
||||
// env values as well.
|
||||
//
|
||||
// AWS_SDK_LOAD_CONFIG=1
|
||||
EnableSharedConfig bool
|
||||
|
||||
// Shared credentials file path can be set to instruct the SDK to use an alternate
|
||||
// file for the shared credentials. If not set the file will be loaded from
|
||||
// $HOME/.aws/credentials on Linux/Unix based systems, and
|
||||
// %USERPROFILE%\.aws\credentials on Windows.
|
||||
//
|
||||
// AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials
|
||||
SharedCredentialsFile string
|
||||
|
||||
// Shared config file path can be set to instruct the SDK to use an alternate
|
||||
// file for the shared config. If not set the file will be loaded from
|
||||
// $HOME/.aws/config on Linux/Unix based systems, and
|
||||
// %USERPROFILE%\.aws\config on Windows.
|
||||
//
|
||||
// AWS_CONFIG_FILE=$HOME/my_shared_config
|
||||
SharedConfigFile string
|
||||
}
|
||||
|
||||
var (
|
||||
credAccessEnvKey = []string{
|
||||
"AWS_ACCESS_KEY_ID",
|
||||
"AWS_ACCESS_KEY",
|
||||
}
|
||||
credSecretEnvKey = []string{
|
||||
"AWS_SECRET_ACCESS_KEY",
|
||||
"AWS_SECRET_KEY",
|
||||
}
|
||||
credSessionEnvKey = []string{
|
||||
"AWS_SESSION_TOKEN",
|
||||
}
|
||||
|
||||
regionEnvKeys = []string{
|
||||
"AWS_REGION",
|
||||
"AWS_DEFAULT_REGION", // Only read if AWS_SDK_LOAD_CONFIG is also set
|
||||
}
|
||||
profileEnvKeys = []string{
|
||||
"AWS_PROFILE",
|
||||
"AWS_DEFAULT_PROFILE", // Only read if AWS_SDK_LOAD_CONFIG is also set
|
||||
}
|
||||
)
|
||||
|
||||
// loadEnvConfig retrieves the SDK's environment configuration.
|
||||
// See `envConfig` for the values that will be retrieved.
|
||||
//
|
||||
// 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
|
||||
// configuration values.
|
||||
func loadEnvConfig() envConfig {
|
||||
enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG"))
|
||||
return envConfigLoad(enableSharedConfig)
|
||||
}
|
||||
|
||||
// loadEnvSharedConfig retrieves the SDK's environment configuration, and the
|
||||
// SDK shared config. See `envConfig` for the values that will be retrieved.
|
||||
//
|
||||
// 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`
|
||||
// environment variable is set.
|
||||
func loadSharedEnvConfig() envConfig {
|
||||
return envConfigLoad(true)
|
||||
}
|
||||
|
||||
func envConfigLoad(enableSharedConfig bool) envConfig {
|
||||
cfg := envConfig{}
|
||||
|
||||
cfg.EnableSharedConfig = enableSharedConfig
|
||||
|
||||
setFromEnvVal(&cfg.Creds.AccessKeyID, credAccessEnvKey)
|
||||
setFromEnvVal(&cfg.Creds.SecretAccessKey, credSecretEnvKey)
|
||||
setFromEnvVal(&cfg.Creds.SessionToken, credSessionEnvKey)
|
||||
|
||||
// Require logical grouping of credentials
|
||||
if len(cfg.Creds.AccessKeyID) == 0 || len(cfg.Creds.SecretAccessKey) == 0 {
|
||||
cfg.Creds = credentials.Value{}
|
||||
} else {
|
||||
cfg.Creds.ProviderName = "EnvConfigCredentials"
|
||||
}
|
||||
|
||||
regionKeys := regionEnvKeys
|
||||
profileKeys := profileEnvKeys
|
||||
if !cfg.EnableSharedConfig {
|
||||
regionKeys = regionKeys[:1]
|
||||
profileKeys = profileKeys[:1]
|
||||
}
|
||||
|
||||
setFromEnvVal(&cfg.Region, regionKeys)
|
||||
setFromEnvVal(&cfg.Profile, profileKeys)
|
||||
|
||||
cfg.SharedCredentialsFile = sharedCredentialsFilename()
|
||||
cfg.SharedConfigFile = sharedConfigFilename()
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
func setFromEnvVal(dst *string, keys []string) {
|
||||
for _, k := range keys {
|
||||
if v := os.Getenv(k); len(v) > 0 {
|
||||
*dst = v
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sharedCredentialsFilename() string {
|
||||
if name := os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); len(name) > 0 {
|
||||
return name
|
||||
}
|
||||
|
||||
return filepath.Join(userHomeDir(), ".aws", "credentials")
|
||||
}
|
||||
|
||||
func sharedConfigFilename() string {
|
||||
if name := os.Getenv("AWS_CONFIG_FILE"); len(name) > 0 {
|
||||
return name
|
||||
}
|
||||
|
||||
return filepath.Join(userHomeDir(), ".aws", "config")
|
||||
}
|
||||
|
||||
func userHomeDir() string {
|
||||
homeDir := os.Getenv("HOME") // *nix
|
||||
if len(homeDir) == 0 { // windows
|
||||
homeDir = os.Getenv("USERPROFILE")
|
||||
}
|
||||
|
||||
return homeDir
|
||||
}
|
||||
|
|
@ -0,0 +1,276 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestLoadEnvConfig_Creds(t *testing.T) {
|
||||
env := stashEnv()
|
||||
defer popEnv(env)
|
||||
|
||||
cases := []struct {
|
||||
Env map[string]string
|
||||
Val credentials.Value
|
||||
}{
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_ACCESS_KEY": "AKID",
|
||||
},
|
||||
Val: credentials.Value{},
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_ACCESS_KEY_ID": "AKID",
|
||||
},
|
||||
Val: credentials.Value{},
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_SECRET_KEY": "SECRET",
|
||||
},
|
||||
Val: credentials.Value{},
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_SECRET_ACCESS_KEY": "SECRET",
|
||||
},
|
||||
Val: credentials.Value{},
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_ACCESS_KEY_ID": "AKID",
|
||||
"AWS_SECRET_ACCESS_KEY": "SECRET",
|
||||
},
|
||||
Val: credentials.Value{
|
||||
AccessKeyID: "AKID", SecretAccessKey: "SECRET",
|
||||
ProviderName: "EnvConfigCredentials",
|
||||
},
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_ACCESS_KEY": "AKID",
|
||||
"AWS_SECRET_KEY": "SECRET",
|
||||
},
|
||||
Val: credentials.Value{
|
||||
AccessKeyID: "AKID", SecretAccessKey: "SECRET",
|
||||
ProviderName: "EnvConfigCredentials",
|
||||
},
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_ACCESS_KEY": "AKID",
|
||||
"AWS_SECRET_KEY": "SECRET",
|
||||
"AWS_SESSION_TOKEN": "TOKEN",
|
||||
},
|
||||
Val: credentials.Value{
|
||||
AccessKeyID: "AKID", SecretAccessKey: "SECRET", SessionToken: "TOKEN",
|
||||
ProviderName: "EnvConfigCredentials",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
os.Clearenv()
|
||||
|
||||
for k, v := range c.Env {
|
||||
os.Setenv(k, v)
|
||||
}
|
||||
|
||||
cfg := loadEnvConfig()
|
||||
assert.Equal(t, c.Val, cfg.Creds)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadEnvConfig(t *testing.T) {
|
||||
env := stashEnv()
|
||||
defer popEnv(env)
|
||||
|
||||
cases := []struct {
|
||||
Env map[string]string
|
||||
Region, Profile string
|
||||
UseSharedConfigCall bool
|
||||
}{
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_REGION": "region",
|
||||
"AWS_PROFILE": "profile",
|
||||
},
|
||||
Region: "region", Profile: "profile",
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_REGION": "region",
|
||||
"AWS_DEFAULT_REGION": "default_region",
|
||||
"AWS_PROFILE": "profile",
|
||||
"AWS_DEFAULT_PROFILE": "default_profile",
|
||||
},
|
||||
Region: "region", Profile: "profile",
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_REGION": "region",
|
||||
"AWS_DEFAULT_REGION": "default_region",
|
||||
"AWS_PROFILE": "profile",
|
||||
"AWS_DEFAULT_PROFILE": "default_profile",
|
||||
"AWS_SDK_LOAD_CONFIG": "1",
|
||||
},
|
||||
Region: "region", Profile: "profile",
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_DEFAULT_REGION": "default_region",
|
||||
"AWS_DEFAULT_PROFILE": "default_profile",
|
||||
},
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_DEFAULT_REGION": "default_region",
|
||||
"AWS_DEFAULT_PROFILE": "default_profile",
|
||||
"AWS_SDK_LOAD_CONFIG": "1",
|
||||
},
|
||||
Region: "default_region", Profile: "default_profile",
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_REGION": "region",
|
||||
"AWS_PROFILE": "profile",
|
||||
},
|
||||
Region: "region", Profile: "profile",
|
||||
UseSharedConfigCall: true,
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_REGION": "region",
|
||||
"AWS_DEFAULT_REGION": "default_region",
|
||||
"AWS_PROFILE": "profile",
|
||||
"AWS_DEFAULT_PROFILE": "default_profile",
|
||||
},
|
||||
Region: "region", Profile: "profile",
|
||||
UseSharedConfigCall: true,
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_REGION": "region",
|
||||
"AWS_DEFAULT_REGION": "default_region",
|
||||
"AWS_PROFILE": "profile",
|
||||
"AWS_DEFAULT_PROFILE": "default_profile",
|
||||
"AWS_SDK_LOAD_CONFIG": "1",
|
||||
},
|
||||
Region: "region", Profile: "profile",
|
||||
UseSharedConfigCall: true,
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_DEFAULT_REGION": "default_region",
|
||||
"AWS_DEFAULT_PROFILE": "default_profile",
|
||||
},
|
||||
Region: "default_region", Profile: "default_profile",
|
||||
UseSharedConfigCall: true,
|
||||
},
|
||||
{
|
||||
Env: map[string]string{
|
||||
"AWS_DEFAULT_REGION": "default_region",
|
||||
"AWS_DEFAULT_PROFILE": "default_profile",
|
||||
"AWS_SDK_LOAD_CONFIG": "1",
|
||||
},
|
||||
Region: "default_region", Profile: "default_profile",
|
||||
UseSharedConfigCall: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
os.Clearenv()
|
||||
|
||||
for k, v := range c.Env {
|
||||
os.Setenv(k, v)
|
||||
}
|
||||
|
||||
var cfg envConfig
|
||||
if c.UseSharedConfigCall {
|
||||
cfg = loadSharedEnvConfig()
|
||||
} else {
|
||||
cfg = loadEnvConfig()
|
||||
}
|
||||
|
||||
assert.Equal(t, c.Region, cfg.Region)
|
||||
assert.Equal(t, c.Profile, cfg.Profile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedCredsFilename(t *testing.T) {
|
||||
env := stashEnv()
|
||||
defer popEnv(env)
|
||||
|
||||
os.Setenv("USERPROFILE", "profile_dir")
|
||||
expect := filepath.Join("profile_dir", ".aws", "credentials")
|
||||
name := sharedCredentialsFilename()
|
||||
assert.Equal(t, expect, name)
|
||||
|
||||
os.Setenv("HOME", "home_dir")
|
||||
expect = filepath.Join("home_dir", ".aws", "credentials")
|
||||
name = sharedCredentialsFilename()
|
||||
assert.Equal(t, expect, name)
|
||||
|
||||
expect = filepath.Join("path/to/credentials/file")
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", expect)
|
||||
name = sharedCredentialsFilename()
|
||||
assert.Equal(t, expect, name)
|
||||
}
|
||||
|
||||
func TestSharedConfigFilename(t *testing.T) {
|
||||
env := stashEnv()
|
||||
defer popEnv(env)
|
||||
|
||||
os.Setenv("USERPROFILE", "profile_dir")
|
||||
expect := filepath.Join("profile_dir", ".aws", "config")
|
||||
name := sharedConfigFilename()
|
||||
assert.Equal(t, expect, name)
|
||||
|
||||
os.Setenv("HOME", "home_dir")
|
||||
expect = filepath.Join("home_dir", ".aws", "config")
|
||||
name = sharedConfigFilename()
|
||||
assert.Equal(t, expect, name)
|
||||
|
||||
expect = filepath.Join("path/to/config/file")
|
||||
os.Setenv("AWS_CONFIG_FILE", expect)
|
||||
name = sharedConfigFilename()
|
||||
assert.Equal(t, expect, name)
|
||||
}
|
||||
|
||||
func TestSetEnvValue(t *testing.T) {
|
||||
env := stashEnv()
|
||||
defer popEnv(env)
|
||||
|
||||
os.Setenv("empty_key", "")
|
||||
os.Setenv("second_key", "2")
|
||||
os.Setenv("third_key", "3")
|
||||
|
||||
var dst string
|
||||
setFromEnvVal(&dst, []string{
|
||||
"empty_key", "first_key", "second_key", "third_key",
|
||||
})
|
||||
|
||||
assert.Equal(t, "2", dst)
|
||||
}
|
||||
|
||||
func stashEnv() []string {
|
||||
env := os.Environ()
|
||||
os.Clearenv()
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
func popEnv(env []string) {
|
||||
os.Clearenv()
|
||||
|
||||
for _, e := range env {
|
||||
p := strings.SplitN(e, "=", 2)
|
||||
os.Setenv(p[0], p[1])
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,14 @@
|
|||
// Package session provides a way to create service clients with shared configuration
|
||||
// and handlers.
|
||||
//
|
||||
// Generally this package should be used instead of the `defaults` package.
|
||||
//
|
||||
// A session should be used to share configurations and request handlers between multiple
|
||||
// service clients. When service clients need specific configuration aws.Config can be
|
||||
// used to provide additional configuration directly to the service client.
|
||||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/private/endpoints"
|
||||
|
|
@ -21,36 +18,204 @@ import (
|
|||
// store configurations and request handlers for those services.
|
||||
//
|
||||
// Sessions are safe to create service clients concurrently, but it is not safe
|
||||
// to mutate the session concurrently.
|
||||
// to mutate the Session concurrently.
|
||||
//
|
||||
// The Session satisfies the service client's client.ClientConfigProvider.
|
||||
type Session struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// New creates a new instance of the handlers merging in the provided Configs
|
||||
// on top of the SDK's default configurations. Once the session is created it
|
||||
// can be mutated to modify Configs or Handlers. The session is safe to be read
|
||||
// concurrently, but it should not be written to concurrently.
|
||||
// New creates a new instance of the handlers merging in the provided configs
|
||||
// on top of the SDK's default configurations. Once the Session is created it
|
||||
// can be mutated to modify the Config or Handlers. The Session is safe to be
|
||||
// read concurrently, but it should not be written to concurrently.
|
||||
//
|
||||
// Example:
|
||||
// // Create a session with the default config and request handlers.
|
||||
// sess := session.New()
|
||||
// If the AWS_SDK_LOAD_CONFIG environment is set to a truthy value, the New
|
||||
// method could now encounter an error when loading the configuration. When
|
||||
// The environment variable is set, and an error occurs, New will return a
|
||||
// session that will fail all requests reporting the error that occured while
|
||||
// loading the session. Use NewSession to get the error when creating the
|
||||
// session.
|
||||
//
|
||||
// // Create a session with a custom region
|
||||
// sess := session.New(&aws.Config{Region: aws.String("us-east-1")})
|
||||
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||
// the shared config file (~/.aws/config) will also be loaded, in addition to
|
||||
// the shared credentials file (~/.aws/config). Values set in both the
|
||||
// shared config, and shared credentials will be taken from the shared
|
||||
// credentials file.
|
||||
//
|
||||
// // Create a session, and add additional handlers for all service
|
||||
// // clients created with the session to inherit. Adds logging handler.
|
||||
// sess := session.New()
|
||||
// sess.Handlers.Send.PushFront(func(r *request.Request) {
|
||||
// // Log every request made and its payload
|
||||
// logger.Println("Request: %s/%s, Payload: %s", r.ClientInfo.ServiceName, r.Operation, r.Params)
|
||||
// Deprecated: Use NewSession functiions to create sessions instead. NewSession
|
||||
// has the same functionality as New except an error can be returned when the
|
||||
// func is called instead of waiting to receive an error until a request is made.
|
||||
func New(cfgs ...*aws.Config) *Session {
|
||||
// load initial config from environment
|
||||
envCfg := loadEnvConfig()
|
||||
|
||||
if envCfg.EnableSharedConfig {
|
||||
s, err := newSession(envCfg, cfgs...)
|
||||
if err != nil {
|
||||
// Old session.New expected all errors to be discovered when
|
||||
// a request is made, and would report the errors then. This
|
||||
// needs to be replicated if an error occurs while creating
|
||||
// the session.
|
||||
msg := "failed to create session with AWS_SDK_LOAD_CONFIG enabled. " +
|
||||
"Use session.NewSession to handle errors occuring during session creation."
|
||||
|
||||
// Session creation failed, need to report the error and prevent
|
||||
// any requests from succeeding.
|
||||
s = &Session{Config: defaults.Config()}
|
||||
s.Config.MergeIn(cfgs...)
|
||||
s.Config.Logger.Log("ERROR:", msg, "Error:", err)
|
||||
s.Handlers.Validate.PushBack(func(r *request.Request) {
|
||||
r.Error = err
|
||||
})
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
return oldNewSession(cfgs...)
|
||||
}
|
||||
|
||||
// NewSession returns a new Session created from SDK defaults, config files,
|
||||
// environment, and user provided config files. Once the Session is created
|
||||
// it can be mutated to modify the Config or Handlers. The Session is safe to
|
||||
// be read concurrently, but it should not be written to concurrently.
|
||||
//
|
||||
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||
// the shared config file (~/.aws/config) will also be loaded in addition to
|
||||
// the shared credentials file (~/.aws/config). Values set in both the
|
||||
// shared config, and shared credentials will be taken from the shared
|
||||
// credentials file. Enabling the Shared Config will also allow the Session
|
||||
// to be built with retrieving credentials with AssumeRole set in the config.
|
||||
//
|
||||
// See the NewSessionWithOptions func for information on how to override or
|
||||
// control through code how the Session will be created. Such as specifing the
|
||||
// config profile, and controlling if shared config is enabled or not.
|
||||
func NewSession(cfgs ...*aws.Config) (*Session, error) {
|
||||
envCfg := loadEnvConfig()
|
||||
|
||||
return newSession(envCfg, cfgs...)
|
||||
}
|
||||
|
||||
// SharedConfigState provides the ability to optionally override the state
|
||||
// of the session's creation based on the shared config being enabled or
|
||||
// disabled.
|
||||
type SharedConfigState int
|
||||
|
||||
const (
|
||||
// SharedConfigStateFromEnv does not override any state of the
|
||||
// AWS_SDK_LOAD_CONFIG env var. It is the default value of the
|
||||
// SharedConfigState type.
|
||||
SharedConfigStateFromEnv SharedConfigState = iota
|
||||
|
||||
// SharedConfigDisable overrides the AWS_SDK_LOAD_CONFIG env var value
|
||||
// and disables the shared config functionality.
|
||||
SharedConfigDisable
|
||||
|
||||
// SharedConfigEnable overrides the AWS_SDK_LOAD_CONFIG env var value
|
||||
// and enables the shared config functionality.
|
||||
SharedConfigEnable
|
||||
)
|
||||
|
||||
// Options provides the means to control how a Session is created and what
|
||||
// configuration values will be loaded.
|
||||
//
|
||||
type Options struct {
|
||||
// Provides config values for the SDK to use when creating service clients
|
||||
// and making API requests to services. Any value set in with this field
|
||||
// will override the associated value provided by the SDK defaults,
|
||||
// environment or config files where relevent.
|
||||
//
|
||||
// If not set, configuration values from from SDK defaults, environment,
|
||||
// config will be used.
|
||||
Config aws.Config
|
||||
|
||||
// Overrides the config profile the Session should be created from. If not
|
||||
// set the value of the environment variable will be loaded (AWS_PROFILE,
|
||||
// or AWS_DEFAULT_PROFILE if the Shared Config is enabled).
|
||||
//
|
||||
// If not set and environment variables are not set the "default"
|
||||
// (DefaultSharedConfigProfile) will be used as the profile to load the
|
||||
// session config from.
|
||||
Profile string
|
||||
|
||||
// Instructs how the Session will be created based on the AWS_SDK_LOAD_CONFIG
|
||||
// environment variable. By default a Session will be created using the
|
||||
// value provided by the AWS_SDK_LOAD_CONFIG environment variable.
|
||||
//
|
||||
// Setting this value to SharedConfigEnable or SharedConfigDisable
|
||||
// will allow you to override the AWS_SDK_LOAD_CONFIG environment variable
|
||||
// and enable or disable the shared config functionality.
|
||||
SharedConfigState SharedConfigState
|
||||
}
|
||||
|
||||
// NewSessionWithOptions returns a new Session created from SDK defaults, config files,
|
||||
// environment, and user provided config files. This func uses the Options
|
||||
// values to configure how the Session is created.
|
||||
//
|
||||
// If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
|
||||
// the shared config file (~/.aws/config) will also be loaded in addition to
|
||||
// the shared credentials file (~/.aws/config). Values set in both the
|
||||
// shared config, and shared credentials will be taken from the shared
|
||||
// credentials file. Enabling the Shared Config will also allow the Session
|
||||
// to be built with retrieving credentials with AssumeRole set in the config.
|
||||
//
|
||||
// // Equivalent to session.New
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{})
|
||||
//
|
||||
// // Specify profile to load for the session's config
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||
// Profile: "profile_name",
|
||||
// })
|
||||
//
|
||||
// // Create a S3 client instance from a session
|
||||
// sess := session.New()
|
||||
// svc := s3.New(sess)
|
||||
func New(cfgs ...*aws.Config) *Session {
|
||||
// // Specify profile for config and region for requests
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||
// Config: aws.Config{Region: aws.String("us-east-1")},
|
||||
// Profile: "profile_name",
|
||||
// })
|
||||
//
|
||||
// // Force enable Shared Config support
|
||||
// sess, err := session.NewSessionWithOptions(session.Options{
|
||||
// SharedConfigState: SharedConfigEnable,
|
||||
// })
|
||||
func NewSessionWithOptions(opts Options) (*Session, error) {
|
||||
var envCfg envConfig
|
||||
if opts.SharedConfigState == SharedConfigEnable {
|
||||
envCfg = loadSharedEnvConfig()
|
||||
} else {
|
||||
envCfg = loadEnvConfig()
|
||||
}
|
||||
|
||||
if len(opts.Profile) > 0 {
|
||||
envCfg.Profile = opts.Profile
|
||||
}
|
||||
|
||||
switch opts.SharedConfigState {
|
||||
case SharedConfigDisable:
|
||||
envCfg.EnableSharedConfig = false
|
||||
case SharedConfigEnable:
|
||||
envCfg.EnableSharedConfig = true
|
||||
}
|
||||
|
||||
return newSession(envCfg, &opts.Config)
|
||||
}
|
||||
|
||||
// Must is a helper function to ensure the Session is valid and there was no
|
||||
// error when calling a NewSession function.
|
||||
//
|
||||
// This helper is intended to be used in variable initialization to load the
|
||||
// Session and configuration at startup. Such as:
|
||||
//
|
||||
// var sess = session.Must(session.NewSession())
|
||||
func Must(sess *Session, err error) *Session {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return sess
|
||||
}
|
||||
|
||||
func oldNewSession(cfgs ...*aws.Config) *Session {
|
||||
cfg := defaults.Config()
|
||||
handlers := defaults.Handlers()
|
||||
|
||||
|
|
@ -72,6 +237,115 @@ func New(cfgs ...*aws.Config) *Session {
|
|||
return s
|
||||
}
|
||||
|
||||
func newSession(envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
|
||||
cfg := defaults.Config()
|
||||
handlers := defaults.Handlers()
|
||||
|
||||
// Get a merged version of the user provided config to determine if
|
||||
// credentials were.
|
||||
userCfg := &aws.Config{}
|
||||
userCfg.MergeIn(cfgs...)
|
||||
|
||||
// Order config files will be loaded in with later files overwriting
|
||||
// previous config file values.
|
||||
cfgFiles := []string{envCfg.SharedConfigFile, envCfg.SharedCredentialsFile}
|
||||
if !envCfg.EnableSharedConfig {
|
||||
// The shared config file (~/.aws/config) is only loaded if instructed
|
||||
// to load via the envConfig.EnableSharedConfig (AWS_SDK_LOAD_CONFIG).
|
||||
cfgFiles = cfgFiles[1:]
|
||||
}
|
||||
|
||||
// Load additional config from file(s)
|
||||
sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers)
|
||||
|
||||
s := &Session{
|
||||
Config: cfg,
|
||||
Handlers: handlers,
|
||||
}
|
||||
|
||||
initHandlers(s)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers) {
|
||||
// Merge in user provided configuration
|
||||
cfg.MergeIn(userCfg)
|
||||
|
||||
// Region if not already set by user
|
||||
if len(aws.StringValue(cfg.Region)) == 0 {
|
||||
if len(envCfg.Region) > 0 {
|
||||
cfg.WithRegion(envCfg.Region)
|
||||
} else if envCfg.EnableSharedConfig && len(sharedCfg.Region) > 0 {
|
||||
cfg.WithRegion(sharedCfg.Region)
|
||||
}
|
||||
}
|
||||
|
||||
// Configure credentials if not already set
|
||||
if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
|
||||
if len(envCfg.Creds.AccessKeyID) > 0 {
|
||||
cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||
envCfg.Creds,
|
||||
)
|
||||
} else if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.RoleARN) > 0 && sharedCfg.AssumeRoleSource != nil {
|
||||
cfgCp := *cfg
|
||||
cfgCp.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||
sharedCfg.AssumeRoleSource.Creds,
|
||||
)
|
||||
cfg.Credentials = stscreds.NewCredentials(
|
||||
&Session{
|
||||
Config: &cfgCp,
|
||||
Handlers: handlers.Copy(),
|
||||
},
|
||||
sharedCfg.AssumeRole.RoleARN,
|
||||
func(opt *stscreds.AssumeRoleProvider) {
|
||||
opt.RoleSessionName = sharedCfg.AssumeRole.RoleSessionName
|
||||
|
||||
if len(sharedCfg.AssumeRole.ExternalID) > 0 {
|
||||
opt.ExternalID = aws.String(sharedCfg.AssumeRole.ExternalID)
|
||||
}
|
||||
|
||||
// MFA not supported
|
||||
},
|
||||
)
|
||||
} else if len(sharedCfg.Creds.AccessKeyID) > 0 {
|
||||
cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
|
||||
sharedCfg.Creds,
|
||||
)
|
||||
} else {
|
||||
// Fallback to default credentials provider, include mock errors
|
||||
// for the credential chain so user can identify why credentials
|
||||
// failed to be retrieved.
|
||||
cfg.Credentials = credentials.NewCredentials(&credentials.ChainProvider{
|
||||
VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
|
||||
Providers: []credentials.Provider{
|
||||
&credProviderError{Err: awserr.New("EnvAccessKeyNotFound", "failed to find credentials in the environment.", nil)},
|
||||
&credProviderError{Err: awserr.New("SharedCredsLoad", fmt.Sprintf("failed to load profile, %s.", envCfg.Profile), nil)},
|
||||
defaults.RemoteCredProvider(*cfg, handlers),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type credProviderError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
var emptyCreds = credentials.Value{}
|
||||
|
||||
func (c credProviderError) Retrieve() (credentials.Value, error) {
|
||||
return credentials.Value{}, c.Err
|
||||
}
|
||||
func (c credProviderError) IsExpired() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func initHandlers(s *Session) {
|
||||
// Add the Validate parameter handler if it is not disabled.
|
||||
s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
|
||||
|
|
@ -80,12 +354,11 @@ func initHandlers(s *Session) {
|
|||
}
|
||||
}
|
||||
|
||||
// Copy creates and returns a copy of the current session, coping the config
|
||||
// Copy creates and returns a copy of the current Session, coping the config
|
||||
// and handlers. If any additional configs are provided they will be merged
|
||||
// on top of the session's copied config.
|
||||
// on top of the Session's copied config.
|
||||
//
|
||||
// Example:
|
||||
// // Create a copy of the current session, configured for the us-west-2 region.
|
||||
// // Create a copy of the current Session, configured for the us-west-2 region.
|
||||
// sess.Copy(&aws.Config{Region: aws.String("us-west-2")})
|
||||
func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
||||
newSession := &Session{
|
||||
|
|
@ -101,15 +374,15 @@ func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
|||
// ClientConfig satisfies the client.ConfigProvider interface and is used to
|
||||
// configure the service client instances. Passing the Session to the service
|
||||
// client's constructor (New) will use this method to configure the client.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.New()
|
||||
// s3.New(sess)
|
||||
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
|
||||
s = s.Copy(cfgs...)
|
||||
endpoint, signingRegion := endpoints.NormalizeEndpoint(
|
||||
aws.StringValue(s.Config.Endpoint), serviceName,
|
||||
aws.StringValue(s.Config.Region), aws.BoolValue(s.Config.DisableSSL))
|
||||
aws.StringValue(s.Config.Endpoint),
|
||||
serviceName,
|
||||
aws.StringValue(s.Config.Region),
|
||||
aws.BoolValue(s.Config.DisableSSL),
|
||||
aws.BoolValue(s.Config.UseDualStack),
|
||||
)
|
||||
|
||||
return client.Config{
|
||||
Config: s.Config,
|
||||
|
|
|
|||
|
|
@ -1,20 +1,344 @@
|
|||
package session_test
|
||||
package session
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
func TestNewDefaultSession(t *testing.T) {
|
||||
s := session.New(&aws.Config{Region: aws.String("region")})
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
s := New(&aws.Config{Region: aws.String("region")})
|
||||
|
||||
assert.Equal(t, "region", *s.Config.Region)
|
||||
assert.Equal(t, http.DefaultClient, s.Config.HTTPClient)
|
||||
assert.NotNil(t, s.Config.Logger)
|
||||
assert.Equal(t, aws.LogOff, *s.Config.LogLevel)
|
||||
}
|
||||
|
||||
func TestNew_WithCustomCreds(t *testing.T) {
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
customCreds := credentials.NewStaticCredentials("AKID", "SECRET", "TOKEN")
|
||||
s := New(&aws.Config{Credentials: customCreds})
|
||||
|
||||
assert.Equal(t, customCreds, s.Config.Credentials)
|
||||
}
|
||||
|
||||
type mockLogger struct {
|
||||
*bytes.Buffer
|
||||
}
|
||||
|
||||
func (w mockLogger) Log(args ...interface{}) {
|
||||
fmt.Fprintln(w, args...)
|
||||
}
|
||||
|
||||
func TestNew_WithSessionLoadError(t *testing.T) {
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
os.Setenv("AWS_SDK_LOAD_CONFIG", "1")
|
||||
os.Setenv("AWS_CONFIG_FILE", testConfigFilename)
|
||||
os.Setenv("AWS_PROFILE", "assume_role_invalid_source_profile")
|
||||
|
||||
logger := bytes.Buffer{}
|
||||
s := New(&aws.Config{Logger: &mockLogger{&logger}})
|
||||
|
||||
assert.NotNil(t, s)
|
||||
|
||||
svc := s3.New(s)
|
||||
_, err := svc.ListBuckets(&s3.ListBucketsInput{})
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, logger.String(), "ERROR: failed to create session with AWS_SDK_LOAD_CONFIG enabled")
|
||||
assert.Contains(t, err.Error(), SharedConfigAssumeRoleError{
|
||||
RoleARN: "assume_role_invalid_source_profile_role_arn",
|
||||
}.Error())
|
||||
}
|
||||
|
||||
func TestSessionCopy(t *testing.T) {
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
os.Setenv("AWS_REGION", "orig_region")
|
||||
|
||||
s := Session{
|
||||
Config: defaults.Config(),
|
||||
Handlers: defaults.Handlers(),
|
||||
}
|
||||
|
||||
newSess := s.Copy(&aws.Config{Region: aws.String("new_region")})
|
||||
|
||||
assert.Equal(t, "orig_region", *s.Config.Region)
|
||||
assert.Equal(t, "new_region", *newSess.Config.Region)
|
||||
}
|
||||
|
||||
func TestSessionClientConfig(t *testing.T) {
|
||||
s, err := NewSession(&aws.Config{Region: aws.String("orig_region")})
|
||||
assert.NoError(t, err)
|
||||
|
||||
cfg := s.ClientConfig("s3", &aws.Config{Region: aws.String("us-west-2")})
|
||||
|
||||
assert.Equal(t, "https://s3-us-west-2.amazonaws.com", cfg.Endpoint)
|
||||
assert.Empty(t, cfg.SigningRegion)
|
||||
assert.Equal(t, "us-west-2", *cfg.Config.Region)
|
||||
}
|
||||
|
||||
func TestNewSession_NoCredentials(t *testing.T) {
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
s, err := NewSession()
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, s.Config.Credentials)
|
||||
assert.NotEqual(t, credentials.AnonymousCredentials, s.Config.Credentials)
|
||||
}
|
||||
|
||||
func TestNewSessionWithOptions_OverrideProfile(t *testing.T) {
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
os.Setenv("AWS_SDK_LOAD_CONFIG", "1")
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename)
|
||||
os.Setenv("AWS_PROFILE", "other_profile")
|
||||
|
||||
s, err := NewSessionWithOptions(Options{
|
||||
Profile: "full_profile",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "full_profile_region", *s.Config.Region)
|
||||
|
||||
creds, err := s.Config.Credentials.Get()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "full_profile_akid", creds.AccessKeyID)
|
||||
assert.Equal(t, "full_profile_secret", creds.SecretAccessKey)
|
||||
assert.Empty(t, creds.SessionToken)
|
||||
assert.Contains(t, creds.ProviderName, "SharedConfigCredentials")
|
||||
}
|
||||
|
||||
func TestNewSessionWithOptions_OverrideSharedConfigEnable(t *testing.T) {
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
os.Setenv("AWS_SDK_LOAD_CONFIG", "0")
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename)
|
||||
os.Setenv("AWS_PROFILE", "full_profile")
|
||||
|
||||
s, err := NewSessionWithOptions(Options{
|
||||
SharedConfigState: SharedConfigEnable,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "full_profile_region", *s.Config.Region)
|
||||
|
||||
creds, err := s.Config.Credentials.Get()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "full_profile_akid", creds.AccessKeyID)
|
||||
assert.Equal(t, "full_profile_secret", creds.SecretAccessKey)
|
||||
assert.Empty(t, creds.SessionToken)
|
||||
assert.Contains(t, creds.ProviderName, "SharedConfigCredentials")
|
||||
}
|
||||
|
||||
func TestNewSessionWithOptions_OverrideSharedConfigDisable(t *testing.T) {
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
os.Setenv("AWS_SDK_LOAD_CONFIG", "1")
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename)
|
||||
os.Setenv("AWS_PROFILE", "full_profile")
|
||||
|
||||
s, err := NewSessionWithOptions(Options{
|
||||
SharedConfigState: SharedConfigDisable,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Empty(t, *s.Config.Region)
|
||||
|
||||
creds, err := s.Config.Credentials.Get()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "full_profile_akid", creds.AccessKeyID)
|
||||
assert.Equal(t, "full_profile_secret", creds.SecretAccessKey)
|
||||
assert.Empty(t, creds.SessionToken)
|
||||
assert.Contains(t, creds.ProviderName, "SharedConfigCredentials")
|
||||
}
|
||||
|
||||
func TestNewSessionWithOptions_Overrides(t *testing.T) {
|
||||
cases := []struct {
|
||||
InEnvs map[string]string
|
||||
InProfile string
|
||||
OutRegion string
|
||||
OutCreds credentials.Value
|
||||
}{
|
||||
{
|
||||
InEnvs: map[string]string{
|
||||
"AWS_SDK_LOAD_CONFIG": "0",
|
||||
"AWS_SHARED_CREDENTIALS_FILE": testConfigFilename,
|
||||
"AWS_PROFILE": "other_profile",
|
||||
},
|
||||
InProfile: "full_profile",
|
||||
OutRegion: "full_profile_region",
|
||||
OutCreds: credentials.Value{
|
||||
AccessKeyID: "full_profile_akid",
|
||||
SecretAccessKey: "full_profile_secret",
|
||||
ProviderName: "SharedConfigCredentials",
|
||||
},
|
||||
},
|
||||
{
|
||||
InEnvs: map[string]string{
|
||||
"AWS_SDK_LOAD_CONFIG": "0",
|
||||
"AWS_SHARED_CREDENTIALS_FILE": testConfigFilename,
|
||||
"AWS_REGION": "env_region",
|
||||
"AWS_ACCESS_KEY": "env_akid",
|
||||
"AWS_SECRET_ACCESS_KEY": "env_secret",
|
||||
"AWS_PROFILE": "other_profile",
|
||||
},
|
||||
InProfile: "full_profile",
|
||||
OutRegion: "env_region",
|
||||
OutCreds: credentials.Value{
|
||||
AccessKeyID: "env_akid",
|
||||
SecretAccessKey: "env_secret",
|
||||
ProviderName: "EnvConfigCredentials",
|
||||
},
|
||||
},
|
||||
{
|
||||
InEnvs: map[string]string{
|
||||
"AWS_SDK_LOAD_CONFIG": "0",
|
||||
"AWS_SHARED_CREDENTIALS_FILE": testConfigFilename,
|
||||
"AWS_CONFIG_FILE": testConfigOtherFilename,
|
||||
"AWS_PROFILE": "shared_profile",
|
||||
},
|
||||
InProfile: "config_file_load_order",
|
||||
OutRegion: "shared_config_region",
|
||||
OutCreds: credentials.Value{
|
||||
AccessKeyID: "shared_config_akid",
|
||||
SecretAccessKey: "shared_config_secret",
|
||||
ProviderName: "SharedConfigCredentials",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
for k, v := range c.InEnvs {
|
||||
os.Setenv(k, v)
|
||||
}
|
||||
|
||||
s, err := NewSessionWithOptions(Options{
|
||||
Profile: c.InProfile,
|
||||
SharedConfigState: SharedConfigEnable,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
creds, err := s.Config.Credentials.Get()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.OutRegion, *s.Config.Region)
|
||||
assert.Equal(t, c.OutCreds.AccessKeyID, creds.AccessKeyID)
|
||||
assert.Equal(t, c.OutCreds.SecretAccessKey, creds.SecretAccessKey)
|
||||
assert.Equal(t, c.OutCreds.SessionToken, creds.SessionToken)
|
||||
assert.Contains(t, creds.ProviderName, c.OutCreds.ProviderName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSesisonAssumeRole(t *testing.T) {
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
os.Setenv("AWS_REGION", "us-east-1")
|
||||
os.Setenv("AWS_SDK_LOAD_CONFIG", "1")
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename)
|
||||
os.Setenv("AWS_PROFILE", "assume_role_w_creds")
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
const respMsg = `
|
||||
<AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
|
||||
<AssumeRoleResult>
|
||||
<AssumedRoleUser>
|
||||
<Arn>arn:aws:sts::account_id:assumed-role/role/session_name</Arn>
|
||||
<AssumedRoleId>AKID:session_name</AssumedRoleId>
|
||||
</AssumedRoleUser>
|
||||
<Credentials>
|
||||
<AccessKeyId>AKID</AccessKeyId>
|
||||
<SecretAccessKey>SECRET</SecretAccessKey>
|
||||
<SessionToken>SESSION_TOKEN</SessionToken>
|
||||
<Expiration>%s</Expiration>
|
||||
</Credentials>
|
||||
</AssumeRoleResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>request-id</RequestId>
|
||||
</ResponseMetadata>
|
||||
</AssumeRoleResponse>
|
||||
`
|
||||
w.Write([]byte(fmt.Sprintf(respMsg, time.Now().Add(15*time.Minute).Format("2006-01-02T15:04:05Z"))))
|
||||
}))
|
||||
|
||||
s, err := NewSession(&aws.Config{Endpoint: aws.String(server.URL), DisableSSL: aws.Bool(true)})
|
||||
|
||||
creds, err := s.Config.Credentials.Get()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "AKID", creds.AccessKeyID)
|
||||
assert.Equal(t, "SECRET", creds.SecretAccessKey)
|
||||
assert.Equal(t, "SESSION_TOKEN", creds.SessionToken)
|
||||
assert.Contains(t, creds.ProviderName, "AssumeRoleProvider")
|
||||
}
|
||||
|
||||
func TestSessionAssumeRole_DisableSharedConfig(t *testing.T) {
|
||||
// Backwards compatibility with Shared config disabled
|
||||
// assume role should not be built into the config.
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
os.Setenv("AWS_SDK_LOAD_CONFIG", "0")
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename)
|
||||
os.Setenv("AWS_PROFILE", "assume_role_w_creds")
|
||||
|
||||
s, err := NewSession()
|
||||
assert.NoError(t, err)
|
||||
|
||||
creds, err := s.Config.Credentials.Get()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "assume_role_w_creds_akid", creds.AccessKeyID)
|
||||
assert.Equal(t, "assume_role_w_creds_secret", creds.SecretAccessKey)
|
||||
assert.Contains(t, creds.ProviderName, "SharedConfigCredentials")
|
||||
}
|
||||
|
||||
func TestSessionAssumeRole_InvalidSourceProfile(t *testing.T) {
|
||||
// Backwards compatibility with Shared config disabled
|
||||
// assume role should not be built into the config.
|
||||
oldEnv := initSessionTestEnv()
|
||||
defer popEnv(oldEnv)
|
||||
|
||||
os.Setenv("AWS_SDK_LOAD_CONFIG", "1")
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", testConfigFilename)
|
||||
os.Setenv("AWS_PROFILE", "assume_role_invalid_source_profile")
|
||||
|
||||
s, err := NewSession()
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "SharedConfigAssumeRoleError: failed to load assume role")
|
||||
assert.Nil(t, s)
|
||||
}
|
||||
|
||||
func initSessionTestEnv() (oldEnv []string) {
|
||||
oldEnv = stashEnv()
|
||||
os.Setenv("AWS_CONFIG_FILE", "file_not_exists")
|
||||
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", "file_not_exists")
|
||||
|
||||
return oldEnv
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,295 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/go-ini/ini"
|
||||
)
|
||||
|
||||
const (
|
||||
// Static Credentials group
|
||||
accessKeyIDKey = `aws_access_key_id` // group required
|
||||
secretAccessKey = `aws_secret_access_key` // group required
|
||||
sessionTokenKey = `aws_session_token` // optional
|
||||
|
||||
// Assume Role Credentials group
|
||||
roleArnKey = `role_arn` // group required
|
||||
sourceProfileKey = `source_profile` // group required
|
||||
externalIDKey = `external_id` // optional
|
||||
mfaSerialKey = `mfa_serial` // optional
|
||||
roleSessionNameKey = `role_session_name` // optional
|
||||
|
||||
// Additional Config fields
|
||||
regionKey = `region`
|
||||
|
||||
// DefaultSharedConfigProfile is the default profile to be used when
|
||||
// loading configuration from the config files if another profile name
|
||||
// is not provided.
|
||||
DefaultSharedConfigProfile = `default`
|
||||
)
|
||||
|
||||
type assumeRoleConfig struct {
|
||||
RoleARN string
|
||||
SourceProfile string
|
||||
ExternalID string
|
||||
MFASerial string
|
||||
RoleSessionName string
|
||||
}
|
||||
|
||||
// sharedConfig represents the configuration fields of the SDK config files.
|
||||
type sharedConfig struct {
|
||||
// Credentials values from the config file. Both aws_access_key_id
|
||||
// and aws_secret_access_key must be provided together in the same file
|
||||
// to be considered valid. The values will be ignored if not a complete group.
|
||||
// aws_session_token is an optional field that can be provided if both of the
|
||||
// other two fields are also provided.
|
||||
//
|
||||
// aws_access_key_id
|
||||
// aws_secret_access_key
|
||||
// aws_session_token
|
||||
Creds credentials.Value
|
||||
|
||||
AssumeRole assumeRoleConfig
|
||||
AssumeRoleSource *sharedConfig
|
||||
|
||||
// Region is the region the SDK should use for looking up AWS service endpoints
|
||||
// and signing requests.
|
||||
//
|
||||
// region
|
||||
Region string
|
||||
}
|
||||
|
||||
type sharedConfigFile struct {
|
||||
Filename string
|
||||
IniData *ini.File
|
||||
}
|
||||
|
||||
// loadSharedConfig retrieves the configuration from the list of files
|
||||
// using the profile provided. The order the files are listed will determine
|
||||
// precedence. Values in subsequent files will overwrite values defined in
|
||||
// earlier files.
|
||||
//
|
||||
// For example, given two files A and B. Both define credentials. If the order
|
||||
// of the files are A then B, B's credential values will be used instead of A's.
|
||||
//
|
||||
// See sharedConfig.setFromFile for information how the config files
|
||||
// will be loaded.
|
||||
func loadSharedConfig(profile string, filenames []string) (sharedConfig, error) {
|
||||
if len(profile) == 0 {
|
||||
profile = DefaultSharedConfigProfile
|
||||
}
|
||||
|
||||
files, err := loadSharedConfigIniFiles(filenames)
|
||||
if err != nil {
|
||||
return sharedConfig{}, err
|
||||
}
|
||||
|
||||
cfg := sharedConfig{}
|
||||
if err = cfg.setFromIniFiles(profile, files); err != nil {
|
||||
return sharedConfig{}, err
|
||||
}
|
||||
|
||||
if len(cfg.AssumeRole.SourceProfile) > 0 {
|
||||
if err := cfg.setAssumeRoleSource(profile, files); err != nil {
|
||||
return sharedConfig{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func loadSharedConfigIniFiles(filenames []string) ([]sharedConfigFile, error) {
|
||||
files := make([]sharedConfigFile, 0, len(filenames))
|
||||
|
||||
for _, filename := range filenames {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
// Skip files which can't be opened and read for whatever reason
|
||||
continue
|
||||
}
|
||||
|
||||
f, err := ini.Load(b)
|
||||
if err != nil {
|
||||
return nil, SharedConfigLoadError{Filename: filename}
|
||||
}
|
||||
|
||||
files = append(files, sharedConfigFile{
|
||||
Filename: filename, IniData: f,
|
||||
})
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (cfg *sharedConfig) setAssumeRoleSource(origProfile string, files []sharedConfigFile) error {
|
||||
var assumeRoleSrc sharedConfig
|
||||
|
||||
// Multiple level assume role chains are not support
|
||||
if cfg.AssumeRole.SourceProfile == origProfile {
|
||||
assumeRoleSrc = *cfg
|
||||
assumeRoleSrc.AssumeRole = assumeRoleConfig{}
|
||||
} else {
|
||||
err := assumeRoleSrc.setFromIniFiles(cfg.AssumeRole.SourceProfile, files)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(assumeRoleSrc.Creds.AccessKeyID) == 0 {
|
||||
return SharedConfigAssumeRoleError{RoleARN: cfg.AssumeRole.RoleARN}
|
||||
}
|
||||
|
||||
cfg.AssumeRoleSource = &assumeRoleSrc
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *sharedConfig) setFromIniFiles(profile string, files []sharedConfigFile) error {
|
||||
// Trim files from the list that don't exist.
|
||||
for _, f := range files {
|
||||
if err := cfg.setFromIniFile(profile, f); err != nil {
|
||||
if _, ok := err.(SharedConfigProfileNotExistsError); ok {
|
||||
// Ignore proviles missings
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setFromFile loads the configuration from the file using
|
||||
// the profile provided. A sharedConfig pointer type value is used so that
|
||||
// multiple config file loadings can be chained.
|
||||
//
|
||||
// Only loads complete logically grouped values, and will not set fields in cfg
|
||||
// for incomplete grouped values in the config. Such as credentials. For example
|
||||
// if a config file only includes aws_access_key_id but no aws_secret_access_key
|
||||
// the aws_access_key_id will be ignored.
|
||||
func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile) error {
|
||||
section, err := file.IniData.GetSection(profile)
|
||||
if err != nil {
|
||||
// Fallback to to alternate profile name: profile <name>
|
||||
section, err = file.IniData.GetSection(fmt.Sprintf("profile %s", profile))
|
||||
if err != nil {
|
||||
return SharedConfigProfileNotExistsError{Profile: profile, Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
// Shared Credentials
|
||||
akid := section.Key(accessKeyIDKey).String()
|
||||
secret := section.Key(secretAccessKey).String()
|
||||
if len(akid) > 0 && len(secret) > 0 {
|
||||
cfg.Creds = credentials.Value{
|
||||
AccessKeyID: akid,
|
||||
SecretAccessKey: secret,
|
||||
SessionToken: section.Key(sessionTokenKey).String(),
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", file.Filename),
|
||||
}
|
||||
}
|
||||
|
||||
// Assume Role
|
||||
roleArn := section.Key(roleArnKey).String()
|
||||
srcProfile := section.Key(sourceProfileKey).String()
|
||||
if len(roleArn) > 0 && len(srcProfile) > 0 {
|
||||
cfg.AssumeRole = assumeRoleConfig{
|
||||
RoleARN: roleArn,
|
||||
SourceProfile: srcProfile,
|
||||
ExternalID: section.Key(externalIDKey).String(),
|
||||
MFASerial: section.Key(mfaSerialKey).String(),
|
||||
RoleSessionName: section.Key(roleSessionNameKey).String(),
|
||||
}
|
||||
}
|
||||
|
||||
// Region
|
||||
if v := section.Key(regionKey).String(); len(v) > 0 {
|
||||
cfg.Region = v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SharedConfigLoadError is an error for the shared config file failed to load.
|
||||
type SharedConfigLoadError struct {
|
||||
Filename string
|
||||
Err error
|
||||
}
|
||||
|
||||
// Code is the short id of the error.
|
||||
func (e SharedConfigLoadError) Code() string {
|
||||
return "SharedConfigLoadError"
|
||||
}
|
||||
|
||||
// Message is the description of the error
|
||||
func (e SharedConfigLoadError) Message() string {
|
||||
return fmt.Sprintf("failed to load config file, %s", e.Filename)
|
||||
}
|
||||
|
||||
// OrigErr is the underlying error that caused the failure.
|
||||
func (e SharedConfigLoadError) OrigErr() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// Error satisfies the error interface.
|
||||
func (e SharedConfigLoadError) Error() string {
|
||||
return awserr.SprintError(e.Code(), e.Message(), "", e.Err)
|
||||
}
|
||||
|
||||
// SharedConfigProfileNotExistsError is an error for the shared config when
|
||||
// the profile was not find in the config file.
|
||||
type SharedConfigProfileNotExistsError struct {
|
||||
Profile string
|
||||
Err error
|
||||
}
|
||||
|
||||
// Code is the short id of the error.
|
||||
func (e SharedConfigProfileNotExistsError) Code() string {
|
||||
return "SharedConfigProfileNotExistsError"
|
||||
}
|
||||
|
||||
// Message is the description of the error
|
||||
func (e SharedConfigProfileNotExistsError) Message() string {
|
||||
return fmt.Sprintf("failed to get profile, %s", e.Profile)
|
||||
}
|
||||
|
||||
// OrigErr is the underlying error that caused the failure.
|
||||
func (e SharedConfigProfileNotExistsError) OrigErr() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// Error satisfies the error interface.
|
||||
func (e SharedConfigProfileNotExistsError) Error() string {
|
||||
return awserr.SprintError(e.Code(), e.Message(), "", e.Err)
|
||||
}
|
||||
|
||||
// SharedConfigAssumeRoleError is an error for the shared config when the
|
||||
// profile contains assume role information, but that information is invalid
|
||||
// or not complete.
|
||||
type SharedConfigAssumeRoleError struct {
|
||||
RoleARN string
|
||||
}
|
||||
|
||||
// Code is the short id of the error.
|
||||
func (e SharedConfigAssumeRoleError) Code() string {
|
||||
return "SharedConfigAssumeRoleError"
|
||||
}
|
||||
|
||||
// Message is the description of the error
|
||||
func (e SharedConfigAssumeRoleError) Message() string {
|
||||
return fmt.Sprintf("failed to load assume role for %s, source profile has no shared credentials",
|
||||
e.RoleARN)
|
||||
}
|
||||
|
||||
// OrigErr is the underlying error that caused the failure.
|
||||
func (e SharedConfigAssumeRoleError) OrigErr() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error satisfies the error interface.
|
||||
func (e SharedConfigAssumeRoleError) Error() string {
|
||||
return awserr.SprintError(e.Code(), e.Message(), "", nil)
|
||||
}
|
||||
264
vendor/github.com/aws/aws-sdk-go/aws/session/shared_config_test.go
generated
vendored
Normal file
264
vendor/github.com/aws/aws-sdk-go/aws/session/shared_config_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/go-ini/ini"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
testConfigFilename = filepath.Join("testdata", "shared_config")
|
||||
testConfigOtherFilename = filepath.Join("testdata", "shared_config_other")
|
||||
)
|
||||
|
||||
func TestLoadSharedConfig(t *testing.T) {
|
||||
cases := []struct {
|
||||
Filenames []string
|
||||
Profile string
|
||||
Expected sharedConfig
|
||||
Err error
|
||||
}{
|
||||
{
|
||||
Filenames: []string{"file_not_exists"},
|
||||
Profile: "default",
|
||||
},
|
||||
{
|
||||
Filenames: []string{testConfigFilename},
|
||||
Expected: sharedConfig{
|
||||
Region: "default_region",
|
||||
},
|
||||
},
|
||||
{
|
||||
Filenames: []string{testConfigOtherFilename, testConfigFilename},
|
||||
Profile: "config_file_load_order",
|
||||
Expected: sharedConfig{
|
||||
Region: "shared_config_region",
|
||||
Creds: credentials.Value{
|
||||
AccessKeyID: "shared_config_akid",
|
||||
SecretAccessKey: "shared_config_secret",
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Filenames: []string{testConfigFilename, testConfigOtherFilename},
|
||||
Profile: "config_file_load_order",
|
||||
Expected: sharedConfig{
|
||||
Region: "shared_config_other_region",
|
||||
Creds: credentials.Value{
|
||||
AccessKeyID: "shared_config_other_akid",
|
||||
SecretAccessKey: "shared_config_other_secret",
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigOtherFilename),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Filenames: []string{testConfigOtherFilename, testConfigFilename},
|
||||
Profile: "assume_role",
|
||||
Expected: sharedConfig{
|
||||
AssumeRole: assumeRoleConfig{
|
||||
RoleARN: "assume_role_role_arn",
|
||||
SourceProfile: "complete_creds",
|
||||
},
|
||||
AssumeRoleSource: &sharedConfig{
|
||||
Creds: credentials.Value{
|
||||
AccessKeyID: "complete_creds_akid",
|
||||
SecretAccessKey: "complete_creds_secret",
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Filenames: []string{testConfigOtherFilename, testConfigFilename},
|
||||
Profile: "assume_role_invalid_source_profile",
|
||||
Expected: sharedConfig{
|
||||
AssumeRole: assumeRoleConfig{
|
||||
RoleARN: "assume_role_invalid_source_profile_role_arn",
|
||||
SourceProfile: "profile_not_exists",
|
||||
},
|
||||
},
|
||||
Err: SharedConfigAssumeRoleError{RoleARN: "assume_role_invalid_source_profile_role_arn"},
|
||||
},
|
||||
{
|
||||
Filenames: []string{testConfigOtherFilename, testConfigFilename},
|
||||
Profile: "assume_role_w_creds",
|
||||
Expected: sharedConfig{
|
||||
Creds: credentials.Value{
|
||||
AccessKeyID: "assume_role_w_creds_akid",
|
||||
SecretAccessKey: "assume_role_w_creds_secret",
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
|
||||
},
|
||||
AssumeRole: assumeRoleConfig{
|
||||
RoleARN: "assume_role_w_creds_role_arn",
|
||||
SourceProfile: "assume_role_w_creds",
|
||||
ExternalID: "1234",
|
||||
RoleSessionName: "assume_role_w_creds_session_name",
|
||||
},
|
||||
AssumeRoleSource: &sharedConfig{
|
||||
Creds: credentials.Value{
|
||||
AccessKeyID: "assume_role_w_creds_akid",
|
||||
SecretAccessKey: "assume_role_w_creds_secret",
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Filenames: []string{testConfigOtherFilename, testConfigFilename},
|
||||
Profile: "assume_role_wo_creds",
|
||||
Expected: sharedConfig{
|
||||
AssumeRole: assumeRoleConfig{
|
||||
RoleARN: "assume_role_wo_creds_role_arn",
|
||||
SourceProfile: "assume_role_wo_creds",
|
||||
},
|
||||
},
|
||||
Err: SharedConfigAssumeRoleError{RoleARN: "assume_role_wo_creds_role_arn"},
|
||||
},
|
||||
{
|
||||
Filenames: []string{filepath.Join("testdata", "shared_config_invalid_ini")},
|
||||
Profile: "profile_name",
|
||||
Err: SharedConfigLoadError{Filename: filepath.Join("testdata", "shared_config_invalid_ini")},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
cfg, err := loadSharedConfig(c.Profile, c.Filenames)
|
||||
if c.Err != nil {
|
||||
assert.Contains(t, err.Error(), c.Err.Error(), "expected error, %d", i)
|
||||
continue
|
||||
}
|
||||
|
||||
assert.NoError(t, err, "unexpected error, %d", i)
|
||||
assert.Equal(t, c.Expected, cfg, "not equal, %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadSharedConfigFromFile(t *testing.T) {
|
||||
filename := testConfigFilename
|
||||
f, err := ini.Load(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load test config file, %s, %v", filename, err)
|
||||
}
|
||||
iniFile := sharedConfigFile{IniData: f, Filename: filename}
|
||||
|
||||
cases := []struct {
|
||||
Profile string
|
||||
Expected sharedConfig
|
||||
Err error
|
||||
}{
|
||||
{
|
||||
Profile: "default",
|
||||
Expected: sharedConfig{Region: "default_region"},
|
||||
},
|
||||
{
|
||||
Profile: "alt_profile_name",
|
||||
Expected: sharedConfig{Region: "alt_profile_name_region"},
|
||||
},
|
||||
{
|
||||
Profile: "short_profile_name_first",
|
||||
Expected: sharedConfig{Region: "short_profile_name_first_short"},
|
||||
},
|
||||
{
|
||||
Profile: "partial_creds",
|
||||
Expected: sharedConfig{},
|
||||
},
|
||||
{
|
||||
Profile: "complete_creds",
|
||||
Expected: sharedConfig{
|
||||
Creds: credentials.Value{
|
||||
AccessKeyID: "complete_creds_akid",
|
||||
SecretAccessKey: "complete_creds_secret",
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Profile: "complete_creds_with_token",
|
||||
Expected: sharedConfig{
|
||||
Creds: credentials.Value{
|
||||
AccessKeyID: "complete_creds_with_token_akid",
|
||||
SecretAccessKey: "complete_creds_with_token_secret",
|
||||
SessionToken: "complete_creds_with_token_token",
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Profile: "full_profile",
|
||||
Expected: sharedConfig{
|
||||
Creds: credentials.Value{
|
||||
AccessKeyID: "full_profile_akid",
|
||||
SecretAccessKey: "full_profile_secret",
|
||||
ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
|
||||
},
|
||||
Region: "full_profile_region",
|
||||
},
|
||||
},
|
||||
{
|
||||
Profile: "partial_assume_role",
|
||||
Expected: sharedConfig{},
|
||||
},
|
||||
{
|
||||
Profile: "assume_role",
|
||||
Expected: sharedConfig{
|
||||
AssumeRole: assumeRoleConfig{
|
||||
RoleARN: "assume_role_role_arn",
|
||||
SourceProfile: "complete_creds",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Profile: "does_not_exists",
|
||||
Err: SharedConfigProfileNotExistsError{Profile: "does_not_exists"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
cfg := sharedConfig{}
|
||||
|
||||
err := cfg.setFromIniFile(c.Profile, iniFile)
|
||||
if c.Err != nil {
|
||||
assert.Contains(t, err.Error(), c.Err.Error(), "expected error, %d", i)
|
||||
continue
|
||||
}
|
||||
|
||||
assert.NoError(t, err, "unexpected error, %d", i)
|
||||
assert.Equal(t, c.Expected, cfg, "not equal, %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadSharedConfigIniFiles(t *testing.T) {
|
||||
cases := []struct {
|
||||
Filenames []string
|
||||
Expected []sharedConfigFile
|
||||
}{
|
||||
{
|
||||
Filenames: []string{"not_exists", testConfigFilename},
|
||||
Expected: []sharedConfigFile{
|
||||
{Filename: testConfigFilename},
|
||||
},
|
||||
},
|
||||
{
|
||||
Filenames: []string{testConfigFilename, testConfigOtherFilename},
|
||||
Expected: []sharedConfigFile{
|
||||
{Filename: testConfigFilename},
|
||||
{Filename: testConfigOtherFilename},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
files, err := loadSharedConfigIniFiles(c.Filenames)
|
||||
assert.NoError(t, err, "unexpected error, %d", i)
|
||||
assert.Equal(t, len(c.Expected), len(files), "expected num files, %d", i)
|
||||
|
||||
for i, expectedFile := range c.Expected {
|
||||
assert.Equal(t, expectedFile.Filename, files[i].Filename)
|
||||
}
|
||||
}
|
||||
}
|
||||
60
vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config
generated
vendored
Normal file
60
vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
[default]
|
||||
s3 =
|
||||
unsupported_key=123
|
||||
other_unsupported=abc
|
||||
|
||||
region = default_region
|
||||
|
||||
[profile alt_profile_name]
|
||||
region = alt_profile_name_region
|
||||
|
||||
[short_profile_name_first]
|
||||
region = short_profile_name_first_short
|
||||
|
||||
[profile short_profile_name_first]
|
||||
region = short_profile_name_first_alt
|
||||
|
||||
[partial_creds]
|
||||
aws_access_key_id = partial_creds_akid
|
||||
|
||||
[complete_creds]
|
||||
aws_access_key_id = complete_creds_akid
|
||||
aws_secret_access_key = complete_creds_secret
|
||||
|
||||
[complete_creds_with_token]
|
||||
aws_access_key_id = complete_creds_with_token_akid
|
||||
aws_secret_access_key = complete_creds_with_token_secret
|
||||
aws_session_token = complete_creds_with_token_token
|
||||
|
||||
[full_profile]
|
||||
aws_access_key_id = full_profile_akid
|
||||
aws_secret_access_key = full_profile_secret
|
||||
region = full_profile_region
|
||||
|
||||
[config_file_load_order]
|
||||
region = shared_config_region
|
||||
aws_access_key_id = shared_config_akid
|
||||
aws_secret_access_key = shared_config_secret
|
||||
|
||||
[partial_assume_role]
|
||||
role_arn = partial_assume_role_role_arn
|
||||
|
||||
[assume_role]
|
||||
role_arn = assume_role_role_arn
|
||||
source_profile = complete_creds
|
||||
|
||||
[assume_role_invalid_source_profile]
|
||||
role_arn = assume_role_invalid_source_profile_role_arn
|
||||
source_profile = profile_not_exists
|
||||
|
||||
[assume_role_w_creds]
|
||||
role_arn = assume_role_w_creds_role_arn
|
||||
source_profile = assume_role_w_creds
|
||||
external_id = 1234
|
||||
role_session_name = assume_role_w_creds_session_name
|
||||
aws_access_key_id = assume_role_w_creds_akid
|
||||
aws_secret_access_key = assume_role_w_creds_secret
|
||||
|
||||
[assume_role_wo_creds]
|
||||
role_arn = assume_role_wo_creds_role_arn
|
||||
source_profile = assume_role_wo_creds
|
||||
1
vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_invalid_ini
generated
vendored
Normal file
1
vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_invalid_ini
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
[profile_nam
|
||||
17
vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_other
generated
vendored
Normal file
17
vendor/github.com/aws/aws-sdk-go/aws/session/testdata/shared_config_other
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[default]
|
||||
region = default_region
|
||||
|
||||
[partial_creds]
|
||||
aws_access_key_id = AKID
|
||||
|
||||
[profile alt_profile_name]
|
||||
region = alt_profile_name_region
|
||||
|
||||
[creds_from_credentials]
|
||||
aws_access_key_id = creds_from_config_akid
|
||||
aws_secret_access_key = creds_from_config_secret
|
||||
|
||||
[config_file_load_order]
|
||||
region = shared_config_other_region
|
||||
aws_access_key_id = shared_config_other_akid
|
||||
aws_secret_access_key = shared_config_other_secret
|
||||
40
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_1_4_test.go
generated
vendored
Normal file
40
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_1_4_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// +build !go1.5
|
||||
|
||||
package v4_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStandaloneSign(t *testing.T) {
|
||||
creds := unit.Session.Config.Credentials
|
||||
signer := v4.NewSigner(creds)
|
||||
|
||||
for _, c := range standaloneSignCases {
|
||||
host := fmt.Sprintf("%s.%s.%s.amazonaws.com",
|
||||
c.SubDomain, c.Region, c.Service)
|
||||
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf("https://%s", host), nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req.URL.Path = c.OrigURI
|
||||
req.URL.RawQuery = c.OrigQuery
|
||||
req.URL.Opaque = fmt.Sprintf("//%s%s", host, c.EscapedURI)
|
||||
opaqueURI := req.URL.Opaque
|
||||
|
||||
_, err = signer.Sign(req, nil, c.Service, c.Region, time.Unix(0, 0))
|
||||
assert.NoError(t, err)
|
||||
|
||||
actual := req.Header.Get("Authorization")
|
||||
assert.Equal(t, c.ExpSig, actual)
|
||||
assert.Equal(t, c.OrigURI, req.URL.Path)
|
||||
assert.Equal(t, opaqueURI, req.URL.Opaque)
|
||||
}
|
||||
}
|
||||
40
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_1_5_test.go
generated
vendored
Normal file
40
vendor/github.com/aws/aws-sdk-go/aws/signer/v4/functional_1_5_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// +build go1.5
|
||||
|
||||
package v4_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStandaloneSign(t *testing.T) {
|
||||
creds := unit.Session.Config.Credentials
|
||||
signer := v4.NewSigner(creds)
|
||||
|
||||
for _, c := range standaloneSignCases {
|
||||
host := fmt.Sprintf("https://%s.%s.%s.amazonaws.com",
|
||||
c.SubDomain, c.Region, c.Service)
|
||||
|
||||
req, err := http.NewRequest("GET", host, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// URL.EscapedPath() will be used by the signer to get the
|
||||
// escaped form of the request's URI path.
|
||||
req.URL.Path = c.OrigURI
|
||||
req.URL.RawQuery = c.OrigQuery
|
||||
|
||||
_, err = signer.Sign(req, nil, c.Service, c.Region, time.Unix(0, 0))
|
||||
assert.NoError(t, err)
|
||||
|
||||
actual := req.Header.Get("Authorization")
|
||||
assert.Equal(t, c.ExpSig, actual)
|
||||
assert.Equal(t, c.OrigURI, req.URL.Path)
|
||||
assert.Equal(t, c.EscapedURI, req.URL.EscapedPath())
|
||||
}
|
||||
}
|
||||
|
|
@ -7,11 +7,28 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var standaloneSignCases = []struct {
|
||||
OrigURI string
|
||||
OrigQuery string
|
||||
Region, Service, SubDomain string
|
||||
ExpSig string
|
||||
EscapedURI string
|
||||
}{
|
||||
{
|
||||
OrigURI: `/logs-*/_search`,
|
||||
OrigQuery: `pretty=true`,
|
||||
Region: "us-west-2", Service: "es", SubDomain: "hostname-clusterkey",
|
||||
EscapedURI: `/logs-%2A/_search`,
|
||||
ExpSig: `AWS4-HMAC-SHA256 Credential=AKID/19700101/us-west-2/es/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=79d0760751907af16f64a537c1242416dacf51204a7dd5284492d15577973b91`,
|
||||
},
|
||||
}
|
||||
|
||||
func TestPresignHandler(t *testing.T) {
|
||||
svc := s3.New(unit.Session)
|
||||
req, _ := svc.PutObjectRequest(&s3.PutObjectInput{
|
||||
|
|
@ -75,3 +92,25 @@ func TestPresignRequest(t *testing.T) {
|
|||
|
||||
assert.NotContains(t, urlstr, "+") // + encoded as %20
|
||||
}
|
||||
|
||||
func TestStandaloneSign_CustomURIEscape(t *testing.T) {
|
||||
var expectSig = `AWS4-HMAC-SHA256 Credential=AKID/19700101/us-east-1/es/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=6601e883cc6d23871fd6c2a394c5677ea2b8c82b04a6446786d64cd74f520967`
|
||||
|
||||
creds := unit.Session.Config.Credentials
|
||||
signer := v4.NewSigner(creds, func(s *v4.Signer) {
|
||||
s.DisableURIPathEscaping = true
|
||||
})
|
||||
|
||||
host := "https://subdomain.us-east-1.es.amazonaws.com"
|
||||
req, err := http.NewRequest("GET", host, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req.URL.Path = `/log-*/_search`
|
||||
req.URL.Opaque = "//subdomain.us-east-1.es.amazonaws.com/log-%2A/_search"
|
||||
|
||||
_, err = signer.Sign(req, nil, "es", "us-east-1", time.Unix(0, 0))
|
||||
assert.NoError(t, err)
|
||||
|
||||
actual := req.Header.Get("Authorization")
|
||||
assert.Equal(t, expectSig, actual)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
// +build go1.5
|
||||
|
||||
package v4
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getURIPath(u *url.URL) string {
|
||||
var uri string
|
||||
|
||||
if len(u.Opaque) > 0 {
|
||||
uri = "/" + strings.Join(strings.Split(u.Opaque, "/")[3:], "/")
|
||||
} else {
|
||||
uri = u.EscapedPath()
|
||||
}
|
||||
|
||||
if len(uri) == 0 {
|
||||
uri = "/"
|
||||
}
|
||||
|
||||
return uri
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// +build !go1.5
|
||||
|
||||
package v4
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getURIPath(u *url.URL) string {
|
||||
var uri string
|
||||
|
||||
if len(u.Opaque) > 0 {
|
||||
uri = "/" + strings.Join(strings.Split(u.Opaque, "/")[3:], "/")
|
||||
} else {
|
||||
uri = u.Path
|
||||
}
|
||||
|
||||
if len(uri) == 0 {
|
||||
uri = "/"
|
||||
}
|
||||
|
||||
return uri
|
||||
}
|
||||
|
|
@ -2,6 +2,48 @@
|
|||
//
|
||||
// Provides request signing for request that need to be signed with
|
||||
// AWS V4 Signatures.
|
||||
//
|
||||
// Standalone Signer
|
||||
//
|
||||
// Generally using the signer outside of the SDK should not require any additional
|
||||
// logic when using Go v1.5 or higher. The signer does this by taking advantage
|
||||
// of the URL.EscapedPath method. If your request URI requires additional escaping
|
||||
// you many need to use the URL.Opaque to define what the raw URI should be sent
|
||||
// to the service as.
|
||||
//
|
||||
// The signer will first check the URL.Opaque field, and use its value if set.
|
||||
// The signer does require the URL.Opaque field to be set in the form of:
|
||||
//
|
||||
// "//<hostname>/<path>"
|
||||
//
|
||||
// // e.g.
|
||||
// "//example.com/some/path"
|
||||
//
|
||||
// The leading "//" and hostname are required or the URL.Opaque escaping will
|
||||
// not work correctly.
|
||||
//
|
||||
// If URL.Opaque is not set the signer will fallback to the URL.EscapedPath()
|
||||
// method and using the returned value. If you're using Go v1.4 you must set
|
||||
// URL.Opaque if the URI path needs escaping. If URL.Opaque is not set with
|
||||
// Go v1.5 the signer will fallback to URL.Path.
|
||||
//
|
||||
// AWS v4 signature validation requires that the canonical string's URI path
|
||||
// element must be the URI escaped form of the HTTP request's path.
|
||||
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
//
|
||||
// The Go HTTP client will perform escaping automatically on the request. Some
|
||||
// of these escaping may cause signature validation errors because the HTTP
|
||||
// request differs from the URI path or query that the signature was generated.
|
||||
// https://golang.org/pkg/net/url/#URL.EscapedPath
|
||||
//
|
||||
// Because of this, it is recommended that when using the signer outside of the
|
||||
// SDK that explicitly escaping the request prior to being signed is preferable,
|
||||
// and will help prevent signature validation errors. This can be done by setting
|
||||
// the URL.Opaque or URL.RawPath. The SDK will use URL.Opaque first and then
|
||||
// call URL.EscapedPath() if Opaque is not set.
|
||||
//
|
||||
// Test `TestStandaloneSign` provides a complete example of using the signer
|
||||
// outside of the SDK and pre-escaping the URI path.
|
||||
package v4
|
||||
|
||||
import (
|
||||
|
|
@ -11,6 +53,7 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
|
@ -119,6 +162,15 @@ type Signer struct {
|
|||
// request's query string.
|
||||
DisableHeaderHoisting bool
|
||||
|
||||
// Disables the automatic escaping of the URI path of the request for the
|
||||
// siganture's canonical string's path. For services that do not need additional
|
||||
// escaping then use this to disable the signer escaping the path.
|
||||
//
|
||||
// S3 is an example of a service that does not need additional escaping.
|
||||
//
|
||||
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
DisableURIPathEscaping bool
|
||||
|
||||
// currentTimeFn returns the time value which represents the current time.
|
||||
// This value should only be used for testing. If it is nil the default
|
||||
// time.Now will be used.
|
||||
|
|
@ -150,6 +202,8 @@ type signingCtx struct {
|
|||
ExpireTime time.Duration
|
||||
SignedHeaderVals http.Header
|
||||
|
||||
DisableURIPathEscaping bool
|
||||
|
||||
credValues credentials.Value
|
||||
isPresign bool
|
||||
formattedTime string
|
||||
|
|
@ -175,6 +229,12 @@ type signingCtx struct {
|
|||
// is not needed as the full request context will be captured by the http.Request
|
||||
// value. It is included for reference though.
|
||||
//
|
||||
// Sign will set the request's Body to be the `body` parameter passed in. If
|
||||
// the body is not already an io.ReadCloser, it will be wrapped within one. If
|
||||
// a `nil` body parameter passed to Sign, the request's Body field will be
|
||||
// also set to nil. Its important to note that this functionality will not
|
||||
// change the request's ContentLength of the request.
|
||||
//
|
||||
// Sign differs from Presign in that it will sign the request using HTTP
|
||||
// header values. This type of signing is intended for http.Request values that
|
||||
// will not be shared, or are shared in a way the header values on the request
|
||||
|
|
@ -229,22 +289,18 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
|
|||
}
|
||||
|
||||
ctx := &signingCtx{
|
||||
Request: r,
|
||||
Body: body,
|
||||
Query: r.URL.Query(),
|
||||
Time: signTime,
|
||||
ExpireTime: exp,
|
||||
isPresign: exp != 0,
|
||||
ServiceName: service,
|
||||
Region: region,
|
||||
Request: r,
|
||||
Body: body,
|
||||
Query: r.URL.Query(),
|
||||
Time: signTime,
|
||||
ExpireTime: exp,
|
||||
isPresign: exp != 0,
|
||||
ServiceName: service,
|
||||
Region: region,
|
||||
DisableURIPathEscaping: v4.DisableURIPathEscaping,
|
||||
}
|
||||
|
||||
if ctx.isRequestSigned() {
|
||||
if !v4.Credentials.IsExpired() && currentTimeFn().Before(ctx.Time.Add(10*time.Minute)) {
|
||||
// If the request is already signed, and the credentials have not
|
||||
// expired, and the request is not too old ignore the signing request.
|
||||
return ctx.SignedHeaderVals, nil
|
||||
}
|
||||
ctx.Time = currentTimeFn()
|
||||
ctx.handlePresignRemoval()
|
||||
}
|
||||
|
|
@ -258,6 +314,20 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
|
|||
ctx.assignAmzQueryValues()
|
||||
ctx.build(v4.DisableHeaderHoisting)
|
||||
|
||||
// If the request is not presigned the body should be attached to it. This
|
||||
// prevents the confusion of wanting to send a signed request without
|
||||
// the body the request was signed for attached.
|
||||
if !ctx.isPresign {
|
||||
var reader io.ReadCloser
|
||||
if body != nil {
|
||||
var ok bool
|
||||
if reader, ok = body.(io.ReadCloser); !ok {
|
||||
reader = ioutil.NopCloser(body)
|
||||
}
|
||||
}
|
||||
r.Body = reader
|
||||
}
|
||||
|
||||
if v4.Debug.Matches(aws.LogDebugWithSigning) {
|
||||
v4.logSigningInfo(ctx)
|
||||
}
|
||||
|
|
@ -338,6 +408,10 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time
|
|||
v4.Logger = req.Config.Logger
|
||||
v4.DisableHeaderHoisting = req.NotHoist
|
||||
v4.currentTimeFn = curTimeFn
|
||||
if name == "s3" {
|
||||
// S3 service should not have any escaping applied
|
||||
v4.DisableURIPathEscaping = true
|
||||
}
|
||||
})
|
||||
|
||||
signingTime := req.Time
|
||||
|
|
@ -345,7 +419,9 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time
|
|||
signingTime = req.LastSignedAt
|
||||
}
|
||||
|
||||
signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.Body, name, region, req.ExpireTime, signingTime)
|
||||
signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.GetBody(),
|
||||
name, region, req.ExpireTime, signingTime,
|
||||
)
|
||||
if err != nil {
|
||||
req.Error = err
|
||||
req.SignedHeaderVals = nil
|
||||
|
|
@ -356,7 +432,7 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time
|
|||
req.LastSignedAt = curTimeFn()
|
||||
}
|
||||
|
||||
const logSignInfoMsg = `DEBUG: Request Signiture:
|
||||
const logSignInfoMsg = `DEBUG: Request Signature:
|
||||
---[ CANONICAL STRING ]-----------------------------
|
||||
%s
|
||||
---[ STRING TO SIGN ]--------------------------------
|
||||
|
|
@ -492,17 +568,10 @@ func (ctx *signingCtx) buildCanonicalHeaders(r rule, header http.Header) {
|
|||
|
||||
func (ctx *signingCtx) buildCanonicalString() {
|
||||
ctx.Request.URL.RawQuery = strings.Replace(ctx.Query.Encode(), "+", "%20", -1)
|
||||
uri := ctx.Request.URL.Opaque
|
||||
if uri != "" {
|
||||
uri = "/" + strings.Join(strings.Split(uri, "/")[3:], "/")
|
||||
} else {
|
||||
uri = ctx.Request.URL.Path
|
||||
}
|
||||
if uri == "" {
|
||||
uri = "/"
|
||||
}
|
||||
|
||||
if ctx.ServiceName != "s3" {
|
||||
uri := getURIPath(ctx.Request.URL)
|
||||
|
||||
if !ctx.DisableURIPathEscaping {
|
||||
uri = rest.EscapePath(uri, false)
|
||||
}
|
||||
|
||||
|
|
@ -545,7 +614,7 @@ func (ctx *signingCtx) buildBodyDigest() {
|
|||
} else {
|
||||
hash = hex.EncodeToString(makeSha256Reader(ctx.Body))
|
||||
}
|
||||
if ctx.ServiceName == "s3" {
|
||||
if ctx.ServiceName == "s3" || ctx.ServiceName == "glacier" {
|
||||
ctx.Request.Header.Set("X-Amz-Content-Sha256", hash)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
package v4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -111,7 +114,7 @@ func TestSignRequest(t *testing.T) {
|
|||
assert.Equal(t, expectedDate, q.Get("X-Amz-Date"))
|
||||
}
|
||||
|
||||
func TestSignBody(t *testing.T) {
|
||||
func TestSignBodyS3(t *testing.T) {
|
||||
req, body := buildRequest("s3", "us-east-1", "hello")
|
||||
signer := buildSigner()
|
||||
signer.Sign(req, body, "s3", "us-east-1", time.Now())
|
||||
|
|
@ -119,6 +122,14 @@ func TestSignBody(t *testing.T) {
|
|||
assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", hash)
|
||||
}
|
||||
|
||||
func TestSignBodyGlacier(t *testing.T) {
|
||||
req, body := buildRequest("glacier", "us-east-1", "hello")
|
||||
signer := buildSigner()
|
||||
signer.Sign(req, body, "glacier", "us-east-1", time.Now())
|
||||
hash := req.Header.Get("X-Amz-Content-Sha256")
|
||||
assert.Equal(t, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", hash)
|
||||
}
|
||||
|
||||
func TestPresignEmptyBodyS3(t *testing.T) {
|
||||
req, body := buildRequest("s3", "us-east-1", "hello")
|
||||
signer := buildSigner()
|
||||
|
|
@ -178,8 +189,12 @@ func TestIgnoreResignRequestWithValidCreds(t *testing.T) {
|
|||
SignSDKRequest(r)
|
||||
sig := r.HTTPRequest.Header.Get("Authorization")
|
||||
|
||||
SignSDKRequest(r)
|
||||
assert.Equal(t, sig, r.HTTPRequest.Header.Get("Authorization"))
|
||||
signSDKRequestWithCurrTime(r, func() time.Time {
|
||||
// Simulate one second has passed so that signature's date changes
|
||||
// when it is resigned.
|
||||
return time.Now().Add(1 * time.Second)
|
||||
})
|
||||
assert.NotEqual(t, sig, r.HTTPRequest.Header.Get("Authorization"))
|
||||
}
|
||||
|
||||
func TestIgnorePreResignRequestWithValidCreds(t *testing.T) {
|
||||
|
|
@ -199,10 +214,14 @@ func TestIgnorePreResignRequestWithValidCreds(t *testing.T) {
|
|||
r.ExpireTime = time.Minute * 10
|
||||
|
||||
SignSDKRequest(r)
|
||||
sig := r.HTTPRequest.Header.Get("X-Amz-Signature")
|
||||
sig := r.HTTPRequest.URL.Query().Get("X-Amz-Signature")
|
||||
|
||||
SignSDKRequest(r)
|
||||
assert.Equal(t, sig, r.HTTPRequest.Header.Get("X-Amz-Signature"))
|
||||
signSDKRequestWithCurrTime(r, func() time.Time {
|
||||
// Simulate one second has passed so that signature's date changes
|
||||
// when it is resigned.
|
||||
return time.Now().Add(1 * time.Second)
|
||||
})
|
||||
assert.NotEqual(t, sig, r.HTTPRequest.URL.Query().Get("X-Amz-Signature"))
|
||||
}
|
||||
|
||||
func TestResignRequestExpiredCreds(t *testing.T) {
|
||||
|
|
@ -280,7 +299,7 @@ func TestPreResignRequestExpiredCreds(t *testing.T) {
|
|||
creds.Expire()
|
||||
|
||||
signSDKRequestWithCurrTime(r, func() time.Time {
|
||||
// Simulate the request occured 15 minutes in the past
|
||||
// Simulate the request occurred 15 minutes in the past
|
||||
return time.Now().Add(-48 * time.Hour)
|
||||
})
|
||||
assert.NotEqual(t, querySig, r.HTTPRequest.URL.Query().Get("X-Amz-Signature"))
|
||||
|
|
@ -308,13 +327,63 @@ func TestResignRequestExpiredRequest(t *testing.T) {
|
|||
origSignedAt := r.LastSignedAt
|
||||
|
||||
signSDKRequestWithCurrTime(r, func() time.Time {
|
||||
// Simulate the request occured 15 minutes in the past
|
||||
// Simulate the request occurred 15 minutes in the past
|
||||
return time.Now().Add(15 * time.Minute)
|
||||
})
|
||||
assert.NotEqual(t, querySig, r.HTTPRequest.Header.Get("Authorization"))
|
||||
assert.NotEqual(t, origSignedAt, r.LastSignedAt)
|
||||
}
|
||||
|
||||
func TestSignWithRequestBody(t *testing.T) {
|
||||
creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION")
|
||||
signer := NewSigner(creds)
|
||||
|
||||
expectBody := []byte("abc123")
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
r.Body.Close()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectBody, b)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
req, err := http.NewRequest("POST", server.URL, nil)
|
||||
|
||||
_, err = signer.Sign(req, bytes.NewReader(expectBody), "service", "region", time.Now())
|
||||
assert.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestSignWithRequestBody_Overwrite(t *testing.T) {
|
||||
creds := credentials.NewStaticCredentials("AKID", "SECRET", "SESSION")
|
||||
signer := NewSigner(creds)
|
||||
|
||||
var expectBody []byte
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
r.Body.Close()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(expectBody), len(b))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
req, err := http.NewRequest("GET", server.URL, strings.NewReader("invalid body"))
|
||||
|
||||
_, err = signer.Sign(req, nil, "service", "region", time.Now())
|
||||
req.ContentLength = 0
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
|
||||
func BenchmarkPresignRequest(b *testing.B) {
|
||||
signer := buildSigner()
|
||||
req, body := buildRequest("dynamodb", "us-east-1", "{}")
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ package aws
|
|||
const SDKName = "aws-sdk-go"
|
||||
|
||||
// SDKVersion is the version of this SDK
|
||||
const SDKVersion = "1.2.7"
|
||||
const SDKVersion = "1.5.2"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// +build go1.5
|
||||
// +build go1.5,deprecated
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
|||
2
vendor/github.com/aws/aws-sdk-go/awsmigrate/awsmigrate-renamer/rename/rename.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/awsmigrate/awsmigrate-renamer/rename/rename.go
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
// +build go1.5
|
||||
// +build go1.5,deprecated
|
||||
|
||||
package rename
|
||||
|
||||
|
|
|
|||
2
vendor/github.com/aws/aws-sdk-go/awsmigrate/awsmigrate-renamer/rename/renames.go
generated
vendored
2
vendor/github.com/aws/aws-sdk-go/awsmigrate/awsmigrate-renamer/rename/renames.go
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
// +build go1.5
|
||||
// +build go1.5,deprecated
|
||||
|
||||
package rename
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// +build go1.5
|
||||
// +build go1.5,deprecated
|
||||
|
||||
package main
|
||||
|
||||
//go:generate go run gen/gen.go
|
||||
//go:generate go run -tags deprecated gen/gen.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@ import (
|
|||
"encoding/xml"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Match is a testing helper to test for testing error by comparing expected
|
||||
|
|
@ -33,9 +32,9 @@ func AssertURL(t *testing.T, expect, actual string, msgAndArgs ...interface{}) b
|
|||
return false
|
||||
}
|
||||
|
||||
assert.Equal(t, expectURL.Host, actualURL.Host, msgAndArgs...)
|
||||
assert.Equal(t, expectURL.Scheme, actualURL.Scheme, msgAndArgs...)
|
||||
assert.Equal(t, expectURL.Path, actualURL.Path, msgAndArgs...)
|
||||
equal(t, expectURL.Host, actualURL.Host, msgAndArgs...)
|
||||
equal(t, expectURL.Scheme, actualURL.Scheme, msgAndArgs...)
|
||||
equal(t, expectURL.Path, actualURL.Path, msgAndArgs...)
|
||||
|
||||
return AssertQuery(t, expectURL.Query().Encode(), actualURL.Query().Encode(), msgAndArgs...)
|
||||
}
|
||||
|
|
@ -54,7 +53,7 @@ func AssertQuery(t *testing.T, expect, actual string, msgAndArgs ...interface{})
|
|||
}
|
||||
|
||||
// Make sure the keys are the same
|
||||
if !assert.Equal(t, queryValueKeys(expectQ), queryValueKeys(actualQ), msgAndArgs...) {
|
||||
if !equal(t, queryValueKeys(expectQ), queryValueKeys(actualQ), msgAndArgs...) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +61,7 @@ func AssertQuery(t *testing.T, expect, actual string, msgAndArgs ...interface{})
|
|||
sort.Strings(expectQVals)
|
||||
actualQVals := actualQ[k]
|
||||
sort.Strings(actualQVals)
|
||||
assert.Equal(t, expectQVals, actualQVals, msgAndArgs...)
|
||||
equal(t, expectQVals, actualQVals, msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -82,7 +81,7 @@ func AssertJSON(t *testing.T, expect, actual string, msgAndArgs ...interface{})
|
|||
return false
|
||||
}
|
||||
|
||||
return assert.Equal(t, expectVal, actualVal, msgAndArgs...)
|
||||
return equal(t, expectVal, actualVal, msgAndArgs...)
|
||||
}
|
||||
|
||||
// AssertXML verifies that the expect xml string matches the actual.
|
||||
|
|
@ -96,7 +95,39 @@ func AssertXML(t *testing.T, expect, actual string, container interface{}, msgAn
|
|||
if err := xml.Unmarshal([]byte(actual), &actualVal); err != nil {
|
||||
t.Errorf(errMsg("unable to parse actual XML", err, msgAndArgs...))
|
||||
}
|
||||
return assert.Equal(t, expectVal, actualVal, msgAndArgs...)
|
||||
return equal(t, expectVal, actualVal, msgAndArgs...)
|
||||
}
|
||||
|
||||
// objectsAreEqual determines if two objects are considered equal.
|
||||
//
|
||||
// This function does no assertion of any kind.
|
||||
//
|
||||
// Based on github.com/stretchr/testify/assert.ObjectsAreEqual
|
||||
// Copied locally to prevent non-test build dependencies on testify
|
||||
func objectsAreEqual(expected, actual interface{}) bool {
|
||||
if expected == nil || actual == nil {
|
||||
return expected == actual
|
||||
}
|
||||
|
||||
return reflect.DeepEqual(expected, actual)
|
||||
}
|
||||
|
||||
// Equal asserts that two objects are equal.
|
||||
//
|
||||
// assert.Equal(t, 123, 123, "123 and 123 should be equal")
|
||||
//
|
||||
// Returns whether the assertion was successful (true) or not (false).
|
||||
//
|
||||
// Based on github.com/stretchr/testify/assert.Equal
|
||||
// Copied locally to prevent non-test build dependencies on testify
|
||||
func equal(t *testing.T, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
if !objectsAreEqual(expected, actual) {
|
||||
t.Errorf("Not Equal:\n\t%#v (expected)\n\t%#v (actual), %s",
|
||||
expected, actual, messageFromMsgAndArgs(msgAndArgs))
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func errMsg(baseMsg string, err error, msgAndArgs ...interface{}) string {
|
||||
|
|
@ -107,6 +138,8 @@ func errMsg(baseMsg string, err error, msgAndArgs ...interface{}) string {
|
|||
return fmt.Sprintf("%s%s, %v", message, baseMsg, err)
|
||||
}
|
||||
|
||||
// Based on github.com/stretchr/testify/assert.messageFromMsgAndArgs
|
||||
// Copied locally to prevent non-test build dependencies on testify
|
||||
func messageFromMsgAndArgs(msgAndArgs []interface{}) string {
|
||||
if len(msgAndArgs) == 0 || msgAndArgs == nil {
|
||||
return ""
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/defaults"
|
||||
"github.com/aws/aws-sdk-go/awstesting/mock"
|
||||
)
|
||||
|
||||
// NewClient creates and initializes a generic service client for testing.
|
||||
|
|
@ -19,24 +18,3 @@ func NewClient(cfgs ...*aws.Config) *client.Client {
|
|||
|
||||
return client.New(*def.Config, info, def.Handlers)
|
||||
}
|
||||
|
||||
// NewMockClient creates and initializes a client that will connect to the
|
||||
// mock server
|
||||
func NewMockClient(cfgs ...*aws.Config) *client.Client {
|
||||
c := mock.Session.ClientConfig("Mock", cfgs...)
|
||||
|
||||
svc := client.New(
|
||||
*c.Config,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "Mock",
|
||||
SigningRegion: c.SigningRegion,
|
||||
Endpoint: c.Endpoint,
|
||||
APIVersion: "2015-12-08",
|
||||
JSONVersion: "1.1",
|
||||
TargetPrefix: "MockServer",
|
||||
},
|
||||
c.Handlers,
|
||||
)
|
||||
|
||||
return svc
|
||||
}
|
||||
|
|
|
|||
29
vendor/github.com/aws/aws-sdk-go/awstesting/integration/customizations/s3/s3crypto/client.go
generated
vendored
Normal file
29
vendor/github.com/aws/aws-sdk-go/awstesting/integration/customizations/s3/s3crypto/client.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// +build integration
|
||||
|
||||
//Package s3crypto provides gucumber integration tests support.
|
||||
package s3crypto
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3crypto"
|
||||
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gucumber.Before("@s3crypto", func() {
|
||||
sess := session.New((&aws.Config{
|
||||
Region: aws.String("us-west-2"),
|
||||
}).WithLogLevel(aws.LogDebugWithRequestRetries | aws.LogDebugWithRequestErrors))
|
||||
encryptionClient := s3crypto.NewEncryptionClient(sess, nil, func(c *s3crypto.EncryptionClient) {
|
||||
})
|
||||
gucumber.World["encryptionClient"] = encryptionClient
|
||||
|
||||
decryptionClient := s3crypto.NewDecryptionClient(sess)
|
||||
gucumber.World["decryptionClient"] = decryptionClient
|
||||
|
||||
gucumber.World["client"] = s3.New(sess)
|
||||
})
|
||||
}
|
||||
18
vendor/github.com/aws/aws-sdk-go/awstesting/integration/customizations/s3/s3crypto/s3_crypto.feature
generated
vendored
Normal file
18
vendor/github.com/aws/aws-sdk-go/awstesting/integration/customizations/s3/s3crypto/s3_crypto.feature
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# language: en
|
||||
@s3crypto @client
|
||||
Feature: S3 Integration Crypto Tests
|
||||
|
||||
Scenario: Get all plaintext fixtures for symmetric masterkey aes cbc
|
||||
When I get all fixtures for "aes_gcm" from "aws-s3-shared-tests"
|
||||
Then I decrypt each fixture against "Java" "version_2"
|
||||
And I compare the decrypted ciphertext to the plaintext
|
||||
|
||||
Scenario: Uploading Go's SDK fixtures
|
||||
When I get all fixtures for "aes_gcm" from "aws-s3-shared-tests"
|
||||
Then I encrypt each fixture with "kms" "AWS_SDK_TEST_ALIAS" "us-west-2" and "aes_gcm"
|
||||
And upload "Go" data with folder "version_2"
|
||||
|
||||
Scenario: Get all plaintext fixtures for symmetric masterkey aes gcm
|
||||
When I get all fixtures for "aes_gcm" from "aws-s3-shared-tests"
|
||||
Then I decrypt each fixture against "Go" "version_2"
|
||||
And I compare the decrypted ciphertext to the plaintext
|
||||
192
vendor/github.com/aws/aws-sdk-go/awstesting/integration/customizations/s3/s3crypto/stepdef.go
generated
vendored
Normal file
192
vendor/github.com/aws/aws-sdk-go/awstesting/integration/customizations/s3/s3crypto/stepdef.go
generated
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
// +build integration
|
||||
|
||||
// Package s3crypto contains shared step definitions that are used across integration tests
|
||||
package s3crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/gucumber/gucumber"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/kms"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3crypto"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gucumber.When(`^I get all fixtures for "(.+?)" from "(.+?)"$`,
|
||||
func(cekAlg, bucket string) {
|
||||
prefix := "plaintext_test_case_"
|
||||
baseFolder := "crypto_tests/" + cekAlg
|
||||
s3Client := gucumber.World["client"].(*s3.S3)
|
||||
|
||||
out, err := s3Client.ListObjects(&s3.ListObjectsInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Prefix: aws.String(baseFolder + "/" + prefix),
|
||||
})
|
||||
assert.NoError(gucumber.T, err)
|
||||
|
||||
plaintexts := make(map[string][]byte)
|
||||
for _, obj := range out.Contents {
|
||||
plaintextKey := obj.Key
|
||||
ptObj, err := s3Client.GetObject(&s3.GetObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: plaintextKey,
|
||||
})
|
||||
assert.NoError(gucumber.T, err)
|
||||
caseKey := strings.TrimPrefix(*plaintextKey, baseFolder+"/"+prefix)
|
||||
plaintext, err := ioutil.ReadAll(ptObj.Body)
|
||||
assert.NoError(gucumber.T, err)
|
||||
|
||||
plaintexts[caseKey] = plaintext
|
||||
}
|
||||
gucumber.World["baseFolder"] = baseFolder
|
||||
gucumber.World["bucket"] = bucket
|
||||
gucumber.World["plaintexts"] = plaintexts
|
||||
})
|
||||
|
||||
gucumber.Then(`^I decrypt each fixture against "(.+?)" "(.+?)"$`, func(lang, version string) {
|
||||
plaintexts := gucumber.World["plaintexts"].(map[string][]byte)
|
||||
baseFolder := gucumber.World["baseFolder"].(string)
|
||||
bucket := gucumber.World["bucket"].(string)
|
||||
prefix := "ciphertext_test_case_"
|
||||
s3Client := gucumber.World["client"].(*s3.S3)
|
||||
s3CryptoClient := gucumber.World["decryptionClient"].(*s3crypto.DecryptionClient)
|
||||
language := "language_" + lang
|
||||
|
||||
ciphertexts := make(map[string][]byte)
|
||||
for caseKey := range plaintexts {
|
||||
cipherKey := baseFolder + "/" + version + "/" + language + "/" + prefix + caseKey
|
||||
|
||||
// To get metadata for encryption key
|
||||
ctObj, err := s3Client.GetObject(&s3.GetObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: &cipherKey,
|
||||
})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// We don't support wrap, so skip it
|
||||
if *ctObj.Metadata["X-Amz-Wrap-Alg"] != "kms" {
|
||||
continue
|
||||
}
|
||||
//masterkeyB64 := ctObj.Metadata["Masterkey"]
|
||||
//masterkey, err := base64.StdEncoding.DecodeString(*masterkeyB64)
|
||||
//assert.NoError(T, err)
|
||||
|
||||
//s3CryptoClient.Config.MasterKey = masterkey
|
||||
ctObj, err = s3CryptoClient.GetObject(&s3.GetObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: &cipherKey,
|
||||
},
|
||||
)
|
||||
assert.NoError(gucumber.T, err)
|
||||
|
||||
ciphertext, err := ioutil.ReadAll(ctObj.Body)
|
||||
assert.NoError(gucumber.T, err)
|
||||
ciphertexts[caseKey] = ciphertext
|
||||
}
|
||||
gucumber.World["ciphertexts"] = ciphertexts
|
||||
})
|
||||
|
||||
gucumber.And(`^I compare the decrypted ciphertext to the plaintext$`, func() {
|
||||
plaintexts := gucumber.World["plaintexts"].(map[string][]byte)
|
||||
ciphertexts := gucumber.World["ciphertexts"].(map[string][]byte)
|
||||
for caseKey, ciphertext := range ciphertexts {
|
||||
assert.Equal(gucumber.T, len(plaintexts[caseKey]), len(ciphertext))
|
||||
assert.True(gucumber.T, bytes.Equal(plaintexts[caseKey], ciphertext))
|
||||
}
|
||||
})
|
||||
|
||||
gucumber.Then(`^I encrypt each fixture with "(.+?)" "(.+?)" "(.+?)" and "(.+?)"$`, func(kek, v1, v2, cek string) {
|
||||
var handler s3crypto.CipherDataGenerator
|
||||
var builder s3crypto.ContentCipherBuilder
|
||||
switch kek {
|
||||
case "kms":
|
||||
arn, err := getAliasInformation(v1, v2)
|
||||
assert.Nil(gucumber.T, err)
|
||||
|
||||
b64Arn := base64.StdEncoding.EncodeToString([]byte(arn))
|
||||
assert.Nil(gucumber.T, err)
|
||||
gucumber.World["Masterkey"] = b64Arn
|
||||
|
||||
handler = s3crypto.NewKMSKeyGenerator(kms.New(session.New(&aws.Config{
|
||||
Region: &v2,
|
||||
})), arn)
|
||||
assert.Nil(gucumber.T, err)
|
||||
default:
|
||||
gucumber.T.Skip()
|
||||
}
|
||||
|
||||
switch cek {
|
||||
case "aes_gcm":
|
||||
builder = s3crypto.AESGCMContentCipherBuilder(handler)
|
||||
default:
|
||||
gucumber.T.Skip()
|
||||
}
|
||||
|
||||
sess := session.New(&aws.Config{
|
||||
Region: aws.String("us-west-2"),
|
||||
})
|
||||
c := s3crypto.NewEncryptionClient(sess, builder, func(c *s3crypto.EncryptionClient) {
|
||||
})
|
||||
gucumber.World["encryptionClient"] = c
|
||||
gucumber.World["cek"] = cek
|
||||
})
|
||||
|
||||
gucumber.And(`^upload "(.+?)" data with folder "(.+?)"$`, func(language, folder string) {
|
||||
c := gucumber.World["encryptionClient"].(*s3crypto.EncryptionClient)
|
||||
cek := gucumber.World["cek"].(string)
|
||||
bucket := gucumber.World["bucket"].(string)
|
||||
plaintexts := gucumber.World["plaintexts"].(map[string][]byte)
|
||||
key := gucumber.World["Masterkey"].(string)
|
||||
for caseKey, plaintext := range plaintexts {
|
||||
input := &s3.PutObjectInput{
|
||||
Bucket: &bucket,
|
||||
Key: aws.String("crypto_tests/" + cek + "/" + folder + "/language_" + language + "/ciphertext_test_case_" + caseKey),
|
||||
Body: bytes.NewReader(plaintext),
|
||||
Metadata: map[string]*string{
|
||||
"Masterkey": &key,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := c.PutObject(input)
|
||||
assert.Nil(gucumber.T, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func getAliasInformation(alias, region string) (string, error) {
|
||||
arn := ""
|
||||
svc := kms.New(session.New(&aws.Config{
|
||||
Region: ®ion,
|
||||
}))
|
||||
|
||||
truncated := true
|
||||
var marker *string
|
||||
for truncated {
|
||||
out, err := svc.ListAliases(&kms.ListAliasesInput{
|
||||
Marker: marker,
|
||||
})
|
||||
if err != nil {
|
||||
return arn, err
|
||||
}
|
||||
for _, aliasEntry := range out.Aliases {
|
||||
if *aliasEntry.AliasName == "alias/"+alias {
|
||||
return *aliasEntry.AliasArn, nil
|
||||
}
|
||||
}
|
||||
truncated = *out.Truncated
|
||||
marker = out.NextMarker
|
||||
}
|
||||
|
||||
return "", errors.New("The alias " + alias + " does not exist in your account. Please add the proper alias to a key")
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
|
|
@ -58,7 +57,7 @@ func setup() {
|
|||
|
||||
// Delete the bucket
|
||||
func teardown() {
|
||||
svc := s3.New(session.New())
|
||||
svc := s3.New(integration.Session)
|
||||
|
||||
objs, _ := svc.ListObjects(&s3.ListObjectsInput{Bucket: bucketName})
|
||||
for _, o := range objs.Contents {
|
||||
|
|
@ -128,7 +127,7 @@ func TestUploadConcurrently(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUploadFailCleanup(t *testing.T) {
|
||||
svc := s3.New(session.New())
|
||||
svc := s3.New(integration.Session)
|
||||
|
||||
// Break checksum on 2nd part so it fails
|
||||
part := 0
|
||||
|
|
@ -151,6 +150,7 @@ func TestUploadFailCleanup(t *testing.T) {
|
|||
Body: bytes.NewReader(integBuf12MB),
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.NotContains(t, err.Error(), "MissingRegion")
|
||||
uploadID := ""
|
||||
if merr, ok := err.(s3manager.MultiUploadFailure); ok {
|
||||
uploadID = merr.UploadID()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import (
|
|||
)
|
||||
|
||||
// Session is a shared session for all integration tests to use.
|
||||
var Session = session.New()
|
||||
var Session = session.Must(session.NewSession())
|
||||
|
||||
func init() {
|
||||
logLevel := Session.Config.LogLevel
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package acm
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/acm"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@acm", func() {
|
||||
World["client"] = acm.New(smoke.Session)
|
||||
gucumber.Before("@acm", func() {
|
||||
gucumber.World["client"] = acm.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/apigateway/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/apigateway/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package apigateway
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/apigateway"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@apigateway", func() {
|
||||
World["client"] = apigateway.New(smoke.Session)
|
||||
gucumber.Before("@apigateway", func() {
|
||||
gucumber.World["client"] = apigateway.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/applicationdiscoveryservice"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@applicationdiscoveryservice", func() {
|
||||
World["client"] = applicationdiscoveryservice.New(smoke.Session, &aws.Config{Region: aws.String("us-west-2")})
|
||||
gucumber.Before("@applicationdiscoveryservice", func() {
|
||||
gucumber.World["client"] = applicationdiscoveryservice.New(
|
||||
smoke.Session, &aws.Config{Region: aws.String("us-west-2")},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/autoscaling/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/autoscaling/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package autoscaling
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/autoscaling"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@autoscaling", func() {
|
||||
World["client"] = autoscaling.New(smoke.Session)
|
||||
gucumber.Before("@autoscaling", func() {
|
||||
gucumber.World["client"] = autoscaling.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package cloudformation
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/cloudformation"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@cloudformation", func() {
|
||||
World["client"] = cloudformation.New(smoke.Session)
|
||||
gucumber.Before("@cloudformation", func() {
|
||||
gucumber.World["client"] = cloudformation.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudfront/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudfront/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package cloudfront
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/cloudfront"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@cloudfront", func() {
|
||||
World["client"] = cloudfront.New(smoke.Session)
|
||||
gucumber.Before("@cloudfront", func() {
|
||||
gucumber.World["client"] = cloudfront.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudhsm/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudhsm/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package cloudhsm
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/cloudhsm"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@cloudhsm", func() {
|
||||
World["client"] = cloudhsm.New(smoke.Session)
|
||||
gucumber.Before("@cloudhsm", func() {
|
||||
gucumber.World["client"] = cloudhsm.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudsearch/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudsearch/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package cloudsearch
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/cloudsearch"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@cloudsearch", func() {
|
||||
World["client"] = cloudsearch.New(smoke.Session)
|
||||
gucumber.Before("@cloudsearch", func() {
|
||||
gucumber.World["client"] = cloudsearch.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudtrail/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudtrail/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package cloudtrail
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/cloudtrail"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@cloudtrail", func() {
|
||||
World["client"] = cloudtrail.New(smoke.Session)
|
||||
gucumber.Before("@cloudtrail", func() {
|
||||
gucumber.World["client"] = cloudtrail.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,9 @@ Feature: AWS CloudTrail
|
|||
|
||||
Scenario: Making a request
|
||||
When I call the "DescribeTrails" API
|
||||
Then the response should contain a "trailList"
|
||||
Then the request should be successful
|
||||
|
||||
Scenario: Handling errors
|
||||
When I attempt to call the "DeleteTrail" API with:
|
||||
| Name | faketrail |
|
||||
Then I expect the response error code to be "TrailNotFoundException"
|
||||
And I expect the response error message to include:
|
||||
"""
|
||||
Unknown trail
|
||||
"""
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudwatch/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cloudwatch/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package cloudwatch
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@cloudwatch", func() {
|
||||
World["client"] = cloudwatch.New(smoke.Session)
|
||||
gucumber.Before("@cloudwatch", func() {
|
||||
gucumber.World["client"] = cloudwatch.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package cloudwatchlogs
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@cloudwatchlogs", func() {
|
||||
World["client"] = cloudwatchlogs.New(smoke.Session)
|
||||
gucumber.Before("@cloudwatchlogs", func() {
|
||||
gucumber.World["client"] = cloudwatchlogs.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/codecommit/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/codecommit/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package codecommit
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/codecommit"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@codecommit", func() {
|
||||
World["client"] = codecommit.New(smoke.Session)
|
||||
gucumber.Before("@codecommit", func() {
|
||||
gucumber.World["client"] = codecommit.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/codedeploy/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/codedeploy/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package codedeploy
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/codedeploy"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@codedeploy", func() {
|
||||
World["client"] = codedeploy.New(smoke.Session)
|
||||
gucumber.Before("@codedeploy", func() {
|
||||
gucumber.World["client"] = codedeploy.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/codepipeline/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/codepipeline/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package codepipeline
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/codepipeline"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@codepipeline", func() {
|
||||
World["client"] = codepipeline.New(smoke.Session)
|
||||
gucumber.Before("@codepipeline", func() {
|
||||
gucumber.World["client"] = codepipeline.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package cognitoidentity
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/cognitoidentity"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@cognitoidentity", func() {
|
||||
World["client"] = cognitoidentity.New(smoke.Session)
|
||||
gucumber.Before("@cognitoidentity", func() {
|
||||
gucumber.World["client"] = cognitoidentity.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cognitosync/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/cognitosync/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package cognitosync
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/cognitosync"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@cognitosync", func() {
|
||||
World["client"] = cognitosync.New(smoke.Session)
|
||||
gucumber.Before("@cognitosync", func() {
|
||||
gucumber.World["client"] = cognitosync.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package configservice
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/configservice"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@configservice", func() {
|
||||
World["client"] = configservice.New(smoke.Session)
|
||||
gucumber.Before("@configservice", func() {
|
||||
gucumber.World["client"] = configservice.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/datapipeline/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/datapipeline/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package datapipeline
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/datapipeline"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@datapipeline", func() {
|
||||
World["client"] = datapipeline.New(smoke.Session)
|
||||
gucumber.Before("@datapipeline", func() {
|
||||
gucumber.World["client"] = datapipeline.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/devicefarm/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/devicefarm/client.go
generated
vendored
|
|
@ -7,13 +7,13 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/devicefarm"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@devicefarm", func() {
|
||||
gucumber.Before("@devicefarm", func() {
|
||||
// FIXME remove custom region
|
||||
World["client"] = devicefarm.New(smoke.Session,
|
||||
gucumber.World["client"] = devicefarm.New(smoke.Session,
|
||||
aws.NewConfig().WithRegion("us-west-2"))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package directconnect
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/directconnect"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@directconnect", func() {
|
||||
World["client"] = directconnect.New(smoke.Session)
|
||||
gucumber.Before("@directconnect", func() {
|
||||
gucumber.World["client"] = directconnect.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package directoryservice
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/directoryservice"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@directoryservice", func() {
|
||||
World["client"] = directoryservice.New(smoke.Session)
|
||||
gucumber.Before("@directoryservice", func() {
|
||||
gucumber.World["client"] = directoryservice.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/dynamodb/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/dynamodb/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package dynamodb
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodb"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@dynamodb", func() {
|
||||
World["client"] = dynamodb.New(smoke.Session)
|
||||
gucumber.Before("@dynamodb", func() {
|
||||
gucumber.World["client"] = dynamodb.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package dynamodbstreams
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/dynamodbstreams"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@dynamodbstreams", func() {
|
||||
World["client"] = dynamodbstreams.New(smoke.Session)
|
||||
gucumber.Before("@dynamodbstreams", func() {
|
||||
gucumber.World["client"] = dynamodbstreams.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package ec2
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@ec2", func() {
|
||||
World["client"] = ec2.New(smoke.Session)
|
||||
gucumber.Before("@ec2", func() {
|
||||
gucumber.World["client"] = ec2.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/ecs"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@ecs", func() {
|
||||
gucumber.Before("@ecs", func() {
|
||||
// FIXME remove custom region
|
||||
World["client"] = ecs.New(smoke.Session,
|
||||
gucumber.World["client"] = ecs.New(smoke.Session,
|
||||
aws.NewConfig().WithRegion("us-west-2"))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/efs"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@efs", func() {
|
||||
gucumber.Before("@efs", func() {
|
||||
// FIXME remove custom region
|
||||
World["client"] = efs.New(smoke.Session,
|
||||
gucumber.World["client"] = efs.New(smoke.Session,
|
||||
aws.NewConfig().WithRegion("us-west-2"))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/elasticache/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/elasticache/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package elasticache
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/elasticache"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@elasticache", func() {
|
||||
World["client"] = elasticache.New(smoke.Session)
|
||||
gucumber.Before("@elasticache", func() {
|
||||
gucumber.World["client"] = elasticache.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package elasticbeanstalk
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@elasticbeanstalk", func() {
|
||||
World["client"] = elasticbeanstalk.New(smoke.Session)
|
||||
gucumber.Before("@elasticbeanstalk", func() {
|
||||
gucumber.World["client"] = elasticbeanstalk.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package elasticloadbalancing
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/elb"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@elasticloadbalancing", func() {
|
||||
World["client"] = elb.New(smoke.Session)
|
||||
gucumber.Before("@elasticloadbalancing", func() {
|
||||
gucumber.World["client"] = elb.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package elastictranscoder
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/elastictranscoder"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@elastictranscoder", func() {
|
||||
World["client"] = elastictranscoder.New(smoke.Session)
|
||||
gucumber.Before("@elastictranscoder", func() {
|
||||
gucumber.World["client"] = elastictranscoder.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package emr
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/emr"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@emr", func() {
|
||||
World["client"] = emr.New(smoke.Session)
|
||||
gucumber.Before("@emr", func() {
|
||||
gucumber.World["client"] = emr.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package es
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/elasticsearchservice"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@es", func() {
|
||||
World["client"] = elasticsearchservice.New(smoke.Session)
|
||||
gucumber.Before("@es", func() {
|
||||
gucumber.World["client"] = elasticsearchservice.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/glacier/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/glacier/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package glacier
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/glacier"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@glacier", func() {
|
||||
World["client"] = glacier.New(smoke.Session)
|
||||
gucumber.Before("@glacier", func() {
|
||||
gucumber.World["client"] = glacier.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package iam
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@iam", func() {
|
||||
World["client"] = iam.New(smoke.Session)
|
||||
gucumber.Before("@iam", func() {
|
||||
gucumber.World["client"] = iam.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
8
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/iotdataplane/client.go
generated
vendored
8
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/iotdataplane/client.go
generated
vendored
|
|
@ -8,19 +8,19 @@ import (
|
|||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/iot"
|
||||
"github.com/aws/aws-sdk-go/service/iotdataplane"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@iotdataplane", func() {
|
||||
gucumber.Before("@iotdataplane", func() {
|
||||
svc := iot.New(smoke.Session)
|
||||
result, err := svc.DescribeEndpoint(&iot.DescribeEndpointInput{})
|
||||
if err != nil {
|
||||
World["error"] = err
|
||||
gucumber.World["error"] = err
|
||||
return
|
||||
}
|
||||
|
||||
World["client"] = iotdataplane.New(smoke.Session, aws.NewConfig().
|
||||
gucumber.World["client"] = iotdataplane.New(smoke.Session, aws.NewConfig().
|
||||
WithEndpoint(*result.EndpointAddress))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
# language: en
|
||||
@iotdataplane @client
|
||||
|
||||
Feature: AWS IoT Data Plane
|
||||
|
||||
Scenario: Handling errors
|
||||
When I attempt to call the "GetThingShadow" API with:
|
||||
| ThingName | "fakeThing" |
|
||||
Then I expect the response error code to be "InvalidRequestException"
|
||||
And I expect the response error message to include:
|
||||
"""
|
||||
Invalid thing name
|
||||
"""
|
||||
| thingName | fake-thing |
|
||||
Then I expect the response error code to be "ResourceNotFoundException"
|
||||
|
|
|
|||
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/kinesis/client.go
generated
vendored
6
vendor/github.com/aws/aws-sdk-go/awstesting/integration/smoke/kinesis/client.go
generated
vendored
|
|
@ -6,11 +6,11 @@ package kinesis
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/kinesis"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@kinesis", func() {
|
||||
World["client"] = kinesis.New(smoke.Session)
|
||||
gucumber.Before("@kinesis", func() {
|
||||
gucumber.World["client"] = kinesis.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package kms
|
|||
import (
|
||||
"github.com/aws/aws-sdk-go/awstesting/integration/smoke"
|
||||
"github.com/aws/aws-sdk-go/service/kms"
|
||||
. "github.com/lsegal/gucumber"
|
||||
"github.com/gucumber/gucumber"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Before("@kms", func() {
|
||||
World["client"] = kms.New(smoke.Session)
|
||||
gucumber.Before("@kms", func() {
|
||||
gucumber.World["client"] = kms.New(smoke.Session)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue