update and vendor all dependencies (#200)

* chore: update and vendor all dependencies

* chore: don't forget custom import repo-infra
This commit is contained in:
Martin Linkhorst 2017-05-11 11:09:49 +02:00 committed by GitHub
parent f9668b8678
commit 8b8312c89a
2345 changed files with 313747 additions and 254275 deletions

168
glide.lock generated
View File

@ -1,5 +1,5 @@
hash: 14f947c6110ead781a61ecc2f0a299cdc730e0968c953226e67dc5695e4f6f20
updated: 2017-04-26T11:21:36.188940531+02:00
hash: d46cd439386717ec9ea20d75ab7a8c272acbfee511338b56a0797426ec29b4ee
updated: 2017-05-09T10:53:15.711029881+02:00
imports:
- name: bitbucket.org/ww/goautoneg
version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675
@ -17,7 +17,7 @@ imports:
- name: github.com/alecthomas/units
version: 2efee857e7cfd4f3d0138cc3cbb1b4966962b93a
- name: github.com/aws/aws-sdk-go
version: 695fe24acaf9afe80b0ce261d4637f42ba0b4c7d
version: fa7f88097f64d1a2bcc65f9b9b547f363082d496
subpackages:
- aws
- aws/awserr
@ -41,29 +41,12 @@ imports:
- private/protocol/rest
- private/protocol/restxml
- private/protocol/xml/xmlutil
- private/waiter
- service/route53
- service/sts
- name: github.com/beorn7/perks
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
subpackages:
- quantile
- name: github.com/blang/semver
version: 31b736133b98f26d5e078ec9eb591666edfd091f
- name: github.com/coreos/go-oidc
version: 5644a2f50e2d2d5ba0b474bc5bc55fea1925936d
subpackages:
- http
- jose
- key
- oauth2
- oidc
- name: github.com/coreos/pkg
version: fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
subpackages:
- health
- httputil
- timeutil
- name: github.com/davecgh/go-spew
version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
subpackages:
@ -74,14 +57,14 @@ imports:
- digest
- reference
- name: github.com/emicklei/go-restful
version: 89ef8af493ab468a45a42bb0d89a06fccdd2fb22
version: 09691a3b6378b740595c1002f40c34dd5f218a22
subpackages:
- log
- swagger
- name: github.com/ghodss/yaml
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
- name: github.com/go-ini/ini
version: c437d20015c2ab6454b7a66a13109ff0fb99e17a
version: e7fea39b01aea8d5671f6858f0532f56e8bff3a5
- name: github.com/go-openapi/jsonpointer
version: 46af16f9f7b149af66e5d1bd010e3574dc06de98
- name: github.com/go-openapi/jsonreference
@ -102,17 +85,13 @@ imports:
subpackages:
- proto
- name: github.com/google/gofuzz
version: bbcb9da2d746f8bdbd6a936686a0a6067ada0ec5
- name: github.com/google/uuid
version: 064e2069ce9c359c118179501254f67d7d37ba24
version: 44d81051d367757e1c7c6a5a86423ece9afcf63c
- name: github.com/howeyc/gopass
version: 3ca23474a7c7203e0a0a070fd33508f6efdb9b3d
- name: github.com/imdario/mergo
version: 6633656539c1639d9d78127b7d47c622b5d7b6dc
- name: github.com/jmespath/go-jmespath
version: bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
- name: github.com/jonboulle/clockwork
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
- name: github.com/juju/ratelimit
version: 77ed1c8a01217656d2080ad51981f6e99adaa177
- name: github.com/kubernetes/repo-infra
@ -127,8 +106,6 @@ imports:
version: fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a
subpackages:
- pbutil
- name: github.com/pborman/uuid
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
- name: github.com/prometheus/client_golang
version: c5b7fccd204277076155f10851dad72b76a49317
subpackages:
@ -152,13 +129,13 @@ imports:
- name: github.com/Sirupsen/logrus
version: ba1b36c82c5e05c4f912a88eab0dcd91a171688f
- name: github.com/spf13/pflag
version: 5ccb023bc27df288a957c5e994cd44fd19619465
version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7
- name: github.com/ugorji/go
version: f1f1a805ed361a0e078bb537e4ea78cd37dcf065
version: ded73eae5db7e7a0ef6f55aace87a2873c5d2b74
subpackages:
- codec
- name: golang.org/x/crypto
version: 1f22c0103821b9390939b6776727195525381532
version: d172538b2cfce0c13cee31e647d0367aa8cd2486
subpackages:
- ssh/terminal
- name: golang.org/x/net
@ -217,27 +194,75 @@ imports:
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
- name: gopkg.in/yaml.v2
version: 53feefa2559fb8dfa8d81baad31be332c97d6c77
- name: k8s.io/apimachinery
version: 75b8dd260ef0469d96d578705a87cffd0e09dab8
subpackages:
- pkg/api/errors
- pkg/api/meta
- pkg/api/resource
- pkg/apimachinery
- pkg/apimachinery/announced
- pkg/apimachinery/registered
- pkg/apis/meta/v1
- pkg/apis/meta/v1/unstructured
- pkg/conversion
- pkg/conversion/queryparams
- pkg/fields
- pkg/labels
- pkg/openapi
- pkg/runtime
- pkg/runtime/schema
- pkg/runtime/serializer
- pkg/runtime/serializer/json
- pkg/runtime/serializer/protobuf
- pkg/runtime/serializer/recognizer
- pkg/runtime/serializer/streaming
- pkg/runtime/serializer/versioning
- pkg/selection
- pkg/types
- pkg/util/errors
- pkg/util/framer
- pkg/util/intstr
- pkg/util/json
- pkg/util/net
- pkg/util/rand
- pkg/util/runtime
- pkg/util/sets
- pkg/util/validation
- pkg/util/validation/field
- pkg/util/wait
- pkg/util/yaml
- pkg/version
- pkg/watch
- third_party/forked/golang/reflect
- name: k8s.io/client-go
version: e121606b0d09b2e1c467183ee46217fa85a6b672
version: 3627aeb7d4f6ade38f995d2c923e459146493c7e
subpackages:
- discovery
- discovery/fake
- kubernetes
- kubernetes/fake
- kubernetes/scheme
- kubernetes/typed/apps/v1beta1
- kubernetes/typed/apps/v1beta1/fake
- kubernetes/typed/authentication/v1
- kubernetes/typed/authentication/v1/fake
- kubernetes/typed/authentication/v1beta1
- kubernetes/typed/authentication/v1beta1/fake
- kubernetes/typed/authorization/v1
- kubernetes/typed/authorization/v1/fake
- kubernetes/typed/authorization/v1beta1
- kubernetes/typed/authorization/v1beta1/fake
- kubernetes/typed/autoscaling/v1
- kubernetes/typed/autoscaling/v1/fake
- kubernetes/typed/autoscaling/v2alpha1
- kubernetes/typed/autoscaling/v2alpha1/fake
- kubernetes/typed/batch/v1
- kubernetes/typed/batch/v1/fake
- kubernetes/typed/batch/v2alpha1
- kubernetes/typed/batch/v2alpha1/fake
- kubernetes/typed/certificates/v1alpha1
- kubernetes/typed/certificates/v1alpha1/fake
- kubernetes/typed/certificates/v1beta1
- kubernetes/typed/certificates/v1beta1/fake
- kubernetes/typed/core/v1
- kubernetes/typed/core/v1/fake
- kubernetes/typed/extensions/v1beta1
@ -246,39 +271,39 @@ imports:
- kubernetes/typed/policy/v1beta1/fake
- kubernetes/typed/rbac/v1alpha1
- kubernetes/typed/rbac/v1alpha1/fake
- kubernetes/typed/rbac/v1beta1
- kubernetes/typed/rbac/v1beta1/fake
- kubernetes/typed/settings/v1alpha1
- kubernetes/typed/settings/v1alpha1/fake
- kubernetes/typed/storage/v1
- kubernetes/typed/storage/v1/fake
- kubernetes/typed/storage/v1beta1
- kubernetes/typed/storage/v1beta1/fake
- pkg/api
- pkg/api/errors
- pkg/api/install
- pkg/api/meta
- pkg/api/meta/metatypes
- pkg/api/resource
- pkg/api/unversioned
- pkg/api/v1
- pkg/api/validation/path
- pkg/apimachinery
- pkg/apimachinery/announced
- pkg/apimachinery/registered
- pkg/apis/apps
- pkg/apis/apps/install
- pkg/apis/apps/v1beta1
- pkg/apis/authentication
- pkg/apis/authentication/install
- pkg/apis/authentication/v1
- pkg/apis/authentication/v1beta1
- pkg/apis/authorization
- pkg/apis/authorization/install
- pkg/apis/authorization/v1
- pkg/apis/authorization/v1beta1
- pkg/apis/autoscaling
- pkg/apis/autoscaling/install
- pkg/apis/autoscaling/v1
- pkg/apis/autoscaling/v2alpha1
- pkg/apis/batch
- pkg/apis/batch/install
- pkg/apis/batch/v1
- pkg/apis/batch/v2alpha1
- pkg/apis/certificates
- pkg/apis/certificates/install
- pkg/apis/certificates/v1alpha1
- pkg/apis/certificates/v1beta1
- pkg/apis/extensions
- pkg/apis/extensions/install
- pkg/apis/extensions/v1beta1
@ -288,55 +313,19 @@ imports:
- pkg/apis/rbac
- pkg/apis/rbac/install
- pkg/apis/rbac/v1alpha1
- pkg/apis/rbac/v1beta1
- pkg/apis/settings
- pkg/apis/settings/install
- pkg/apis/settings/v1alpha1
- pkg/apis/storage
- pkg/apis/storage/install
- pkg/apis/storage/v1
- pkg/apis/storage/v1beta1
- pkg/auth/user
- pkg/conversion
- pkg/conversion/queryparams
- pkg/fields
- pkg/genericapiserver/openapi/common
- pkg/labels
- pkg/runtime
- pkg/runtime/serializer
- pkg/runtime/serializer/json
- pkg/runtime/serializer/protobuf
- pkg/runtime/serializer/recognizer
- pkg/runtime/serializer/streaming
- pkg/runtime/serializer/versioning
- pkg/selection
- pkg/third_party/forked/golang/reflect
- pkg/third_party/forked/golang/template
- pkg/types
- pkg/util
- pkg/util/cert
- pkg/util/clock
- pkg/util/errors
- pkg/util/flowcontrol
- pkg/util/framer
- pkg/util/homedir
- pkg/util/integer
- pkg/util/intstr
- pkg/util/json
- pkg/util/jsonpath
- pkg/util/labels
- pkg/util/net
- pkg/util/parsers
- pkg/util/rand
- pkg/util/runtime
- pkg/util/sets
- pkg/util/uuid
- pkg/util/validation
- pkg/util/validation/field
- pkg/util/wait
- pkg/util/yaml
- pkg/version
- pkg/watch
- pkg/watch/versioned
- plugin/pkg/client/auth
- plugin/pkg/client/auth/gcp
- plugin/pkg/client/auth/oidc
- rest
- rest/watch
- testing
- tools/auth
- tools/clientcmd
@ -345,4 +334,9 @@ imports:
- tools/clientcmd/api/v1
- tools/metrics
- transport
- util/cert
- util/clock
- util/flowcontrol
- util/homedir
- util/integer
testImports: []

View File

@ -5,20 +5,15 @@ import:
- package: github.com/alecthomas/kingpin
version: ~2.2.4
- package: github.com/aws/aws-sdk-go
version: ~1.7.9
version: ~1.8.20
subpackages:
- aws
- aws/session
- service/route53
- package: github.com/google/uuid
version: ~0.2.0
- package: github.com/prometheus/client_golang
version: ~0.8.0
subpackages:
- prometheus
- prometheus/promhttp
- package: github.com/spf13/pflag
- package: github.com/kubernetes/repo-infra
- package: golang.org/x/net
subpackages:
- context
@ -29,10 +24,14 @@ import:
subpackages:
- dns/v1
- googleapi
- package: k8s.io/apimachinery
subpackages:
- pkg/apis/meta/v1
- package: k8s.io/client-go
version: ~2.0.0
version: ~3.0.0-beta.0
subpackages:
- kubernetes
- pkg/api/v1
- pkg/apis/extensions/v1beta1
- tools/clientcmd
- package: github.com/kubernetes/repo-infra

View File

@ -23,8 +23,9 @@ import (
"text/template"
log "github.com/Sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
"github.com/kubernetes-incubator/external-dns/endpoint"
@ -62,7 +63,7 @@ func NewIngressSource(client kubernetes.Interface, namespace string, fqdntemplat
// Endpoints returns endpoint objects for each host-target combination that should be processed.
// Retrieves all ingress resources on all namespaces
func (sc *ingressSource) Endpoints() ([]*endpoint.Endpoint, error) {
ingresses, err := sc.client.Extensions().Ingresses(sc.namespace).List(v1.ListOptions{})
ingresses, err := sc.client.Extensions().Ingresses(sc.namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}

View File

@ -19,6 +19,7 @@ package source
import (
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
@ -369,7 +370,7 @@ type fakeIngress struct {
func (ing fakeIngress) Ingress() *v1beta1.Ingress {
ingress := &v1beta1.Ingress{
ObjectMeta: v1.ObjectMeta{
ObjectMeta: metav1.ObjectMeta{
Namespace: ing.namespace,
Name: ing.name,
Annotations: ing.annotations,

View File

@ -23,6 +23,8 @@ import (
"text/template"
log "github.com/Sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/pkg/api/v1"
@ -65,7 +67,7 @@ func NewServiceSource(client kubernetes.Interface, namespace, fqdntemplate strin
// Endpoints returns endpoint objects for each service that should be processed.
func (sc *serviceSource) Endpoints() ([]*endpoint.Endpoint, error) {
services, err := sc.client.CoreV1().Services(sc.namespace).List(v1.ListOptions{})
services, err := sc.client.CoreV1().Services(sc.namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}

View File

@ -20,6 +20,7 @@ import (
"net"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/pkg/api/v1"
@ -375,7 +376,7 @@ func testServiceEndpoints(t *testing.T) {
}
service := &v1.Service{
ObjectMeta: v1.ObjectMeta{
ObjectMeta: metav1.ObjectMeta{
Namespace: tc.svcNamespace,
Name: tc.svcName,
Labels: tc.labels,
@ -415,7 +416,7 @@ func BenchmarkServiceEndpoints(b *testing.B) {
kubernetes := fake.NewSimpleClientset()
service := &v1.Service{
ObjectMeta: v1.ObjectMeta{
ObjectMeta: metav1.ObjectMeta{
Namespace: "testing",
Name: "foo",
Annotations: map[string]string{

View File

@ -0,0 +1,14 @@
Please fill out the sections below to help us address your issue.
### Version of AWS SDK for Go?
### Version of Go (`go version`)?
### What issue did you see?
### Steps to reproduce
If you have have an runnable example, please include it.

View File

@ -0,0 +1,3 @@
For changes to files under the `/model/` folder, and manual edits to autogenerated code (e.g. `/service/s3/api.go`) please create an Issue instead of a PR for those type of changes.
If there is an existing bug or feature this PR is answers please reference it here.

View File

@ -1,3 +1,297 @@
Release v1.8.20 (2017-05-04)
===
### Service Client Updates
* `service/ecs`: Updates service API, documentation, and paginators
* Exposes container instance registration time in ECS:DescribeContainerInstances.
* `aws/endpoints`: Updated Regions and Endpoints metadata.
* `service/marketplaceentitlementservice`: Adds new service
* `service/lambda`: Updates service API and documentation
* Support for UpdateFunctionCode DryRun option
Release v1.8.19 (2017-04-28)
===
### Service Client Updates
* `service/cloudformation`: Updates service waiters and paginators
* Adding back the removed waiters and paginators.
Release v1.8.18 (2017-04-28)
===
### Service Client Updates
* `service/cloudformation`: Updates service API, documentation, waiters, paginators, and examples
* API update for CloudFormation: New optional parameter ClientRequestToken which can be used as an idempotency token to safely retry certain operations as well as tagging StackEvents.
* `service/rds`: Updates service API, documentation, and examples
* The DescribeDBClusterSnapshots API now returns a SourceDBClusterSnapshotArn field which identifies the source DB cluster snapshot of a copied snapshot.
* `service/rekognition`: Updates service API
* Fix for missing file type check
* `service/snowball`: Updates service API, documentation, and paginators
* The Snowball API has a new exception that can be thrown for list operation requests.
* `service/sqs`: Updates service API, documentation, and paginators
* Adding server-side encryption (SSE) support to SQS by integrating with AWS KMS; adding new queue attributes to SQS CreateQueue, SetQueueAttributes and GetQueueAttributes APIs to support SSE.
Release v1.8.17 (2017-04-26)
===
### Service Client Updates
* `aws/endpoints`: Updated Regions and Endpoints metadata.
* `service/rds`: Updates service API and documentation
* With Amazon Relational Database Service (Amazon RDS) running MySQL or Amazon Aurora, you can now authenticate to your DB instance using IAM database authentication.
Release v1.8.16 (2017-04-21)
===
### Service Client Updates
* `service/appstream`: Updates service API, documentation, and paginators
* The new feature named "Default Internet Access" will enable Internet access from AppStream 2.0 instances - image builders and fleet instances. Admins will check a flag either through AWS management console for AppStream 2.0 or through API while creating an image builder or while creating/updating a fleet.
* `service/kinesis`: Updates service API, documentation, waiters, and paginators
* Adds a new waiter, StreamNotExists, to Kinesis.
### SDK Enhancements
* `aws/endpoints`: Add utilities improving endpoints lookup (#1218)
* Adds several utilities to the endpoints packages to make looking up partitions, regions, and services easier.
* Fixes #994
### SDK Bugs
* `private/protocol/xml/xmlutil`: Fix unmarshaling dropping errors (#1219)
* The XML unmarshaler would drop any serialization or body read error that occurred on the floor effectively hiding any errors that would occur.
* Fixes #1205
Release v1.8.15 (2017-04-20)
===
### Service Client Updates
* `service/devicefarm`: Updates service API and documentation
* API Update for AWS Device Farm: Support for Deals and Promotions
* `service/directconnect`: Updates service documentation
* Documentation updates for AWS Direct Connect.
* `service/elbv2`: Updates service waiters
* `service/kms`: Updates service documentation and examples
* Doc-only update for Key Management Service (KMS): Update docs for GrantConstraints and GenerateRandom
* `service/route53`: Updates service documentation
* Release notes: SDK documentation now includes examples for ChangeResourceRecordSets for all types of resource record set, such as weighted, alias, and failover.
* `service/route53domains`: Updates service API, documentation, and paginators
* Adding examples and other documentation updates.
### SDK Enhancements
* `service/s3`: Add utilities to make getting a bucket's region easier (#1207)
* Adds two features which make it easier to get a bucket's region, `s3.NormalizeBucketLocation` and `s3manager.GetBucketRegion`.
### SDK Bugs
* `service/s3`: Fix HeadObject's incorrect documented error codes (#1213)
* The HeadObject's model incorrectly states that the operation can return the NoSuchKey error code.
* Fixes #1208
Release v1.8.14 (2017-04-19)
===
### Service Client Updates
* `service/apigateway`: Updates service API and documentation
* Add support for "embed" property.
* `service/codestar`: Adds new service
* AWS CodeStar is a cloud-based service for creating, managing, and working with software development projects on AWS. An AWS CodeStar project creates and integrates AWS services for your project development toolchain. AWS CodeStar also manages the permissions required for project users.
* `service/ec2`: Updates service API and documentation
* Adds support for creating an Amazon FPGA Image (AFI) from a specified design checkpoint (DCP).
* `service/iam`: Updates service API and documentation
* This changes introduces a new IAM role type, Service Linked Role, which works like a normal role but must be managed via services' control.
* `service/lambda`: Updates service API and documentation
* Lambda integration with CloudDebugger service to enable customers to enable tracing for the Lambda functions and send trace information to the CloudDebugger service.
* `service/lexmodelbuildingservice`: Adds new service
* `service/polly`: Updates service API, documentation, and paginators
* API Update for Amazon Polly: Add support for speech marks
* `service/rekognition`: Updates service API and documentation
* Given an image, the API detects explicit or suggestive adult content in the image and returns a list of corresponding labels with confidence scores, as well as a taxonomy (parent-child relation) for each label.
Release v1.8.13 (2017-04-18)
===
### Service Client Updates
* `service/lambda`: Updates service API and documentation
* You can use tags to group and filter your Lambda functions, making it easier to analyze them for billing allocation purposes. For more information, see Tagging Lambda Functions. You can now write or upgrade your Lambda functions using Python version 3.6. For more information, see Programming Model for Authoring Lambda Functions in Python. Note: Features will be rolled out in the US regions on 4/19.
### SDK Enhancements
* `aws/request`: add support for appengine's custom standard library (#1190)
* Remove syscall error checking on appengine platforms.
Release v1.8.12 (2017-04-11)
===
### Service Client Updates
* `service/apigateway`: Updates service API and documentation
* API Gateway request validators
* `service/batch`: Updates service API and documentation
* API Update for AWS Batch: Customer provided AMI for MANAGED Compute Environment
* `service/gamelift`: Updates service API and documentation
* Allows developers to utilize an improved workflow when calling our Queues API and introduces a new feature that allows developers to specify a maximum allowable latency per Queue.
* `service/opsworks`: Updates service API, documentation, and paginators
* Cloudwatch Logs agent configuration can now be attached to OpsWorks Layers using CreateLayer and UpdateLayer. OpsWorks will then automatically install and manage the CloudWatch Logs agent on the instances part of the OpsWorks Layer.
### SDK Bugs
* `aws/client`: Fix clients polluting handler list (#1197)
* Fixes the clients potentially polluting the passed in handler list with the client's customizations. This change ensures every client always works with a clean copy of the request handlers and it cannot pollute the handlers back upstream.
* Fixes #1184
* `aws/request`: Fix waiter error match condition (#1195)
* Fixes the waiters's matching overwriting the request's err, effectively ignoring the error condition. This broke waiters with the FailureWaiterState matcher state.
Release v1.8.11 (2017-04-07)
===
### Service Client Updates
* `service/redshift`: Updates service API, documentation, and paginators
* This update adds the GetClusterCredentials API which is used to get temporary login credentials to the cluster. AccountWithRestoreAccess now has a new member AccountAlias, this is the identifier of the AWS support account authorized to restore the specified snapshot. This is added to support the feature where the customer can share their snapshot with the Amazon Redshift Support Account without having to manually specify the AWS Redshift Service account ID on the AWS Console/API.
Release v1.8.10 (2017-04-06)
===
### Service Client Updates
* `service/elbv2`: Updates service documentation
Release v1.8.9 (2017-04-05)
===
### Service Client Updates
* `service/elasticache`: Updates service API, documentation, paginators, and examples
* ElastiCache added support for testing the Elasticache Multi-AZ feature with Automatic Failover.
Release v1.8.8 (2017-04-04)
===
### Service Client Updates
* `service/cloudwatch`: Updates service API, documentation, and paginators
* Amazon Web Services announced the immediate availability of two additional alarm configuration rules for Amazon CloudWatch Alarms. The first rule is for configuring missing data treatment. Customers have the options to treat missing data as alarm threshold breached, alarm threshold not breached, maintain alarm state and the current default treatment. The second rule is for alarms based on percentiles metrics that can trigger unnecassarily if the percentile is calculated from a small number of samples. The new rule can treat percentiles with low sample counts as same as missing data. If the first rule is enabled, the same treatment will be applied when an alarm encounters a percentile with low sample counts.
Release v1.8.7 (2017-04-03)
===
### Service Client Updates
* `service/lexruntimeservice`: Updates service API and documentation
* Adds support to PostContent for speech input
### SDK Enhancements
* `aws/request`: Improve handler copy, push back, push front performance (#1171)
* Minor optimization to the handler list's handling of copying and pushing request handlers to the handler list.
* Update codegen header to use Go std wording (#1172)
* Go recently accepted the proposal for standard generated file header wording in, https://golang.org/s/generatedcode.
### SDK Bugs
* `service/dynamodb`: Fix DynamoDB using custom retryer (#1170)
* Fixes (#1139) the DynamoDB service client clobbering any custom retryer that was passed into the service client or Session's config.
Release v1.8.6 (2017-04-01)
===
### Service Client Updates
* `service/clouddirectory`: Updates service API and documentation
* ListObjectAttributes now supports filtering by facet.
* `aws/endpoints`: Updated Regions and Endpoints metadata.
Release v1.8.5 (2017-03-30)
===
### Service Client Updates
* `service/cloudformation`: Updates service waiters and paginators
* Adding paginators for ListExports and ListImports
* `service/cloudfront`: Adds new service
* Amazon CloudFront now supports user configurable HTTP Read and Keep-Alive Idle Timeouts for your Custom Origin Servers
* `service/configservice`: Updates service documentation
* `aws/endpoints`: Updated Regions and Endpoints metadata.
* `service/resourcegroupstaggingapi`: Adds new service
* `service/storagegateway`: Updates service API and documentation
* File gateway mode in AWS Storage gateway provides access to objects in S3 as files on a Network File System (NFS) mount point. Once a file share is created, any changes made externally to the S3 bucket will not be reflected by the gateway. Using the cache refresh feature in this update, the customer can trigger an on-demand scan of the keys in their S3 bucket and refresh the file namespace cached on the gateway. It takes as an input the fileShare ARN and refreshes the cache for only that file share. Additionally there is new functionality on file gateway that allows you configure what squash options they would like on their file share, this allows a customer to configure their gateway to not squash root permissions. This can be done by setting options in NfsOptions for CreateNfsFileShare and UpdateNfsFileShare APIs.
Release v1.8.4 (2017-03-28)
===
### Service Client Updates
* `service/batch`: Updates service API, documentation, and paginators
* Customers can now provide a retryStrategy as part of the RegisterJobDefinition and SubmitJob API calls. The retryStrategy object has a number value for attempts. This is the number of non successful executions before a job is considered FAILED. In addition, the JobDetail object now has an attempts field and shows all execution attempts.
* `service/ec2`: Updates service API and documentation
* Customers can now tag their Amazon EC2 Instances and Amazon EBS Volumes at
the time of their creation. You can do this from the EC2 Instance launch
wizard or through the RunInstances or CreateVolume APIs. By tagging
resources at the time of creation, you can eliminate the need to run custom
tagging scripts after resource creation. In addition, you can now set
resource-level permissions on the CreateVolume, CreateTags, DeleteTags, and
the RunInstances APIs. This allows you to implement stronger security
policies by giving you more granular control over which users and groups
have access to these APIs. You can also enforce the use of tagging and
control what tag keys and values are set on your resources. When you combine
tag usage and resource-level IAM policies together, you can ensure your
instances and volumes are properly secured upon creation and achieve more
accurate cost allocation reporting. These new features are provided at no
additional cost.
### SDK Enhancements
* `aws/request`: Add retry support for RequestTimeoutException (#1158)
* Adds support for retrying RequestTimeoutException error code that is returned by some services.
### SDK Bugs
* `private/model/api`: Fix Waiter and Paginators panic on nil param inputs (#1157)
* Corrects the code generation for Paginators and waiters that caused a panic if nil input parameters were used with the operations.
Release v1.8.3 (2017-03-27)
===
## Service Client Updates
* `service/ssm`: Updates service API, documentation, and paginators
* Updated validation rules for SendCommand and RegisterTaskWithMaintenanceWindow APIs.
Release v1.8.2 (2017-03-24)
===
Service Client Updates
---
* `service/applicationautoscaling`: Updates service API, documentation, and paginators
* Application AutoScaling is launching support for a new target resource (AppStream 2.0 Fleets) as a scalable target.
* `service/cloudtrail`: Updates service API and documentation
* Doc-only Update for CloudTrail: Add required parameters for GetEventSelectors and PutEventSelectors
Release v1.8.1 (2017-03-23)
===
Service Client Updates
---
* `service/applicationdiscoveryservice`: Updates service API, documentation, and paginators
* Adds export configuration options to the AWS Discovery Service API.
* `service/elbv2`: Updates waiters
* `aws/endpoints`: Updated Regions and Endpoints metadata.
* `service/lambda`: Updates service API and paginators
* Adds support for new runtime Node.js v6.10 for AWS Lambda service
Release v1.8.0 (2017-03-22)
===
Service Client Updates
---
* `service/codebuild`: Updates service documentation
* `service/directconnect`: Updates service API
* Deprecated DescribeConnectionLoa, DescribeInterconnectLoa, AllocateConnectionOnInterconnect and DescribeConnectionsOnInterconnect operations in favor of DescribeLoa, DescribeLoa, AllocateHostedConnection and DescribeHostedConnections respectively.
* `service/marketplacecommerceanalytics`: Updates service API, documentation, and paginators
* This update adds a new data set, us_sales_and_use_tax_records, which enables AWS Marketplace sellers to programmatically access to their U.S. Sales and Use Tax report data.
* `service/pinpoint`: Updates service API and documentation
* Amazon Pinpoint User Segmentation
* Added ability to segment endpoints by user attributes in addition to endpoint attributes. Amazon Pinpoint Event Stream Preview
* Added functionality to publish raw app analytics and campaign events data as events streams to Kinesis and Kinesis Firehose
* The feature provides developers with increased flexibility of exporting raw events to S3, Redshift, Elasticsearch using a Kinesis Firehose stream or enable real time event processing use cases using a Kinesis stream
* `service/rekognition`: Updates service documentation.
SDK Features
---
* `aws/request`: Add support for context.Context to SDK API operation requests (#1132)
* Adds support for context.Context to the SDK by adding `WithContext` methods for each API operation, Paginators and Waiters. e.g `PutObjectWithContext`. This change also adds the ability to provide request functional options to the method calls instead of requiring you to use the `Request` API operation method (e.g `PutObjectRequest`).
* Adds a `Complete` Request handler list that will be called ever time a request is completed. This includes both success and failure. Complete will only be called once per API operation request.
* `private/waiter` package moved from the private group to `aws/request/waiter` and made publicly available.
* Adds Context support to all API operations, Waiters(WaitUntil) and Paginators(Pages) methods.
* Adds Context support for s3manager and s3crypto clients.
SDK Enhancements
---
* `aws/signer/v4`: Adds support for unsigned payload signer config (#1130)
* Adds configuration option to the v4.Signer to specify the request's body should not be signed. This will only correclty function on services that support unsigned payload. e.g. S3, Glacier.
SDK Bug Fixes
---
* `service/s3`: Fix S3 HostID to be available in S3 request error message (#1131)
* Adds a new type s3.RequestFailure which exposes the S3 HostID value from a S3 API operation response. This is helpful when you have an error with S3, and need to contact support. Both RequestID and HostID are needed.
* `private/model/api`: Do not return a link if uid is empty (#1133)
* Fixes SDK's doc generation to not generate API reference doc links if the SDK us unable to create a valid link.
* `aws/request`: Optimization to handler list copy to prevent multiple alloc calls. (#1134)
Release v1.7.9 (2017-03-13)
===

View File

@ -0,0 +1,5 @@
### SDK Features
### SDK Enhancements
### SDK Bugs

View File

@ -64,6 +64,11 @@ Please be aware of the following notes prior to opening a pull request:
SDK's test coverage percentage are unlikely to be merged until tests have
been added.
5. The JSON files under the SDK's `models` folder are sourced from outside the SDK.
Such as `models/apis/ec2/2016-11-15/api.json`. We will not accept pull requests
directly on these models. If you discover an issue with the models please
create a Github [issue](issues) describing the issue.
### Testing
To run the tests locally, running the `make unit` command will `go get` the

View File

@ -5,6 +5,7 @@ LINTIGNORESTUTTER='service/[^/]+/(api|service)\.go:.+(and that stutters)'
LINTIGNOREINFLECT='service/[^/]+/(api|errors|service)\.go:.+(method|const) .+ should be '
LINTIGNOREINFLECTS3UPLOAD='service/s3/s3manager/upload\.go:.+struct field SSEKMSKeyId should be '
LINTIGNOREDEPS='vendor/.+\.go'
LINTIGNOREPKGCOMMENT='service/[^/]+/doc_custom.go:.+package comment should be of the form'
UNIT_TEST_TAGS="example codegen"
SDK_WITH_VENDOR_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/src")
@ -64,6 +65,9 @@ integration: get-deps-tests integ-custom smoke-tests performance
integ-custom:
go test -tags "integration" ./awstesting/integration/customizations/...
cleanup-integ:
go run -tags "integration" ./awstesting/cmd/bucket_cleanup/main.go "aws-sdk-go-integration"
smoke-tests: get-deps-tests
gucumber -go-tags "integration" ./awstesting/integration/smoke
@ -123,7 +127,7 @@ verify: get-deps-verify lint vet
lint:
@echo "go lint SDK and vendor packages"
@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}`; \
lint=`echo "$$lint" | grep -E -v -e ${LINTIGNOREDOT} -e ${LINTIGNOREDOC} -e ${LINTIGNORECONST} -e ${LINTIGNORESTUTTER} -e ${LINTIGNOREINFLECT} -e ${LINTIGNOREDEPS} -e ${LINTIGNOREINFLECTS3UPLOAD} -e ${LINTIGNOREPKGCOMMENT}`; \
echo "$$lint"; \
if [ "$$lint" != "" ] && [ "$$lint" != "skipping golint" ]; then exit 1; fi

View File

@ -1,11 +1,6 @@
# AWS SDK for Go
[![API Reference](http://img.shields.io/badge/api-reference-blue.svg)](http://docs.aws.amazon.com/sdk-for-go/api) [![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://img.shields.io/travis/aws/aws-sdk-go.svg)](https://travis-ci.org/aws/aws-sdk-go) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
<span style="display: inline-block;">
[![API Reference](http://img.shields.io/badge/api-reference-blue.svg)](http://docs.aws.amazon.com/sdk-for-go/api)
[![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://img.shields.io/travis/aws/aws-sdk-go.svg)](https://travis-ci.org/aws/aws-sdk-go)
[![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
</span>
# AWS SDK for Go
aws-sdk-go is the official AWS SDK for the Go programming language.
@ -33,6 +28,7 @@ These two processes will still include the `vendor` folder and it should be dele
## Getting Help
Please use these community resources for getting help. We use the GitHub issues for tracking bugs and feature requests.
* Ask a question on [StackOverflow](http://stackoverflow.com/) and tag it with the [`aws-sdk-go`](http://stackoverflow.com/questions/tagged/aws-sdk-go) tag.
* Come join the AWS SDK for Go community chat on [gitter](https://gitter.im/aws/aws-sdk-go).
* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html).
@ -40,9 +36,9 @@ Please use these community resources for getting help. We use the GitHub issues
## Opening Issues
If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues]( https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS youre using. Please also include repro case when appropriate.
If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues](https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS youre using. Please also include repro case when appropriate.
The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help]( https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner.
The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help](https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner.
## Reference Documentation
@ -54,80 +50,397 @@ The GitHub issues are intended for bug reports and feature requests. For help an
[`SDK Examples`](https://github.com/aws/aws-sdk-go/tree/master/example) - Included in the SDK's repo are a several hand crafted examples using the SDK features and AWS services.
## Configuring Credentials
## Overview of SDK's Packages
Before using the SDK, ensure that you've configured credentials. The best
way to configure credentials on a development machine is to use the
`~/.aws/credentials` file, which might look like:
The SDK is composed of two main components, SDK core, and service clients.
The SDK core packages are all available under the aws package at the root of
the SDK. Each client for a supported AWS service is available within its own
package under the service folder at the root of the SDK.
```
[default]
aws_access_key_id = AKID1234567890
aws_secret_access_key = MY-SECRET-KEY
```
* aws - SDK core, provides common shared types such as Config, Logger,
and utilities to make working with API parameters easier.
You can learn more about the credentials file from this
[blog post](http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs).
* awserr - Provides the error interface that the SDK will use for all
errors that occur in the SDK's processing. This includes service API
response errors as well. The Error type is made up of a code and message.
Cast the SDK's returned error type to awserr.Error and call the Code
method to compare returned error to specific error codes. See the package's
documentation for additional values that can be extracted such as RequestID.
Alternatively, you can set the following environment variables:
* credentials - Provides the types and built in credentials providers
the SDK will use to retrieve AWS credentials to make API requests with.
Nested under this folder are also additional credentials providers such as
stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles.
```
AWS_ACCESS_KEY_ID=AKID1234567890
AWS_SECRET_ACCESS_KEY=MY-SECRET-KEY
```
* endpoints - Provides the AWS Regions and Endpoints metadata for the SDK.
Use this to lookup AWS service endpoint information such as which services
are in a region, and what regions a service is in. Constants are also provided
for all region identifiers, e.g UsWest2RegionID for "us-west-2".
### 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.
* session - Provides initial default configuration, and load
configuration from external sources such as environment and shared
credentials file.
## Using the Go SDK
* request - Provides the API request sending, and retry logic for the SDK.
This package also includes utilities for defining your own request
retryer, and configuring how the SDK processes the request.
To use a service in the SDK, create a service variable by calling the `New()`
function. Once you have a service client, you can call API operations which each
return response data and a possible error.
* service - Clients for AWS services. All services supported by the SDK are
available under this folder.
To list a set of instance IDs from EC2, you could run:
## How to Use the SDK's AWS Service Clients
The SDK includes the Go types and utilities you can use to make requests to
AWS service APIs. Within the service folder at the root of the SDK you'll find
a package for each AWS service the SDK supports. All service clients follows
a common pattern of creation and usage.
When creating a client for an AWS service you'll first need to have a Session
value constructed. The Session provides shared configuration that can be shared
between your service clients. When service clients are created you can pass
in additional configuration via the aws.Config type to override configuration
provided by in the Session to create service client instances with custom
configuration.
Once the service's client is created you can use it to make API requests the
AWS service. These clients are safe to use concurrently.
## Configuring the SDK
In the AWS SDK for Go, you can configure settings for service clients, such
as the log level and maximum number of retries. Most settings are optional;
however, for each service client, you must specify a region and your credentials.
The SDK uses these values to send requests to the correct AWS region and sign
requests with the correct credentials. You can specify these values as part
of a session or as environment variables.
See the SDK's [configuration guide][config_guide] for more information.
See the [session][session_pkg] package documentation for more information on how to use Session
with the SDK.
See the [Config][config_typ] type in the [aws][aws_pkg] package for more information on configuration
options.
[config_guide]: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html
[session_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/session/
[config_typ]: https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
[aws_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/
### Configuring Credentials
When using the SDK you'll generally need your AWS credentials to authenticate
with AWS services. The SDK supports multiple methods of supporting these
credentials. By default the SDK will source credentials automatically from
its default credential chain. See the session package for more information
on this chain, and how to configure it. The common items in the credential
chain are the following:
* Environment Credentials - Set of environment variables that are useful
when sub processes are created for specific roles.
* Shared Credentials file (~/.aws/credentials) - This file stores your
credentials based on a profile name and is useful for local development.
* EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials
to application running on an EC2 instance. This removes the need to manage
credential files in production.
Credentials can be configured in code as well by setting the Config's Credentials
value to a custom provider or using one of the providers included with the
SDK to bypass the default credential chain and use a custom one. This is
helpful when you want to instruct the SDK to only use a specific set of
credentials or providers.
This example creates a credential provider for assuming an IAM role, "myRoleARN"
and configures the S3 service client to use that role for API requests.
```go
package main
// Initial credentials loaded from SDK's default credential chain. Such as
// the environment, shared credentials (~/.aws/credentials), or EC2 Instance
// Role. These credentials will be used to to make the STS Assume Role API.
sess := session.Must(session.NewSession())
import (
"fmt"
// Create the credentials from AssumeRoleProvider to assume the role
// referenced by the "myRoleARN" ARN.
creds := stscreds.NewCredentials(sess, "myRoleArn")
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
)
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(sess, &aws.Config{Region: aws.String("us-west-2")})
// Call the DescribeInstances Operation
resp, err := svc.DescribeInstances(nil)
if err != nil {
panic(err)
}
// resp has all of the response data, pull out instance IDs:
fmt.Println("> Number of reservation sets: ", len(resp.Reservations))
for idx, res := range resp.Reservations {
fmt.Println(" > Number of instances: ", len(res.Instances))
for _, inst := range resp.Reservations[idx].Instances {
fmt.Println(" - Instance ID: ", *inst.InstanceId)
}
}
}
// Create service client value configured for credentials
// from assumed role.
svc := s3.New(sess, &aws.Config{Credentials: creds})/
```
You can find more information and operations in our
[API documentation](http://docs.aws.amazon.com/sdk-for-go/api/).
See the [credentials][credentials_pkg] package documentation for more information on credential
providers included with the SDK, and how to customize the SDK's usage of
credentials.
The SDK has support for the shared configuration file (~/.aws/config). This
support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1",
or enabling the feature in code when creating a Session via the
Option's SharedConfigState parameter.
```go
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
```
[credentials_pkg]: ttps://docs.aws.amazon.com/sdk-for-go/api/aws/credentials
### Configuring AWS Region
In addition to the credentials you'll need to specify the region the SDK
will use to make AWS API requests to. In the SDK you can specify the region
either with an environment variable, or directly in code when a Session or
service client is created. The last value specified in code wins if the region
is specified multiple ways.
To set the region via the environment variable set the "AWS_REGION" to the
region you want to the SDK to use. Using this method to set the region will
allow you to run your application in multiple regions without needing additional
code in the application to select the region.
AWS_REGION=us-west-2
The endpoints package includes constants for all regions the SDK knows. The
values are all suffixed with RegionID. These values are helpful, because they
reduce the need to type the region string manually.
To set the region on a Session use the aws package's Config struct parameter
Region to the AWS region you want the service clients created from the session to
use. This is helpful when you want to create multiple service clients, and
all of the clients make API requests to the same region.
```go
sess := session.Must(session.NewSession(&aws.Config{
Region: aws.String(endpoints.UsWest2RegionID),
}))
```
See the [endpoints][endpoints_pkg] package for the AWS Regions and Endpoints metadata.
In addition to setting the region when creating a Session you can also set
the region on a per service client bases. This overrides the region of a
Session. This is helpful when you want to create service clients in specific
regions different from the Session's region.
```go
svc := s3.New(sess, &aws.Config{
Region: aws.String(endpoints.UsWest2RegionID),
})
```
See the [Config][config_typ] type in the [aws][aws_pkg] package for more information and additional
options such as setting the Endpoint, and other service client configuration options.
[endpoints_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/
## Making API Requests
Once the client is created you can make an API request to the service.
Each API method takes a input parameter, and returns the service response
and an error. The SDK provides methods for making the API call in multiple ways.
In this list we'll use the S3 ListObjects API as an example for the different
ways of making API requests.
* ListObjects - Base API operation that will make the API request to the service.
* ListObjectsRequest - API methods suffixed with Request will construct the
API request, but not send it. This is also helpful when you want to get a
presigned URL for a request, and share the presigned URL instead of your
application making the request directly.
* ListObjectsPages - Same as the base API operation, but uses a callback to
automatically handle pagination of the API's response.
* ListObjectsWithContext - Same as base API operation, but adds support for
the Context pattern. This is helpful for controlling the canceling of in
flight requests. See the Go standard library context package for more
information. This method also takes request package's Option functional
options as the variadic argument for modifying how the request will be
made, or extracting information from the raw HTTP response.
* ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for
the Context pattern. Similar to ListObjectsWithContext this method also
takes the request package's Option function option types as the variadic
argument.
In addition to the API operations the SDK also includes several higher level
methods that abstract checking for and waiting for an AWS resource to be in
a desired state. In this list we'll use WaitUntilBucketExists to demonstrate
the different forms of waiters.
* WaitUntilBucketExists. - Method to make API request to query an AWS service for
a resource's state. Will return successfully when that state is accomplished.
* WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds
support for the Context pattern. In addition these methods take request
package's WaiterOptions to configure the waiter, and how underlying request
will be made by the SDK.
The API method will document which error codes the service might return for
the operation. These errors will also be available as const strings prefixed
with "ErrCode" in the service client's package. If there are no errors listed
in the API's SDK documentation you'll need to consult the AWS service's API
documentation for the errors that could be returned.
```go
ctx := context.Background()
result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("my-key"),
})
if err != nil {
// Cast err to awserr.Error to handle specific error codes.
aerr, ok := err.(awserr.Error)
if ok && aerr.Code() == s3.ErrCodeNoSuchKey {
// Specific error code handling
}
return err
}
// Make sure to close the body when done with it for S3 GetObject APIs or
// will leak connections.
defer result.Body.Close()
fmt.Println("Object Size:", aws.StringValue(result.ContentLength))
```
### API Request Pagination and Resource Waiters
Pagination helper methods are suffixed with "Pages", and provide the
functionality needed to round trip API page requests. Pagination methods
take a callback function that will be called for each page of the API's response.
```go
objects := []string{}
err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{
Bucket: aws.String(myBucket),
}, func(p *s3.ListObjectsOutput, lastPage bool) bool {
for _, o := range p.Contents {
objects = append(objects, aws.StringValue(o.Key))
}
return true // continue paging
})
if err != nil {
panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err))
}
fmt.Println("Objects in bucket:", objects)
```
Waiter helper methods provide the functionality to wait for an AWS resource
state. These methods abstract the logic needed to to check the state of an
AWS resource, and wait until that resource is in a desired state. The waiter
will block until the resource is in the state that is desired, an error occurs,
or the waiter times out. If a resource times out the error code returned will
be request.WaiterResourceNotReadyErrorCode.
```go
err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{
Bucket: aws.String(myBucket),
})
if err != nil {
aerr, ok := err.(awserr.Error)
if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode {
fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist")
}
panic(fmt.Errorf("failed to wait for bucket to exist, %v", err))
}
fmt.Println("Bucket", myBucket, "exists")
```
## Complete SDK Example
This example shows a complete working Go file which will upload a file to S3
and use the Context pattern to implement timeout logic that will cancel the
request if it takes too long. This example highlights how to use sessions,
create a service client, make a request, handle the error, and process the
response.
```go
package main
import (
"context"
"flag"
"fmt"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
// Uploads a file to S3 given a bucket and object key. Also takes a duration
// value to terminate the update if it doesn't complete within that time.
//
// The AWS Region needs to be provided in the AWS shared config or on the
// environment variable as `AWS_REGION`. Credentials also must be provided
// Will default to shared config file, but can load from environment if provided.
//
// Usage:
// # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
// go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
func main() {
var bucket, key string
var timeout time.Duration
flag.StringVar(&bucket, "b", "", "Bucket name.")
flag.StringVar(&key, "k", "", "Object key name.")
flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
flag.Parse()
// All clients require a Session. The Session provides the client with
// shared configuration such as region, endpoint, and credentials. A
// Session should be shared where possible to take advantage of
// configuration and credential caching. See the session package for
// more information.
sess := session.Must(session.NewSession())
// Create a new instance of the service's client with a Session.
// Optional aws.Config values can also be provided as variadic arguments
// to the New function. This option allows you to provide service
// specific configuration.
svc := s3.New(sess)
// Create a context with a timeout that will abort the upload if it takes
// more than the passed in timeout.
ctx := context.Background()
var cancelFn func()
if timeout > 0 {
ctx, cancelFn = context.WithTimeout(ctx, timeout)
}
// Ensure the context is canceled to prevent leaking.
// See context package for more information, https://golang.org/pkg/context/
defer cancelFn()
// Uploads the object to S3. The Context will interrupt the request if the
// timeout expires.
_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: os.Stdin,
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
// If the SDK can determine the request or retry delay was canceled
// by a context the CanceledErrorCode error code will be returned.
fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
} else {
fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
}
os.Exit(1)
}
fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
}
```
## License

View File

@ -5,6 +5,7 @@ import (
"net/http/httputil"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/request"
)
@ -46,7 +47,7 @@ func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, op
svc := &Client{
Config: cfg,
ClientInfo: info,
Handlers: handlers,
Handlers: handlers.Copy(),
}
switch retryer, ok := cfg.Retryer.(request.Retryer); {
@ -86,8 +87,8 @@ func (c *Client) AddDebugHandlers() {
return
}
c.Handlers.Send.PushFront(logRequest)
c.Handlers.Send.PushBack(logResponse)
c.Handlers.Send.PushFrontNamed(request.NamedHandler{Name: "awssdk.client.LogRequest", Fn: logRequest})
c.Handlers.Send.PushBackNamed(request.NamedHandler{Name: "awssdk.client.LogResponse", Fn: logResponse})
}
const logReqMsg = `DEBUG: Request %s/%s Details:
@ -105,6 +106,7 @@ func logRequest(r *request.Request) {
dumpedBody, err := httputil.DumpRequestOut(r.HTTPRequest, logBody)
if err != nil {
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
r.Error = awserr.New(request.ErrCodeRead, "an error occurred during request body reading", err)
return
}
@ -135,6 +137,7 @@ func logResponse(r *request.Request) {
dumpedBody, err := httputil.DumpResponse(r.HTTPResponse, logBody)
if err != nil {
r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
r.Error = awserr.New(request.ErrCodeRead, "an error occurred during response body reading", err)
return
}

View File

@ -0,0 +1,78 @@
package client
import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/request"
)
func pushBackTestHandler(name string, list *request.HandlerList) *bool {
called := false
(*list).PushBackNamed(request.NamedHandler{
Name: name,
Fn: func(r *request.Request) {
called = true
},
})
return &called
}
func pushFrontTestHandler(name string, list *request.HandlerList) *bool {
called := false
(*list).PushFrontNamed(request.NamedHandler{
Name: name,
Fn: func(r *request.Request) {
called = true
},
})
return &called
}
func TestNewClient_CopyHandlers(t *testing.T) {
handlers := request.Handlers{}
firstCalled := pushBackTestHandler("first", &handlers.Send)
secondCalled := pushBackTestHandler("second", &handlers.Send)
var clientHandlerCalled *bool
c := New(aws.Config{}, metadata.ClientInfo{}, handlers,
func(c *Client) {
clientHandlerCalled = pushFrontTestHandler("client handler", &c.Handlers.Send)
},
)
if e, a := 2, handlers.Send.Len(); e != a {
t.Errorf("expect %d original handlers, got %d", e, a)
}
if e, a := 3, c.Handlers.Send.Len(); e != a {
t.Errorf("expect %d client handlers, got %d", e, a)
}
handlers.Send.Run(nil)
if !*firstCalled {
t.Errorf("expect first handler to of been called")
}
*firstCalled = false
if !*secondCalled {
t.Errorf("expect second handler to of been called")
}
*secondCalled = false
if *clientHandlerCalled {
t.Errorf("expect client handler to not of been called, but was")
}
c.Handlers.Send.Run(nil)
if !*firstCalled {
t.Errorf("expect client's first handler to of been called")
}
if !*secondCalled {
t.Errorf("expect client's second handler to of been called")
}
if !*clientHandlerCalled {
t.Errorf("expect client's client handler to of been called")
}
}

View File

@ -54,6 +54,12 @@ func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
// ShouldRetry returns true if the request should be retried.
func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
// If one of the other handlers already set the retry state
// we don't want to override it based on the service's state
if r.Retryable != nil {
return *r.Retryable
}
if r.HTTPResponse.StatusCode >= 500 {
return true
}

View File

@ -53,6 +53,13 @@ type Config struct {
// to use based on region.
EndpointResolver endpoints.Resolver
// EnforceShouldRetryCheck is used in the AfterRetryHandler to always call
// ShouldRetry regardless of whether or not if request.Retryable is set.
// This will utilize ShouldRetry method of custom retryers. If EnforceShouldRetryCheck
// is not set, then ShouldRetry will only be called if request.Retryable is nil.
// Proper handling of the request.Retryable field is important when setting this field.
EnforceShouldRetryCheck *bool
// The region to send requests to. This parameter is required and must
// be configured globally or on a per-client basis unless otherwise
// noted. A full list of regions is found in the "Regions and Endpoints"
@ -187,6 +194,10 @@ type Config struct {
// request delays. This value should only be used for testing. To adjust
// the delay of a request see the aws/client.DefaultRetryer and
// aws/request.Retryer.
//
// SleepDelay will prevent any Context from being used for canceling retry
// delay of an API operation. It is recommended to not use SleepDelay at all
// and specify a Retryer instead.
SleepDelay func(time.Duration)
// DisableRestProtocolURICleaning will not clean the URL path when making rest protocol requests.
@ -439,6 +450,10 @@ func mergeInConfig(dst *Config, other *Config) {
if other.DisableRestProtocolURICleaning != nil {
dst.DisableRestProtocolURICleaning = other.DisableRestProtocolURICleaning
}
if other.EnforceShouldRetryCheck != nil {
dst.EnforceShouldRetryCheck = other.EnforceShouldRetryCheck
}
}
// Copy will return a shallow copy of the Config object. If any additional

71
vendor/github.com/aws/aws-sdk-go/aws/context.go generated vendored Normal file
View File

@ -0,0 +1,71 @@
package aws
import (
"time"
)
// Context is an copy of the Go v1.7 stdlib's context.Context interface.
// It is represented as a SDK interface to enable you to use the "WithContext"
// API methods with Go v1.6 and a Context type such as golang.org/x/net/context.
//
// See https://golang.org/pkg/context on how to use contexts.
type Context interface {
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
Deadline() (deadline time.Time, ok bool)
// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
Done() <-chan struct{}
// Err returns a non-nil error value after Done is closed. Err returns
// Canceled if the context was canceled or DeadlineExceeded if the
// context's deadline passed. No other values for Err are defined.
// After Done is closed, successive calls to Err return the same value.
Err() error
// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
//
// Use context values only for request-scoped data that transits
// processes and API boundaries, not for passing optional parameters to
// functions.
Value(key interface{}) interface{}
}
// BackgroundContext returns a context that will never be canceled, has no
// values, and no deadline. This context is used by the SDK to provide
// backwards compatibility with non-context API operations and functionality.
//
// Go 1.6 and before:
// This context function is equivalent to context.Background in the Go stdlib.
//
// Go 1.7 and later:
// The context returned will be the value returned by context.Background()
//
// See https://golang.org/pkg/context for more information on Contexts.
func BackgroundContext() Context {
return backgroundCtx
}
// SleepWithContext will wait for the timer duration to expire, or the context
// is canceled. Which ever happens first. If the context is canceled the Context's
// error will be returned.
//
// Expects Context to always return a non-nil error if the Done channel is closed.
func SleepWithContext(ctx Context, dur time.Duration) error {
t := time.NewTimer(dur)
defer t.Stop()
select {
case <-t.C:
break
case <-ctx.Done():
return ctx.Err()
}
return nil
}

41
vendor/github.com/aws/aws-sdk-go/aws/context_1_6.go generated vendored Normal file
View File

@ -0,0 +1,41 @@
// +build !go1.7
package aws
import "time"
// An emptyCtx is a copy of the the Go 1.7 context.emptyCtx type. This
// is copied to provide a 1.6 and 1.5 safe version of context that is compatible
// with Go 1.7's Context.
//
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (*emptyCtx) Done() <-chan struct{} {
return nil
}
func (*emptyCtx) Err() error {
return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
return nil
}
func (e *emptyCtx) String() string {
switch e {
case backgroundCtx:
return "aws.BackgroundContext"
}
return "unknown empty Context"
}
var (
backgroundCtx = new(emptyCtx)
)

9
vendor/github.com/aws/aws-sdk-go/aws/context_1_7.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
// +build go1.7
package aws
import "context"
var (
backgroundCtx = context.Background()
)

37
vendor/github.com/aws/aws-sdk-go/aws/context_test.go generated vendored Normal file
View File

@ -0,0 +1,37 @@
package aws_test
import (
"fmt"
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/awstesting"
)
func TestSleepWithContext(t *testing.T) {
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
err := aws.SleepWithContext(ctx, 1*time.Millisecond)
if err != nil {
t.Errorf("expect context to not be canceled, got %v", err)
}
}
func TestSleepWithContext_Canceled(t *testing.T) {
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
expectErr := fmt.Errorf("context canceled")
ctx.Error = expectErr
close(ctx.DoneCh)
err := aws.SleepWithContext(ctx, 1*time.Millisecond)
if err == nil {
t.Fatalf("expect error, did not get one")
}
if e, a := expectErr, err; e != a {
t.Errorf("expect %v error, got %v", e, a)
}
}

View File

@ -27,7 +27,7 @@ type lener interface {
// or will use the HTTPRequest.Header's "Content-Length" if defined. If unable
// to determine request body length and no "Content-Length" was specified it will panic.
//
// The Content-Length will only be aded to the request if the length of the body
// The Content-Length will only be added to the request if the length of the body
// is greater than 0. If the body is empty or the current `Content-Length`
// header is <= 0, the header will also be stripped.
var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLengthHandler", Fn: func(r *request.Request) {
@ -71,8 +71,8 @@ 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 significant delays
// occur whne retrying requests that would cause the signature to expire.
// is built and signed significantly before it is sent. Or significant delays
// occur when retrying requests that would cause the signature to expire.
var ValidateReqSigHandler = request.NamedHandler{
Name: "core.ValidateReqSigHandler",
Fn: func(r *request.Request) {
@ -98,10 +98,36 @@ var ValidateReqSigHandler = request.NamedHandler{
}
// 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 SendHandler = request.NamedHandler{
Name: "core.SendHandler",
Fn: func(r *request.Request) {
sender := sendFollowRedirects
if r.DisableFollowRedirects {
sender = sendWithoutFollowRedirects
}
var err error
r.HTTPResponse, err = r.Config.HTTPClient.Do(r.HTTPRequest)
r.HTTPResponse, err = sender(r)
if err != nil {
handleSendError(r, err)
}
},
}
func sendFollowRedirects(r *request.Request) (*http.Response, error) {
return r.Config.HTTPClient.Do(r.HTTPRequest)
}
func sendWithoutFollowRedirects(r *request.Request) (*http.Response, error) {
transport := r.Config.HTTPClient.Transport
if transport == nil {
transport = http.DefaultTransport
}
return transport.RoundTrip(r.HTTPRequest)
}
func handleSendError(r *request.Request, err error) {
// Prevent leaking if an HTTPResponse was returned. Clean up
// the body.
if r.HTTPResponse != nil {
@ -109,7 +135,7 @@ var SendHandler = request.NamedHandler{Name: "core.SendHandler", Fn: func(r *req
}
// Capture the case where url.Error is returned for error processing
// response. e.g. 301 without location header comes back as string
// error and r.HTTPResponse is nil. Other url redirect errors will
// error and r.HTTPResponse is nil. Other URL redirect errors will
// comeback in a similar method.
if e, ok := err.(*url.Error); ok && e.Err != nil {
if s := reStatusCode.FindStringSubmatch(e.Err.Error()); s != nil {
@ -134,8 +160,17 @@ var SendHandler = request.NamedHandler{Name: "core.SendHandler", Fn: func(r *req
// Catch all other request errors.
r.Error = awserr.New("RequestError", "send request failed", err)
r.Retryable = aws.Bool(true) // network errors are retryable
// Override the error with a context canceled error, if that was canceled.
ctx := r.Context()
select {
case <-ctx.Done():
r.Error = awserr.New(request.CanceledErrorCode,
"request context canceled", ctx.Err())
r.Retryable = aws.Bool(false)
default:
}
}}
}
// ValidateResponseHandler is a request handler to validate service response.
var ValidateResponseHandler = request.NamedHandler{Name: "core.ValidateResponseHandler", Fn: func(r *request.Request) {
@ -150,13 +185,22 @@ var ValidateResponseHandler = request.NamedHandler{Name: "core.ValidateResponseH
var AfterRetryHandler = request.NamedHandler{Name: "core.AfterRetryHandler", Fn: func(r *request.Request) {
// If one of the other handlers already set the retry state
// we don't want to override it based on the service's state
if r.Retryable == nil {
if r.Retryable == nil || aws.BoolValue(r.Config.EnforceShouldRetryCheck) {
r.Retryable = aws.Bool(r.ShouldRetry(r))
}
if r.WillRetry() {
r.RetryDelay = r.RetryRules(r)
r.Config.SleepDelay(r.RetryDelay)
if sleepFn := r.Config.SleepDelay; sleepFn != nil {
// Support SleepDelay for backwards compatibility and testing
sleepFn(r.RetryDelay)
} else if err := aws.SleepWithContext(r.Context(), r.RetryDelay); err != nil {
r.Error = awserr.New(request.CanceledErrorCode,
"request context canceled", err)
r.Retryable = aws.Bool(false)
return
}
// when the expired token exception occurs the credentials
// need to be expired locally so that the next request to

View File

@ -96,6 +96,94 @@ func TestAfterRetryRefreshCreds(t *testing.T) {
assert.True(t, credProvider.retrieveCalled)
}
func TestAfterRetryWithContextCanceled(t *testing.T) {
c := awstesting.NewClient()
req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)}
req.SetContext(ctx)
req.Error = fmt.Errorf("some error")
req.Retryable = aws.Bool(true)
req.HTTPResponse = &http.Response{
StatusCode: 500,
}
close(ctx.DoneCh)
ctx.Error = fmt.Errorf("context canceled")
corehandlers.AfterRetryHandler.Fn(req)
if req.Error == nil {
t.Fatalf("expect error but didn't receive one")
}
aerr := req.Error.(awserr.Error)
if e, a := request.CanceledErrorCode, aerr.Code(); e != a {
t.Errorf("expect %q, error code got %q", e, a)
}
}
func TestAfterRetryWithContext(t *testing.T) {
c := awstesting.NewClient()
req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)}
req.SetContext(ctx)
req.Error = fmt.Errorf("some error")
req.Retryable = aws.Bool(true)
req.HTTPResponse = &http.Response{
StatusCode: 500,
}
corehandlers.AfterRetryHandler.Fn(req)
if req.Error != nil {
t.Fatalf("expect no error, got %v", req.Error)
}
if e, a := 1, req.RetryCount; e != a {
t.Errorf("expect retry count to be %d, got %d", e, a)
}
}
func TestSendWithContextCanceled(t *testing.T) {
c := awstesting.NewClient(&aws.Config{
SleepDelay: func(dur time.Duration) {
t.Errorf("SleepDelay should not be called")
},
})
req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{}, 0)}
req.SetContext(ctx)
req.Error = fmt.Errorf("some error")
req.Retryable = aws.Bool(true)
req.HTTPResponse = &http.Response{
StatusCode: 500,
}
close(ctx.DoneCh)
ctx.Error = fmt.Errorf("context canceled")
corehandlers.SendHandler.Fn(req)
if req.Error == nil {
t.Fatalf("expect error but didn't receive one")
}
aerr := req.Error.(awserr.Error)
if e, a := request.CanceledErrorCode, aerr.Code(); e != a {
t.Errorf("expect %q, error code got %q", e, a)
}
}
type testSendHandlerTransport struct{}
func (t *testSendHandlerTransport) RoundTrip(r *http.Request) (*http.Response, error) {
@ -118,6 +206,39 @@ func TestSendHandlerError(t *testing.T) {
assert.NotNil(t, r.HTTPResponse)
}
func TestSendWithoutFollowRedirects(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/original":
w.Header().Set("Location", "/redirected")
w.WriteHeader(301)
case "/redirected":
t.Fatalf("expect not to redirect, but was")
}
}))
svc := awstesting.NewClient(&aws.Config{
DisableSSL: aws.Bool(true),
Endpoint: aws.String(server.URL),
})
svc.Handlers.Clear()
svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
r := svc.NewRequest(&request.Operation{
Name: "Operation",
HTTPPath: "/original",
}, nil, nil)
r.DisableFollowRedirects = true
err := r.Send()
if err != nil {
t.Errorf("expect no error, got %v", err)
}
if e, a := 301, r.HTTPResponse.StatusCode; e != a {
t.Errorf("expect %d status code, got %d", e, a)
}
}
func TestValidateReqSigHandler(t *testing.T) {
cases := []struct {
Req *request.Request

View File

@ -39,16 +39,18 @@ var (
// does not return any credentials ChainProvider will return the error
// ErrNoValidProvidersFoundInChain
//
// creds := NewChainCredentials(
// []Provider{
// &EnvProvider{},
// &EC2RoleProvider{
// creds := credentials.NewChainCredentials(
// []credentials.Provider{
// &credentials.EnvProvider{},
// &ec2rolecreds.EC2RoleProvider{
// Client: ec2metadata.New(sess),
// },
// })
//
// // Usage of ChainCredentials with aws.Config
// svc := ec2.New(&aws.Config{Credentials: creds})
// svc := ec2.New(session.Must(session.NewSession(&aws.Config{
// Credentials: creds,
// })))
//
type ChainProvider struct {
Providers []Provider

View File

@ -14,7 +14,7 @@
//
// Example of using the environment variable credentials.
//
// creds := NewEnvCredentials()
// creds := credentials.NewEnvCredentials()
//
// // Retrieve the credentials value
// credValue, err := creds.Get()
@ -26,7 +26,7 @@
// This may be helpful to proactively expire credentials and refresh them sooner
// than they would naturally expire on their own.
//
// creds := NewCredentials(&EC2RoleProvider{})
// creds := credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{})
// creds.Expire()
// credsValue, err := creds.Get()
// // New credentials will be retrieved instead of from cache.
@ -43,7 +43,7 @@
// func (m *MyProvider) Retrieve() (Value, error) {...}
// func (m *MyProvider) IsExpired() bool {...}
//
// creds := NewCredentials(&MyProvider{})
// creds := credentials.NewCredentials(&MyProvider{})
// credValue, err := creds.Get()
//
package credentials
@ -60,7 +60,9 @@ import (
// when making service API calls. For example, when accessing public
// s3 buckets.
//
// svc := s3.New(&aws.Config{Credentials: AnonymousCredentials})
// svc := s3.New(session.Must(session.NewSession(&aws.Config{
// Credentials: credentials.AnonymousCredentials,
// })))
// // Access public S3 buckets.
//
// @readonly
@ -88,7 +90,7 @@ type Value struct {
// The Provider should not need to implement its own mutexes, because
// that will be managed by Credentials.
type Provider interface {
// Refresh returns nil if it successfully retrieved the value.
// Retrieve returns nil if it successfully retrieved the value.
// Error is returned if the value were not obtainable, or empty.
Retrieve() (Value, error)
@ -97,6 +99,27 @@ type Provider interface {
IsExpired() bool
}
// An ErrorProvider is a stub credentials provider that always returns an error
// this is used by the SDK when construction a known provider is not possible
// due to an error.
type ErrorProvider struct {
// The error to be returned from Retrieve
Err error
// The provider name to set on the Retrieved returned Value
ProviderName string
}
// Retrieve will always return the error that the ErrorProvider was created with.
func (p ErrorProvider) Retrieve() (Value, error) {
return Value{ProviderName: p.ProviderName}, p.Err
}
// IsExpired will always return not expired.
func (p ErrorProvider) IsExpired() bool {
return false
}
// A Expiry provides shared expiration logic to be used by credentials
// providers to implement expiry functionality.
//

View File

@ -29,6 +29,7 @@ var (
// Environment variables used:
//
// * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY
//
// * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY
type EnvProvider struct {
retrieved bool

View File

@ -10,10 +10,12 @@ package defaults
import (
"fmt"
"net/http"
"net/url"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/corehandlers"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
@ -56,7 +58,6 @@ func Config() *aws.Config {
WithMaxRetries(aws.UseServiceDefaultRetries).
WithLogger(aws.NewDefaultLogger()).
WithLogLevel(aws.LogOff).
WithSleepDelay(time.Sleep).
WithEndpointResolver(endpoints.DefaultResolver())
}
@ -97,23 +98,51 @@ func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credenti
})
}
// RemoteCredProvider returns a credenitials provider for the default remote
const (
httpProviderEnvVar = "AWS_CONTAINER_CREDENTIALS_FULL_URI"
ecsCredsProviderEnvVar = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
)
// RemoteCredProvider returns a credentials 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 u := os.Getenv(httpProviderEnvVar); len(u) > 0 {
return localHTTPCredProvider(cfg, handlers, u)
}
if len(ecsCredURI) > 0 {
return ecsCredProvider(cfg, handlers, ecsCredURI)
if uri := os.Getenv(ecsCredsProviderEnvVar); len(uri) > 0 {
u := fmt.Sprintf("http://169.254.170.2%s", uri)
return httpCredProvider(cfg, handlers, u)
}
return ec2RoleProvider(cfg, handlers)
}
func ecsCredProvider(cfg aws.Config, handlers request.Handlers, uri string) credentials.Provider {
const host = `169.254.170.2`
func localHTTPCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider {
var errMsg string
return endpointcreds.NewProviderClient(cfg, handlers,
fmt.Sprintf("http://%s%s", host, uri),
parsed, err := url.Parse(u)
if err != nil {
errMsg = fmt.Sprintf("invalid URL, %v", err)
} else if host := aws.URLHostname(parsed); !(host == "localhost" || host == "127.0.0.1") {
errMsg = fmt.Sprintf("invalid host address, %q, only localhost and 127.0.0.1 are valid.", host)
}
if len(errMsg) > 0 {
if cfg.Logger != nil {
cfg.Logger.Log("Ignoring, HTTP credential provider", errMsg, err)
}
return credentials.ErrorProvider{
Err: awserr.New("CredentialsEndpointError", errMsg, err),
ProviderName: endpointcreds.ProviderName,
}
}
return httpCredProvider(cfg, handlers, u)
}
func httpCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider {
return endpointcreds.NewProviderClient(cfg, handlers, u,
func(p *endpointcreds.Provider) {
p.ExpiryWindow = 5 * time.Minute
},

View File

@ -6,39 +6,83 @@ import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/stretchr/testify/assert"
)
func TestHTTPCredProvider(t *testing.T) {
cases := []struct {
Host string
Fail bool
}{
{"localhost", false}, {"127.0.0.1", false},
{"www.example.com", true}, {"169.254.170.2", true},
}
defer os.Clearenv()
for i, c := range cases {
u := fmt.Sprintf("http://%s/abc/123", c.Host)
os.Setenv(httpProviderEnvVar, u)
provider := RemoteCredProvider(aws.Config{}, request.Handlers{})
if provider == nil {
t.Fatalf("%d, expect provider not to be nil, but was", i)
}
if c.Fail {
creds, err := provider.Retrieve()
if err == nil {
t.Fatalf("%d, expect error but got none", i)
} else {
aerr := err.(awserr.Error)
if e, a := "CredentialsEndpointError", aerr.Code(); e != a {
t.Errorf("%d, expect %s error code, got %s", i, e, a)
}
}
if e, a := endpointcreds.ProviderName, creds.ProviderName; e != a {
t.Errorf("%d, expect %s provider name got %s", i, e, a)
}
} else {
httpProvider := provider.(*endpointcreds.Provider)
if e, a := u, httpProvider.Client.Endpoint; e != a {
t.Errorf("%d, expect %q endpoint, got %q", i, e, a)
}
}
}
}
func TestECSCredProvider(t *testing.T) {
defer os.Clearenv()
os.Setenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/abc/123")
os.Setenv(ecsCredsProviderEnvVar, "/abc/123")
provider := RemoteCredProvider(aws.Config{}, request.Handlers{})
if provider == nil {
t.Fatalf("expect provider not to be nil, but was")
}
assert.NotNil(t, provider)
ecsProvider, ok := provider.(*endpointcreds.Provider)
assert.NotNil(t, ecsProvider)
assert.True(t, ok)
assert.Equal(t, fmt.Sprintf("http://169.254.170.2/abc/123"),
ecsProvider.Client.Endpoint)
httpProvider := provider.(*endpointcreds.Provider)
if httpProvider == nil {
t.Fatalf("expect provider not to be nil, but was")
}
if e, a := "http://169.254.170.2/abc/123", httpProvider.Client.Endpoint; e != a {
t.Errorf("expect %q endpoint, got %q", e, a)
}
}
func TestDefaultEC2RoleProvider(t *testing.T) {
provider := RemoteCredProvider(aws.Config{}, request.Handlers{})
if provider == nil {
t.Fatalf("expect provider not to be nil, but was")
}
assert.NotNil(t, provider)
ec2Provider, ok := provider.(*ec2rolecreds.EC2RoleProvider)
assert.NotNil(t, ec2Provider)
assert.True(t, ok)
fmt.Println(ec2Provider.Client.Endpoint)
assert.Equal(t, fmt.Sprintf("http://169.254.169.254/latest"),
ec2Provider.Client.Endpoint)
ec2Provider := provider.(*ec2rolecreds.EC2RoleProvider)
if ec2Provider == nil {
t.Fatalf("expect provider not to be nil, but was")
}
if e, a := "http://169.254.169.254/latest", ec2Provider.Client.Endpoint; e != a {
t.Errorf("expect %q endpoint, got %q", e, a)
}
}

View File

@ -1,4 +1,4 @@
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
// Code generated by aws/endpoints/v3model_codegen.go. DO NOT EDIT.
package endpoints
@ -60,6 +60,7 @@ const (
CodecommitServiceID = "codecommit" // Codecommit.
CodedeployServiceID = "codedeploy" // Codedeploy.
CodepipelineServiceID = "codepipeline" // Codepipeline.
CodestarServiceID = "codestar" // Codestar.
CognitoIdentityServiceID = "cognito-identity" // CognitoIdentity.
CognitoIdpServiceID = "cognito-idp" // CognitoIdp.
CognitoSyncServiceID = "cognito-sync" // CognitoSync.
@ -83,6 +84,7 @@ const (
ElasticmapreduceServiceID = "elasticmapreduce" // Elasticmapreduce.
ElastictranscoderServiceID = "elastictranscoder" // Elastictranscoder.
EmailServiceID = "email" // Email.
EntitlementMarketplaceServiceID = "entitlement.marketplace" // EntitlementMarketplace.
EsServiceID = "es" // Es.
EventsServiceID = "events" // Events.
FirehoseServiceID = "firehose" // Firehose.
@ -103,6 +105,7 @@ const (
MarketplacecommerceanalyticsServiceID = "marketplacecommerceanalytics" // Marketplacecommerceanalytics.
MeteringMarketplaceServiceID = "metering.marketplace" // MeteringMarketplace.
MobileanalyticsServiceID = "mobileanalytics" // Mobileanalytics.
ModelsLexServiceID = "models.lex" // ModelsLex.
MonitoringServiceID = "monitoring" // Monitoring.
MturkRequesterServiceID = "mturk-requester" // MturkRequester.
OpsworksServiceID = "opsworks" // Opsworks.
@ -131,6 +134,7 @@ const (
StsServiceID = "sts" // Sts.
SupportServiceID = "support" // Support.
SwfServiceID = "swf" // Swf.
TaggingServiceID = "tagging" // Tagging.
WafServiceID = "waf" // Waf.
WafRegionalServiceID = "waf-regional" // WafRegional.
WorkdocsServiceID = "workdocs" // Workdocs.
@ -141,17 +145,20 @@ const (
// DefaultResolver returns an Endpoint resolver that will be able
// to resolve endpoints for: AWS Standard, AWS China, and AWS GovCloud (US).
//
// Casting the return value of this func to a EnumPartitions will
// allow you to get a list of the partitions in the order the endpoints
// will be resolved in.
// Use DefaultPartitions() to get the list of the default partitions.
func DefaultResolver() Resolver {
return defaultPartitions
}
// DefaultPartitions returns a list of the partitions the SDK is bundled
// with. The available partitions are: AWS Standard, AWS China, and AWS GovCloud (US).
//
// resolver := endpoints.DefaultResolver()
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
// partitions := endpoints.DefaultPartitions
// for _, p := range partitions {
// // ... inspect partitions
// }
func DefaultResolver() Resolver {
return defaultPartitions
func DefaultPartitions() []Partition {
return defaultPartitions.Partitions()
}
var defaultPartitions = partitions{
@ -249,6 +256,7 @@ var awsPartition = partition{
Endpoints: endpoints{
"ap-northeast-1": endpoint{},
"ap-northeast-2": endpoint{},
"ap-south-1": endpoint{},
"ap-southeast-1": endpoint{},
"ap-southeast-2": endpoint{},
"eu-central-1": endpoint{},
@ -345,6 +353,7 @@ var awsPartition = partition{
"ap-southeast-1": endpoint{},
"ap-southeast-2": endpoint{},
"eu-west-1": endpoint{},
"eu-west-2": endpoint{},
"us-east-1": endpoint{},
"us-east-2": endpoint{},
"us-west-2": endpoint{},
@ -435,6 +444,10 @@ var awsPartition = partition{
"codebuild": service{
Endpoints: endpoints{
"ap-northeast-1": endpoint{},
"ap-southeast-1": endpoint{},
"ap-southeast-2": endpoint{},
"eu-central-1": endpoint{},
"eu-west-1": endpoint{},
"us-east-1": endpoint{},
"us-east-2": endpoint{},
@ -483,11 +496,21 @@ var awsPartition = partition{
"us-west-2": endpoint{},
},
},
"codestar": service{
Endpoints: endpoints{
"eu-west-1": endpoint{},
"us-east-1": endpoint{},
"us-east-2": endpoint{},
"us-west-2": endpoint{},
},
},
"cognito-identity": service{
Endpoints: endpoints{
"ap-northeast-1": endpoint{},
"ap-northeast-2": endpoint{},
"ap-south-1": endpoint{},
"ap-southeast-2": endpoint{},
"eu-central-1": endpoint{},
"eu-west-1": endpoint{},
@ -502,6 +525,7 @@ var awsPartition = partition{
Endpoints: endpoints{
"ap-northeast-1": endpoint{},
"ap-northeast-2": endpoint{},
"ap-south-1": endpoint{},
"ap-southeast-2": endpoint{},
"eu-central-1": endpoint{},
"eu-west-1": endpoint{},
@ -516,6 +540,7 @@ var awsPartition = partition{
Endpoints: endpoints{
"ap-northeast-1": endpoint{},
"ap-northeast-2": endpoint{},
"ap-south-1": endpoint{},
"ap-southeast-2": endpoint{},
"eu-central-1": endpoint{},
"eu-west-1": endpoint{},
@ -755,6 +780,7 @@ var awsPartition = partition{
"elasticfilesystem": service{
Endpoints: endpoints{
"ap-southeast-2": endpoint{},
"eu-west-1": endpoint{},
"us-east-1": endpoint{},
"us-east-2": endpoint{},
@ -829,6 +855,16 @@ var awsPartition = partition{
"us-west-2": endpoint{},
},
},
"entitlement.marketplace": service{
Defaults: endpoint{
CredentialScope: credentialScope{
Service: "aws-marketplace",
},
},
Endpoints: endpoints{
"us-east-1": endpoint{},
},
},
"es": service{
Endpoints: endpoints{
@ -837,8 +873,10 @@ var awsPartition = partition{
"ap-south-1": endpoint{},
"ap-southeast-1": endpoint{},
"ap-southeast-2": endpoint{},
"ca-central-1": endpoint{},
"eu-central-1": endpoint{},
"eu-west-1": endpoint{},
"eu-west-2": endpoint{},
"sa-east-1": endpoint{},
"us-east-1": endpoint{},
"us-east-2": endpoint{},
@ -1022,6 +1060,7 @@ var awsPartition = partition{
Endpoints: endpoints{
"ap-northeast-1": endpoint{},
"ap-northeast-2": endpoint{},
"ap-south-1": endpoint{},
"ap-southeast-1": endpoint{},
"ap-southeast-2": endpoint{},
"eu-central-1": endpoint{},
@ -1100,6 +1139,16 @@ var awsPartition = partition{
"us-east-1": endpoint{},
},
},
"models.lex": service{
Defaults: endpoint{
CredentialScope: credentialScope{
Service: "lex",
},
},
Endpoints: endpoints{
"us-east-1": endpoint{},
},
},
"monitoring": service{
Defaults: endpoint{
Protocols: []string{"http", "https"},
@ -1380,7 +1429,6 @@ var awsPartition = partition{
Endpoints: endpoints{
"ap-south-1": endpoint{},
"ap-southeast-2": endpoint{},
"ca-central-1": endpoint{},
"eu-central-1": endpoint{},
"eu-west-1": endpoint{},
"eu-west-2": endpoint{},
@ -1467,6 +1515,7 @@ var awsPartition = partition{
Endpoints: endpoints{
"ap-northeast-1": endpoint{},
"ap-northeast-2": endpoint{},
"ap-south-1": endpoint{},
"ap-southeast-1": endpoint{},
"ap-southeast-2": endpoint{},
"ca-central-1": endpoint{},
@ -1567,6 +1616,25 @@ var awsPartition = partition{
"us-west-2": endpoint{},
},
},
"tagging": service{
Endpoints: endpoints{
"ap-northeast-1": endpoint{},
"ap-northeast-2": endpoint{},
"ap-south-1": endpoint{},
"ap-southeast-1": endpoint{},
"ap-southeast-2": endpoint{},
"ca-central-1": endpoint{},
"eu-central-1": endpoint{},
"eu-west-1": endpoint{},
"eu-west-2": endpoint{},
"sa-east-1": endpoint{},
"us-east-1": endpoint{},
"us-east-2": endpoint{},
"us-west-1": endpoint{},
"us-west-2": endpoint{},
},
},
"waf": service{
PartitionEndpoint: "aws-global",
IsRegionalized: boxedFalse,
@ -1678,6 +1746,12 @@ var awscnPartition = partition{
"cn-north-1": endpoint{},
},
},
"codedeploy": service{
Endpoints: endpoints{
"cn-north-1": endpoint{},
},
},
"config": service{
Endpoints: endpoints{
@ -1855,6 +1929,12 @@ var awscnPartition = partition{
},
"swf": service{
Endpoints: endpoints{
"cn-north-1": endpoint{},
},
},
"tagging": service{
Endpoints: endpoints{
"cn-north-1": endpoint{},
},

View File

@ -124,6 +124,49 @@ type EnumPartitions interface {
Partitions() []Partition
}
// RegionsForService returns a map of regions for the partition and service.
// If either the partition or service does not exist false will be returned
// as the second parameter.
//
// This example shows how to get the regions for DynamoDB in the AWS partition.
// rs, exists := endpoints.RegionsForService(endpoints.DefaultPartitions(), endpoints.AwsPartitionID, endpoints.DynamodbServiceID)
//
// This is equivalent to using the partition directly.
// rs := endpoints.AwsPartition().Services()[endpoints.DynamodbServiceID].Regions()
func RegionsForService(ps []Partition, partitionID, serviceID string) (map[string]Region, bool) {
for _, p := range ps {
if p.ID() != partitionID {
continue
}
if _, ok := p.p.Services[serviceID]; !ok {
break
}
s := Service{
id: serviceID,
p: p.p,
}
return s.Regions(), true
}
return map[string]Region{}, false
}
// PartitionForRegion returns the first partition which includes the region
// passed in. This includes both known regions and regions which match
// a pattern supported by the partition which may include regions that are
// not explicitly known by the partition. Use the Regions method of the
// returned Partition if explicit support is needed.
func PartitionForRegion(ps []Partition, regionID string) (Partition, bool) {
for _, p := range ps {
if _, ok := p.p.Regions[regionID]; ok || p.p.RegionRegex.MatchString(regionID) {
return p, true
}
}
return Partition{}, false
}
// A Partition provides the ability to enumerate the partition's regions
// and services.
type Partition struct {
@ -132,7 +175,7 @@ type Partition struct {
}
// ID returns the identifier of the partition.
func (p *Partition) ID() string { return p.id }
func (p Partition) ID() string { return p.id }
// EndpointFor attempts to resolve the endpoint based on service and region.
// See Options for information on configuring how the endpoint is resolved.
@ -155,13 +198,13 @@ func (p *Partition) ID() string { return p.id }
// Errors that can be returned.
// * UnknownServiceError
// * UnknownEndpointError
func (p *Partition) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
func (p Partition) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
return p.p.EndpointFor(service, region, opts...)
}
// Regions returns a map of Regions indexed by their ID. This is useful for
// enumerating over the regions in a partition.
func (p *Partition) Regions() map[string]Region {
func (p Partition) Regions() map[string]Region {
rs := map[string]Region{}
for id := range p.p.Regions {
rs[id] = Region{
@ -175,7 +218,7 @@ func (p *Partition) Regions() map[string]Region {
// Services returns a map of Service indexed by their ID. This is useful for
// enumerating over the services in a partition.
func (p *Partition) Services() map[string]Service {
func (p Partition) Services() map[string]Service {
ss := map[string]Service{}
for id := range p.p.Services {
ss[id] = Service{
@ -195,16 +238,16 @@ type Region struct {
}
// ID returns the region's identifier.
func (r *Region) ID() string { return r.id }
func (r Region) ID() string { return r.id }
// ResolveEndpoint resolves an endpoint from the context of the region given
// a service. See Partition.EndpointFor for usage and errors that can be returned.
func (r *Region) ResolveEndpoint(service string, opts ...func(*Options)) (ResolvedEndpoint, error) {
func (r Region) ResolveEndpoint(service string, opts ...func(*Options)) (ResolvedEndpoint, error) {
return r.p.EndpointFor(service, r.id, opts...)
}
// Services returns a list of all services that are known to be in this region.
func (r *Region) Services() map[string]Service {
func (r Region) Services() map[string]Service {
ss := map[string]Service{}
for id, s := range r.p.Services {
if _, ok := s.Endpoints[r.id]; ok {
@ -226,17 +269,38 @@ type Service struct {
}
// ID returns the identifier for the service.
func (s *Service) ID() string { return s.id }
func (s Service) ID() string { return s.id }
// ResolveEndpoint resolves an endpoint from the context of a service given
// a region. See Partition.EndpointFor for usage and errors that can be returned.
func (s *Service) ResolveEndpoint(region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
func (s Service) ResolveEndpoint(region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
return s.p.EndpointFor(s.id, region, opts...)
}
// Regions returns a map of Regions that the service is present in.
//
// A region is the AWS region the service exists in. Whereas a Endpoint is
// an URL that can be resolved to a instance of a service.
func (s Service) Regions() map[string]Region {
rs := map[string]Region{}
for id := range s.p.Services[s.id].Endpoints {
if _, ok := s.p.Regions[id]; ok {
rs[id] = Region{
id: id,
p: s.p,
}
}
}
return rs
}
// Endpoints returns a map of Endpoints indexed by their ID for all known
// endpoints for a service.
func (s *Service) Endpoints() map[string]Endpoint {
//
// A region is the AWS region the service exists in. Whereas a Endpoint is
// an URL that can be resolved to a instance of a service.
func (s Service) Endpoints() map[string]Endpoint {
es := map[string]Endpoint{}
for id := range s.p.Services[s.id].Endpoints {
es[id] = Endpoint{
@ -259,15 +323,15 @@ type Endpoint struct {
}
// ID returns the identifier for an endpoint.
func (e *Endpoint) ID() string { return e.id }
func (e Endpoint) ID() string { return e.id }
// ServiceID returns the identifier the endpoint belongs to.
func (e *Endpoint) ServiceID() string { return e.serviceID }
func (e Endpoint) ServiceID() string { return e.serviceID }
// ResolveEndpoint resolves an endpoint from the context of a service and
// region the endpoint represents. See Partition.EndpointFor for usage and
// errors that can be returned.
func (e *Endpoint) ResolveEndpoint(opts ...func(*Options)) (ResolvedEndpoint, error) {
func (e Endpoint) ResolveEndpoint(opts ...func(*Options)) (ResolvedEndpoint, error) {
return e.p.EndpointFor(e.serviceID, e.id, opts...)
}
@ -300,28 +364,6 @@ type EndpointNotFoundError struct {
Region string
}
//// NewEndpointNotFoundError builds and returns NewEndpointNotFoundError.
//func NewEndpointNotFoundError(p, s, r string) EndpointNotFoundError {
// return EndpointNotFoundError{
// awsError: awserr.New("EndpointNotFoundError", "unable to find endpoint", nil),
// Partition: p,
// Service: s,
// Region: r,
// }
//}
//
//// Error returns string representation of the error.
//func (e EndpointNotFoundError) Error() string {
// extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
// e.Partition, e.Service, e.Region)
// return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
//}
//
//// String returns the string representation of the error.
//func (e EndpointNotFoundError) String() string {
// return e.Error()
//}
// A UnknownServiceError is returned when the service does not resolve to an
// endpoint. Includes a list of all known services for the partition. Returned
// when a partition does not support the service.

View File

@ -84,6 +84,22 @@ func TestEnumRegionServices(t *testing.T) {
}
}
func TestEnumServiceRegions(t *testing.T) {
p := testPartitions[0].Partition()
rs := p.Services()["service1"].Regions()
if e, a := 2, len(rs); e != a {
t.Errorf("expect %d regions, got %d", e, a)
}
if _, ok := rs["us-east-1"]; !ok {
t.Errorf("expect region to be found")
}
if _, ok := rs["us-west-2"]; !ok {
t.Errorf("expect region to be found")
}
}
func TestEnumServicesEndpoints(t *testing.T) {
p := testPartitions[0].Partition()
@ -242,3 +258,78 @@ func TestOptionsSet(t *testing.T) {
t.Errorf("expect %v options got %v", expect, actual)
}
}
func TestRegionsForService(t *testing.T) {
ps := DefaultPartitions()
var expect map[string]Region
var serviceID string
for _, s := range ps[0].Services() {
expect = s.Regions()
serviceID = s.ID()
if len(expect) > 0 {
break
}
}
actual, ok := RegionsForService(ps, ps[0].ID(), serviceID)
if !ok {
t.Fatalf("expect regions to be found, was not")
}
if len(actual) == 0 {
t.Fatalf("expect service %s to have regions", serviceID)
}
if e, a := len(expect), len(actual); e != a {
t.Fatalf("expect %d regions, got %d", e, a)
}
for id, r := range actual {
if e, a := id, r.ID(); e != a {
t.Errorf("expect %s region id, got %s", e, a)
}
if _, ok := expect[id]; !ok {
t.Errorf("expect %s region to be found", id)
}
}
}
func TestRegionsForService_NotFound(t *testing.T) {
ps := testPartitions.Partitions()
actual, ok := RegionsForService(ps, ps[0].ID(), "service-not-exists")
if ok {
t.Fatalf("expect no regions to be found, but were")
}
if len(actual) != 0 {
t.Errorf("expect no regions, got %v", actual)
}
}
func TestPartitionForRegion(t *testing.T) {
ps := DefaultPartitions()
expect := ps[len(ps)%2]
var regionID string
for id := range expect.Regions() {
regionID = id
break
}
actual, ok := PartitionForRegion(ps, regionID)
if !ok {
t.Fatalf("expect partition to be found")
}
if e, a := expect.ID(), actual.ID(); e != a {
t.Errorf("expect %s partition, got %s", e, a)
}
}
func TestPartitionForRegion_NotFound(t *testing.T) {
ps := DefaultPartitions()
actual, ok := PartitionForRegion(ps, "regionNotExists")
if ok {
t.Errorf("expect no partition to be found, got %v", actual)
}
}

View File

@ -158,7 +158,7 @@ var funcMap = template.FuncMap{
const v3Tmpl = `
{{ define "defaults" -}}
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
// Code generated by aws/endpoints/v3model_codegen.go. DO NOT EDIT.
package endpoints
@ -209,17 +209,20 @@ import (
// DefaultResolver returns an Endpoint resolver that will be able
// to resolve endpoints for: {{ ListPartitionNames . }}.
//
// Casting the return value of this func to a EnumPartitions will
// allow you to get a list of the partitions in the order the endpoints
// will be resolved in.
// Use DefaultPartitions() to get the list of the default partitions.
func DefaultResolver() Resolver {
return defaultPartitions
}
// DefaultPartitions returns a list of the partitions the SDK is bundled
// with. The available partitions are: {{ ListPartitionNames . }}.
//
// resolver := endpoints.DefaultResolver()
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
// partitions := endpoints.DefaultPartitions
// for _, p := range partitions {
// // ... inspect partitions
// }
func DefaultResolver() Resolver {
return defaultPartitions
func DefaultPartitions() []Partition {
return defaultPartitions.Partitions()
}
var defaultPartitions = partitions{

12
vendor/github.com/aws/aws-sdk-go/aws/jsonvalue.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
package aws
// JSONValue is a representation of a grab bag type that will be marshaled
// into a json string. This type can be used just like any other map.
//
// Example:
//
// values := aws.JSONValue{
// "Foo": "Bar",
// }
// values["Baz"] = "Qux"
type JSONValue map[string]interface{}

View File

@ -0,0 +1,19 @@
// +build !appengine
package request
import (
"net"
"os"
"syscall"
)
func isErrConnectionReset(err error) bool {
if opErr, ok := err.(*net.OpError); ok {
if sysErr, ok := opErr.Err.(*os.SyscallError); ok {
return sysErr.Err == syscall.ECONNRESET
}
}
return false
}

View File

@ -0,0 +1,11 @@
// +build appengine
package request
import (
"strings"
)
func isErrConnectionReset(err error) bool {
return strings.Contains(err.Error(), "connection reset")
}

View File

@ -0,0 +1,9 @@
// +build appengine
package request_test
import (
"errors"
)
var stubConnectionResetError = errors.New("connection reset")

View File

@ -0,0 +1,11 @@
// +build !appengine
package request_test
import (
"net"
"os"
"syscall"
)
var stubConnectionResetError = &net.OpError{Err: &os.SyscallError{Syscall: "read", Err: syscall.ECONNRESET}}

View File

@ -18,6 +18,7 @@ type Handlers struct {
UnmarshalError HandlerList
Retry HandlerList
AfterRetry HandlerList
Complete HandlerList
}
// Copy returns of this handler's lists.
@ -33,6 +34,7 @@ func (h *Handlers) Copy() Handlers {
UnmarshalMeta: h.UnmarshalMeta.copy(),
Retry: h.Retry.copy(),
AfterRetry: h.AfterRetry.copy(),
Complete: h.Complete.copy(),
}
}
@ -48,6 +50,7 @@ func (h *Handlers) Clear() {
h.ValidateResponse.Clear()
h.Retry.Clear()
h.AfterRetry.Clear()
h.Complete.Clear()
}
// A HandlerListRunItem represents an entry in the HandlerList which
@ -85,13 +88,17 @@ func (l *HandlerList) copy() HandlerList {
n := HandlerList{
AfterEachFn: l.AfterEachFn,
}
n.list = append([]NamedHandler{}, l.list...)
if len(l.list) == 0 {
return n
}
n.list = append(make([]NamedHandler, 0, len(l.list)), l.list...)
return n
}
// Clear clears the handler list.
func (l *HandlerList) Clear() {
l.list = []NamedHandler{}
l.list = l.list[0:0]
}
// Len returns the number of handlers in the list.
@ -101,33 +108,54 @@ func (l *HandlerList) Len() int {
// PushBack pushes handler f to the back of the handler list.
func (l *HandlerList) PushBack(f func(*Request)) {
l.list = append(l.list, NamedHandler{"__anonymous", f})
}
// PushFront pushes handler f to the front of the handler list.
func (l *HandlerList) PushFront(f func(*Request)) {
l.list = append([]NamedHandler{{"__anonymous", f}}, l.list...)
l.PushBackNamed(NamedHandler{"__anonymous", f})
}
// PushBackNamed pushes named handler f to the back of the handler list.
func (l *HandlerList) PushBackNamed(n NamedHandler) {
if cap(l.list) == 0 {
l.list = make([]NamedHandler, 0, 5)
}
l.list = append(l.list, n)
}
// PushFront pushes handler f to the front of the handler list.
func (l *HandlerList) PushFront(f func(*Request)) {
l.PushFrontNamed(NamedHandler{"__anonymous", f})
}
// PushFrontNamed pushes named handler f to the front of the handler list.
func (l *HandlerList) PushFrontNamed(n NamedHandler) {
if cap(l.list) == len(l.list) {
// Allocating new list required
l.list = append([]NamedHandler{n}, l.list...)
} else {
// Enough room to prepend into list.
l.list = append(l.list, NamedHandler{})
copy(l.list[1:], l.list)
l.list[0] = n
}
}
// Remove removes a NamedHandler n
func (l *HandlerList) Remove(n NamedHandler) {
newlist := []NamedHandler{}
for _, m := range l.list {
if m.Name != n.Name {
newlist = append(newlist, m)
l.RemoveByName(n.Name)
}
// RemoveByName removes a NamedHandler by name.
func (l *HandlerList) RemoveByName(name string) {
for i := 0; i < len(l.list); i++ {
m := l.list[i]
if m.Name == name {
// Shift array preventing creating new arrays
copy(l.list[i:], l.list[i+1:])
l.list[len(l.list)-1] = NamedHandler{}
l.list = l.list[:len(l.list)-1]
// decrement list so next check to length is correct
i--
}
}
l.list = newlist
}
// Run executes all handlers in the list with a given request object.
@ -163,6 +191,16 @@ func HandlerListStopOnError(item HandlerListRunItem) bool {
return item.Request.Error == nil
}
// WithAppendUserAgent will add a string to the user agent prefixed with a
// single white space.
func WithAppendUserAgent(s string) Option {
return func(r *Request) {
r.Handlers.Build.PushBack(func(r2 *Request) {
AddToUserAgent(r, s)
})
}
}
// MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request
// header. If the extra parameters are provided they will be added as metadata to the
// name/version pair resulting in the following format.

View File

@ -7,6 +7,8 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/awstesting/unit"
"github.com/aws/aws-sdk-go/service/s3"
)
func TestHandlerList(t *testing.T) {
@ -85,3 +87,71 @@ func TestStopHandlers(t *testing.T) {
assert.Equal(t, 2, called, "Expect only two handlers to be called")
}
func BenchmarkNewRequest(b *testing.B) {
svc := s3.New(unit.Session)
for i := 0; i < b.N; i++ {
r, _ := svc.GetObjectRequest(nil)
if r == nil {
b.Fatal("r should not be nil")
}
}
}
func BenchmarkHandlersCopy(b *testing.B) {
handlers := request.Handlers{}
handlers.Validate.PushBack(func(r *request.Request) {})
handlers.Validate.PushBack(func(r *request.Request) {})
handlers.Build.PushBack(func(r *request.Request) {})
handlers.Build.PushBack(func(r *request.Request) {})
handlers.Send.PushBack(func(r *request.Request) {})
handlers.Send.PushBack(func(r *request.Request) {})
handlers.Unmarshal.PushBack(func(r *request.Request) {})
handlers.Unmarshal.PushBack(func(r *request.Request) {})
for i := 0; i < b.N; i++ {
h := handlers.Copy()
if e, a := handlers.Validate.Len(), h.Validate.Len(); e != a {
b.Fatalf("expected %d handlers got %d", e, a)
}
}
}
func BenchmarkHandlersPushBack(b *testing.B) {
handlers := request.Handlers{}
for i := 0; i < b.N; i++ {
h := handlers.Copy()
h.Validate.PushBack(func(r *request.Request) {})
h.Validate.PushBack(func(r *request.Request) {})
h.Validate.PushBack(func(r *request.Request) {})
h.Validate.PushBack(func(r *request.Request) {})
}
}
func BenchmarkHandlersPushFront(b *testing.B) {
handlers := request.Handlers{}
for i := 0; i < b.N; i++ {
h := handlers.Copy()
h.Validate.PushFront(func(r *request.Request) {})
h.Validate.PushFront(func(r *request.Request) {})
h.Validate.PushFront(func(r *request.Request) {})
h.Validate.PushFront(func(r *request.Request) {})
}
}
func BenchmarkHandlersClear(b *testing.B) {
handlers := request.Handlers{}
for i := 0; i < b.N; i++ {
h := handlers.Copy()
h.Validate.PushFront(func(r *request.Request) {})
h.Validate.PushFront(func(r *request.Request) {})
h.Validate.PushFront(func(r *request.Request) {})
h.Validate.PushFront(func(r *request.Request) {})
h.Clear()
}
}

View File

@ -16,6 +16,24 @@ import (
"github.com/aws/aws-sdk-go/aws/client/metadata"
)
const (
// ErrCodeSerialization is the serialization error code that is received
// during protocol unmarshaling.
ErrCodeSerialization = "SerializationError"
// ErrCodeRead is an error that is returned during HTTP reads.
ErrCodeRead = "ReadError"
// ErrCodeResponseTimeout is the connection timeout error that is recieved
// during body reads.
ErrCodeResponseTimeout = "ResponseTimeout"
// CanceledErrorCode is the error code that will be returned by an
// API request that was canceled. Requests given a aws.Context may
// return this error when canceled.
CanceledErrorCode = "RequestCanceled"
)
// A Request is the service request to be made.
type Request struct {
Config aws.Config
@ -40,13 +58,16 @@ type Request struct {
NotHoist bool
SignedHeaderVals http.Header
LastSignedAt time.Time
DisableFollowRedirects bool
context aws.Context
built bool
// Need to persist an intermideant body betweend the input Body and HTTP
// Need to persist an intermediate body between 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.
// safe to use concurrently and wrap the input Body for each HTTP request.
safeBody *offsetReader
}
@ -60,14 +81,6 @@ type Operation struct {
BeforePresignFn func(r *Request) error
}
// Paginator keeps track of pagination configuration for an API operation.
type Paginator struct {
InputTokens []string
OutputTokens []string
LimitToken string
TruncationToken string
}
// New returns a new Request pointer for the service API
// operation and parameters.
//
@ -111,6 +124,94 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
return r
}
// A Option is a functional option that can augment or modify a request when
// using a WithContext API operation method.
type Option func(*Request)
// WithGetResponseHeader builds a request Option which will retrieve a single
// header value from the HTTP Response. If there are multiple values for the
// header key use WithGetResponseHeaders instead to access the http.Header
// map directly. The passed in val pointer must be non-nil.
//
// This Option can be used multiple times with a single API operation.
//
// var id2, versionID string
// svc.PutObjectWithContext(ctx, params,
// request.WithGetResponseHeader("x-amz-id-2", &id2),
// request.WithGetResponseHeader("x-amz-version-id", &versionID),
// )
func WithGetResponseHeader(key string, val *string) Option {
return func(r *Request) {
r.Handlers.Complete.PushBack(func(req *Request) {
*val = req.HTTPResponse.Header.Get(key)
})
}
}
// WithGetResponseHeaders builds a request Option which will retrieve the
// headers from the HTTP response and assign them to the passed in headers
// variable. The passed in headers pointer must be non-nil.
//
// var headers http.Header
// svc.PutObjectWithContext(ctx, params, request.WithGetResponseHeaders(&headers))
func WithGetResponseHeaders(headers *http.Header) Option {
return func(r *Request) {
r.Handlers.Complete.PushBack(func(req *Request) {
*headers = req.HTTPResponse.Header
})
}
}
// WithLogLevel is a request option that will set the request to use a specific
// log level when the request is made.
//
// svc.PutObjectWithContext(ctx, params, request.WithLogLevel(aws.LogDebugWithHTTPBody)
func WithLogLevel(l aws.LogLevelType) Option {
return func(r *Request) {
r.Config.LogLevel = aws.LogLevel(l)
}
}
// ApplyOptions will apply each option to the request calling them in the order
// the were provided.
func (r *Request) ApplyOptions(opts ...Option) {
for _, opt := range opts {
opt(r)
}
}
// Context will always returns a non-nil context. If Request does not have a
// context aws.BackgroundContext will be returned.
func (r *Request) Context() aws.Context {
if r.context != nil {
return r.context
}
return aws.BackgroundContext()
}
// SetContext adds a Context to the current request that can be used to cancel
// a in-flight request. The Context value must not be nil, or this method will
// panic.
//
// Unlike http.Request.WithContext, SetContext does not return a copy of the
// Request. It is not safe to use use a single Request value for multiple
// requests. A new Request should be created for each API operation request.
//
// Go 1.6 and below:
// The http.Request's Cancel field will be set to the Done() value of
// the context. This will overwrite the Cancel field's value.
//
// Go 1.7 and above:
// The http.Request.WithContext will be used to set the context on the underlying
// http.Request. This will create a shallow copy of the http.Request. The SDK
// may create sub contexts in the future for nested requests such as retries.
func (r *Request) SetContext(ctx aws.Context) {
if ctx == nil {
panic("context cannot be nil")
}
setRequestContext(r, ctx)
}
// WillRetry returns if the request's can be retried.
func (r *Request) WillRetry() bool {
return r.Error != nil && aws.BoolValue(r.Retryable) && r.RetryCount < r.MaxRetries()
@ -262,7 +363,7 @@ func (r *Request) ResetBody() {
// Related golang/go#18257
l, err := computeBodyLength(r.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to compute request body size", err)
r.Error = awserr.New(ErrCodeSerialization, "failed to compute request body size", err)
return
}
@ -344,6 +445,12 @@ func (r *Request) GetBody() io.ReadSeeker {
//
// Send will not close the request.Request's body.
func (r *Request) Send() error {
defer func() {
// Regardless of success or failure of the request trigger the Complete
// request handlers.
r.Handlers.Complete.Run(r)
}()
for {
if aws.BoolValue(r.Retryable) {
if r.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) {
@ -446,6 +553,9 @@ func shouldRetryCancel(r *Request) bool {
timeoutErr := false
errStr := r.Error.Error()
if ok {
if awsErr.Code() == CanceledErrorCode {
return false
}
err := awsErr.OrigErr()
netErr, netOK := err.(net.Error)
timeoutErr = netOK && netErr.Temporary()

View File

@ -0,0 +1,14 @@
// +build go1.7
package request
import "github.com/aws/aws-sdk-go/aws"
// setContext updates the Request to use the passed in context for cancellation.
// Context will also be used for request retry delay.
//
// Creates shallow copy of the http.Request with the WithContext method.
func setRequestContext(r *Request, ctx aws.Context) {
r.context = ctx
r.HTTPRequest = r.HTTPRequest.WithContext(ctx)
}

View File

@ -0,0 +1,14 @@
// +build !go1.7
package request
import "github.com/aws/aws-sdk-go/aws"
// setContext updates the Request to use the passed in context for cancellation.
// Context will also be used for request retry delay.
//
// Creates shallow copy of the http.Request with the WithContext method.
func setRequestContext(r *Request, ctx aws.Context) {
r.context = ctx
r.HTTPRequest.Cancel = ctx.Done()
}

View File

@ -0,0 +1,46 @@
package request_test
import (
"fmt"
"strings"
"testing"
"github.com/aws/aws-sdk-go/aws/corehandlers"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/awstesting"
)
func TestRequest_SetContext(t *testing.T) {
svc := awstesting.NewClient()
svc.Handlers.Clear()
svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
r := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
r.SetContext(ctx)
ctx.Error = fmt.Errorf("context canceled")
close(ctx.DoneCh)
err := r.Send()
if err == nil {
t.Fatalf("expected error, got none")
}
// Only check against canceled because go 1.6 will not use the context's
// Err().
if e, a := "canceled", err.Error(); !strings.Contains(a, e) {
t.Errorf("expect %q to be in %q, but was not", e, a)
}
}
func TestRequest_SetContextPanic(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Fatalf("expect SetContext to panic, did not")
}
}()
r := &request.Request{}
r.SetContext(nil)
}

View File

@ -2,8 +2,6 @@ package request
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCopy(t *testing.T) {
@ -15,6 +13,15 @@ func TestCopy(t *testing.T) {
req.Handlers = handlers
r := req.copy()
assert.NotEqual(t, req, r)
assert.Equal(t, req.Operation.HTTPMethod, r.Operation.HTTPMethod)
if r == req {
t.Fatal("expect request pointer copy to be different")
}
if r.Operation == req.Operation {
t.Errorf("expect request operation pointer to be different")
}
if e, a := req.Operation.HTTPMethod, r.Operation.HTTPMethod; e != a {
t.Errorf("expect %q http method, got %q", e, a)
}
}

View File

@ -2,29 +2,125 @@ package request
import (
"reflect"
"sync/atomic"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awsutil"
)
//type Paginater interface {
// HasNextPage() bool
// NextPage() *Request
// EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error
//}
// A Pagination provides paginating of SDK API operations which are paginatable.
// Generally you should not use this type directly, but use the "Pages" API
// operations method to automatically perform pagination for you. Such as,
// "S3.ListObjectsPages", and "S3.ListObjectsPagesWithContext" methods.
//
// Pagination differs from a Paginator type in that pagination is the type that
// does the pagination between API operations, and Paginator defines the
// configuration that will be used per page request.
//
// cont := true
// for p.Next() && cont {
// data := p.Page().(*s3.ListObjectsOutput)
// // process the page's data
// }
// return p.Err()
//
// See service client API operation Pages methods for examples how the SDK will
// use the Pagination type.
type Pagination struct {
// Function to return a Request value for each pagination request.
// Any configuration or handlers that need to be applied to the request
// prior to getting the next page should be done here before the request
// returned.
//
// NewRequest should always be built from the same API operations. It is
// undefined if different API operations are returned on subsequent calls.
NewRequest func() (*Request, error)
// HasNextPage returns true if this request has more pages of data available.
func (r *Request) HasNextPage() bool {
return len(r.nextPageTokens()) > 0
started bool
nextTokens []interface{}
err error
curPage interface{}
}
// nextPageTokens returns the tokens to use when asking for the next page of
// data.
// HasNextPage will return true if Pagination is able to determine that the API
// operation has additional pages. False will be returned if there are no more
// pages remaining.
//
// Will always return true if Next has not been called yet.
func (p *Pagination) HasNextPage() bool {
return !(p.started && len(p.nextTokens) == 0)
}
// Err returns the error Pagination encountered when retrieving the next page.
func (p *Pagination) Err() error {
return p.err
}
// Page returns the current page. Page should only be called after a successful
// call to Next. It is undefined what Page will return if Page is called after
// Next returns false.
func (p *Pagination) Page() interface{} {
return p.curPage
}
// Next will attempt to retrieve the next page for the API operation. When a page
// is retrieved true will be returned. If the page cannot be retrieved, or there
// are no more pages false will be returned.
//
// Use the Page method to retrieve the current page data. The data will need
// to be cast to the API operation's output type.
//
// Use the Err method to determine if an error occurred if Page returns false.
func (p *Pagination) Next() bool {
if !p.HasNextPage() {
return false
}
req, err := p.NewRequest()
if err != nil {
p.err = err
return false
}
if p.started {
for i, intok := range req.Operation.InputTokens {
awsutil.SetValueAtPath(req.Params, intok, p.nextTokens[i])
}
}
p.started = true
err = req.Send()
if err != nil {
p.err = err
return false
}
p.nextTokens = req.nextPageTokens()
p.curPage = req.Data
return true
}
// A Paginator is the configuration data that defines how an API operation
// should be paginated. This type is used by the API service models to define
// the generated pagination config for service APIs.
//
// The Pagination type is what provides iterating between pages of an API. It
// is only used to store the token metadata the SDK should use for performing
// pagination.
type Paginator struct {
InputTokens []string
OutputTokens []string
LimitToken string
TruncationToken string
}
// nextPageTokens returns the tokens to use when asking for the next page of data.
func (r *Request) nextPageTokens() []interface{} {
if r.Operation.Paginator == nil {
return nil
}
if r.Operation.TruncationToken != "" {
tr, _ := awsutil.ValuesAtPath(r.Data, r.Operation.TruncationToken)
if len(tr) == 0 {
@ -61,9 +157,40 @@ func (r *Request) nextPageTokens() []interface{} {
return tokens
}
// Ensure a deprecated item is only logged once instead of each time its used.
func logDeprecatedf(logger aws.Logger, flag *int32, msg string) {
if logger == nil {
return
}
if atomic.CompareAndSwapInt32(flag, 0, 1) {
logger.Log(msg)
}
}
var (
logDeprecatedHasNextPage int32
logDeprecatedNextPage int32
logDeprecatedEachPage int32
)
// HasNextPage returns true if this request has more pages of data available.
//
// Deprecated Use Pagination type for configurable pagination of API operations
func (r *Request) HasNextPage() bool {
logDeprecatedf(r.Config.Logger, &logDeprecatedHasNextPage,
"Request.HasNextPage deprecated. Use Pagination type for configurable pagination of API operations")
return len(r.nextPageTokens()) > 0
}
// NextPage returns a new Request that can be executed to return the next
// page of result data. Call .Send() on this request to execute it.
//
// Deprecated Use Pagination type for configurable pagination of API operations
func (r *Request) NextPage() *Request {
logDeprecatedf(r.Config.Logger, &logDeprecatedNextPage,
"Request.NextPage deprecated. Use Pagination type for configurable pagination of API operations")
tokens := r.nextPageTokens()
if len(tokens) == 0 {
return nil
@ -90,7 +217,12 @@ func (r *Request) NextPage() *Request {
// as the structure "T". The lastPage value represents whether the page is
// the last page of data or not. The return value of this function should
// return true to keep iterating or false to stop.
//
// Deprecated Use Pagination type for configurable pagination of API operations
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
logDeprecatedf(r.Config.Logger, &logDeprecatedEachPage,
"Request.EachPage deprecated. Use Pagination type for configurable pagination of API operations")
for page := r; page != nil; page = page.NextPage() {
if err := page.Send(); err != nil {
return err

View File

@ -7,6 +7,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/unit"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/route53"
@ -380,6 +381,154 @@ func TestPaginationNilToken(t *testing.T) {
assert.Equal(t, []string{"first.example.com.", "second.example.com.", "third.example.com."}, results)
}
func TestPaginationNilInput(t *testing.T) {
// Code generation doesn't have a great way to verify the code is correct
// other than being run via unit tests in the SDK. This should be fixed
// So code generation can be validated independently.
client := s3.New(unit.Session)
client.Handlers.Validate.Clear()
client.Handlers.Send.Clear() // mock sending
client.Handlers.Unmarshal.Clear()
client.Handlers.UnmarshalMeta.Clear()
client.Handlers.ValidateResponse.Clear()
client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = &s3.ListObjectsOutput{}
})
gotToEnd := false
numPages := 0
err := client.ListObjectsPages(nil, func(p *s3.ListObjectsOutput, last bool) bool {
numPages++
if last {
gotToEnd = true
}
return true
})
if err != nil {
t.Fatalf("expect no error, but got %v", err)
}
if e, a := 1, numPages; e != a {
t.Errorf("expect %d number pages but got %d", e, a)
}
if !gotToEnd {
t.Errorf("expect to of gotten to end, did not")
}
}
func TestPaginationWithContextNilInput(t *testing.T) {
// Code generation doesn't have a great way to verify the code is correct
// other than being run via unit tests in the SDK. This should be fixed
// So code generation can be validated independently.
client := s3.New(unit.Session)
client.Handlers.Validate.Clear()
client.Handlers.Send.Clear() // mock sending
client.Handlers.Unmarshal.Clear()
client.Handlers.UnmarshalMeta.Clear()
client.Handlers.ValidateResponse.Clear()
client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = &s3.ListObjectsOutput{}
})
gotToEnd := false
numPages := 0
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
err := client.ListObjectsPagesWithContext(ctx, nil, func(p *s3.ListObjectsOutput, last bool) bool {
numPages++
if last {
gotToEnd = true
}
return true
})
if err != nil {
t.Fatalf("expect no error, but got %v", err)
}
if e, a := 1, numPages; e != a {
t.Errorf("expect %d number pages but got %d", e, a)
}
if !gotToEnd {
t.Errorf("expect to of gotten to end, did not")
}
}
type testPageInput struct {
NextToken string
}
type testPageOutput struct {
Value string
NextToken *string
}
func TestPagination_Standalone(t *testing.T) {
expect := []struct {
Value, PrevToken, NextToken string
}{
{"FirstValue", "InitalToken", "FirstToken"},
{"SecondValue", "FirstToken", "SecondToken"},
{"ThirdValue", "SecondToken", ""},
}
input := testPageInput{
NextToken: expect[0].PrevToken,
}
c := awstesting.NewClient()
i := 0
p := request.Pagination{
NewRequest: func() (*request.Request, error) {
r := c.NewRequest(
&request.Operation{
Name: "Operation",
Paginator: &request.Paginator{
InputTokens: []string{"NextToken"},
OutputTokens: []string{"NextToken"},
},
},
&input, &testPageOutput{},
)
// Setup handlers for testing
r.Handlers.Clear()
r.Handlers.Build.PushBack(func(req *request.Request) {
in := req.Params.(*testPageInput)
if e, a := expect[i].PrevToken, in.NextToken; e != a {
t.Errorf("%d, expect NextToken input %q, got %q", i, e, a)
}
})
r.Handlers.Unmarshal.PushBack(func(req *request.Request) {
out := &testPageOutput{
Value: expect[i].Value,
}
if len(expect[i].NextToken) > 0 {
out.NextToken = aws.String(expect[i].NextToken)
}
req.Data = out
})
return r, nil
},
}
for p.Next() {
data := p.Page().(*testPageOutput)
if e, a := expect[i].Value, data.Value; e != a {
t.Errorf("%d, expect Value to be %q, got %q", i, e, a)
}
if e, a := expect[i].NextToken, aws.StringValue(data.NextToken); e != a {
t.Errorf("%d, expect NextToken to be %q, got %q", i, e, a)
}
i++
}
if e, a := len(expect), i; e != a {
t.Errorf("expected to process %d pages, did %d", e, a)
}
if err := p.Err(); err != nil {
t.Fatalf("%d, expected no error, got %v", i, err)
}
}
// Benchmarks
var benchResps = []*dynamodb.ListTablesOutput{
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},

View File

@ -3,23 +3,29 @@ package request_test
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"reflect"
"runtime"
"strconv"
"testing"
"time"
"github.com/stretchr/testify/assert"
"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/client/metadata"
"github.com/aws/aws-sdk-go/aws/corehandlers"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/signer/v4"
"github.com/aws/aws-sdk-go/awstesting"
"github.com/aws/aws-sdk-go/awstesting/unit"
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
"github.com/aws/aws-sdk-go/private/protocol/rest"
)
@ -91,9 +97,15 @@ func TestRequestRecoverRetry5xx(t *testing.T) {
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.Nil(t, err)
assert.Equal(t, 2, int(r.RetryCount))
assert.Equal(t, "valid", out.Data)
if err != nil {
t.Fatalf("expect no error, but got %v", err)
}
if e, a := 2, int(r.RetryCount); e != a {
t.Errorf("expect %d retry count, got %d", e, a)
}
if e, a := "valid", out.Data; e != a {
t.Errorf("expect %q output got %q", e, a)
}
}
// test that retries occur for 4xx status codes with a response type that can be retried - see `shouldRetry`
@ -117,9 +129,15 @@ func TestRequestRecoverRetry4xxRetryable(t *testing.T) {
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.Nil(t, err)
assert.Equal(t, 2, int(r.RetryCount))
assert.Equal(t, "valid", out.Data)
if err != nil {
t.Fatalf("expect no error, but got %v", err)
}
if e, a := 2, int(r.RetryCount); e != a {
t.Errorf("expect %d retry count, got %d", e, a)
}
if e, a := "valid", out.Data; e != a {
t.Errorf("expect %q output got %q", e, a)
}
}
// test that retries don't occur for 4xx status codes with a response type that can't be retried
@ -135,15 +153,22 @@ func TestRequest4xxUnretryable(t *testing.T) {
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.NotNil(t, err)
if e, ok := err.(awserr.RequestFailure); ok {
assert.Equal(t, 401, e.StatusCode())
} else {
assert.Fail(t, "Expected error to be a service failure")
if err == nil {
t.Fatalf("expect error, but did not get one")
}
aerr := err.(awserr.RequestFailure)
if e, a := 401, aerr.StatusCode(); e != a {
t.Errorf("expect %d status code, got %d", e, a)
}
if e, a := "SignatureDoesNotMatch", aerr.Code(); e != a {
t.Errorf("expect %q error code, got %q", e, a)
}
if e, a := "Signature does not match.", aerr.Message(); e != a {
t.Errorf("expect %q error message, got %q", e, a)
}
if e, a := 0, int(r.RetryCount); e != a {
t.Errorf("expect %d retry count, got %d", e, a)
}
assert.Equal(t, "SignatureDoesNotMatch", err.(awserr.Error).Code())
assert.Equal(t, "Signature does not match.", err.(awserr.Error).Message())
assert.Equal(t, 0, int(r.RetryCount))
}
func TestRequestExhaustRetries(t *testing.T) {
@ -171,22 +196,31 @@ func TestRequestExhaustRetries(t *testing.T) {
})
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
err := r.Send()
assert.NotNil(t, err)
if e, ok := err.(awserr.RequestFailure); ok {
assert.Equal(t, 500, e.StatusCode())
} else {
assert.Fail(t, "Expected error to be a service failure")
if err == nil {
t.Fatalf("expect error, but did not get one")
}
aerr := err.(awserr.RequestFailure)
if e, a := 500, aerr.StatusCode(); e != a {
t.Errorf("expect %d status code, got %d", e, a)
}
if e, a := "UnknownError", aerr.Code(); e != a {
t.Errorf("expect %q error code, got %q", e, a)
}
if e, a := "An error occurred.", aerr.Message(); e != a {
t.Errorf("expect %q error message, got %q", e, a)
}
if e, a := 3, int(r.RetryCount); e != a {
t.Errorf("expect %d retry count, got %d", e, a)
}
assert.Equal(t, "UnknownError", err.(awserr.Error).Code())
assert.Equal(t, "An error occurred.", err.(awserr.Error).Message())
assert.Equal(t, 3, int(r.RetryCount))
expectDelays := []struct{ min, max time.Duration }{{30, 59}, {60, 118}, {120, 236}}
for i, v := range delays {
min := expectDelays[i].min * time.Millisecond
max := expectDelays[i].max * time.Millisecond
assert.True(t, min <= v && v <= max,
"Expect delay to be within range, i:%d, v:%s, min:%s, max:%s", i, v, min, max)
if !(min <= v && v <= max) {
t.Errorf("Expect delay to be within range, i:%d, v:%s, min:%s, max:%s",
i, v, min, max)
}
}
}
@ -222,14 +256,26 @@ func TestRequestRecoverExpiredCreds(t *testing.T) {
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.Nil(t, err)
if err != nil {
t.Fatalf("expect no error, got %v", err)
}
assert.False(t, credExpiredBeforeRetry, "Expect valid creds before retry check")
assert.True(t, credExpiredAfterRetry, "Expect expired creds after retry check")
assert.False(t, s.Config.Credentials.IsExpired(), "Expect valid creds after cred expired recovery")
if credExpiredBeforeRetry {
t.Errorf("Expect valid creds before retry check")
}
if !credExpiredAfterRetry {
t.Errorf("Expect expired creds after retry check")
}
if s.Config.Credentials.IsExpired() {
t.Errorf("Expect valid creds after cred expired recovery")
}
assert.Equal(t, 1, int(r.RetryCount))
assert.Equal(t, "valid", out.Data)
if e, a := 1, int(r.RetryCount); e != a {
t.Errorf("expect %d retry count, got %d", e, a)
}
if e, a := "valid", out.Data; e != a {
t.Errorf("expect %q output got %q", e, a)
}
}
func TestMakeAddtoUserAgentHandler(t *testing.T) {
@ -238,7 +284,9 @@ func TestMakeAddtoUserAgentHandler(t *testing.T) {
r.HTTPRequest.Header.Set("User-Agent", "foo/bar")
fn(r)
assert.Equal(t, "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"))
if e, a := "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"); e != a {
t.Errorf("expect %q user agent, got %q", e, a)
}
}
func TestMakeAddtoUserAgentFreeFormHandler(t *testing.T) {
@ -247,7 +295,9 @@ func TestMakeAddtoUserAgentFreeFormHandler(t *testing.T) {
r.HTTPRequest.Header.Set("User-Agent", "foo/bar")
fn(r)
assert.Equal(t, "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"))
if e, a := "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"); e != a {
t.Errorf("expect %q user agent, got %q", e, a)
}
}
func TestRequestUserAgent(t *testing.T) {
@ -256,11 +306,15 @@ func TestRequestUserAgent(t *testing.T) {
req := s.NewRequest(&request.Operation{Name: "Operation"}, nil, &testData{})
req.HTTPRequest.Header.Set("User-Agent", "foo/bar")
assert.NoError(t, req.Build())
if err := req.Build(); err != nil {
t.Fatalf("expect no error, got %v", err)
}
expectUA := fmt.Sprintf("foo/bar %s/%s (%s; %s; %s)",
aws.SDKName, aws.SDKVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH)
assert.Equal(t, expectUA, req.HTTPRequest.Header.Get("User-Agent"))
if e, a := expectUA, req.HTTPRequest.Header.Get("User-Agent"); e != a {
t.Errorf("expect %q user agent, got %q", e, a)
}
}
func TestRequestThrottleRetries(t *testing.T) {
@ -288,22 +342,31 @@ func TestRequestThrottleRetries(t *testing.T) {
})
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
err := r.Send()
assert.NotNil(t, err)
if e, ok := err.(awserr.RequestFailure); ok {
assert.Equal(t, 500, e.StatusCode())
} else {
assert.Fail(t, "Expected error to be a service failure")
if err == nil {
t.Fatalf("expect error, but did not get one")
}
aerr := err.(awserr.RequestFailure)
if e, a := 500, aerr.StatusCode(); e != a {
t.Errorf("expect %d status code, got %d", e, a)
}
if e, a := "Throttling", aerr.Code(); e != a {
t.Errorf("expect %q error code, got %q", e, a)
}
if e, a := "An error occurred.", aerr.Message(); e != a {
t.Errorf("expect %q error message, got %q", e, a)
}
if e, a := 3, int(r.RetryCount); e != a {
t.Errorf("expect %d retry count, got %d", e, a)
}
assert.Equal(t, "Throttling", err.(awserr.Error).Code())
assert.Equal(t, "An error occurred.", err.(awserr.Error).Message())
assert.Equal(t, 3, int(r.RetryCount))
expectDelays := []struct{ min, max time.Duration }{{500, 999}, {1000, 1998}, {2000, 3996}}
for i, v := range delays {
min := expectDelays[i].min * time.Millisecond
max := expectDelays[i].max * time.Millisecond
assert.True(t, min <= v && v <= max,
"Expect delay to be within range, i:%d, v:%s, min:%s, max:%s", i, v, min, max)
if !(min <= v && v <= max) {
t.Errorf("Expect delay to be within range, i:%d, v:%s, min:%s, max:%s",
i, v, min, max)
}
}
}
@ -339,9 +402,15 @@ func TestRequestRecoverTimeoutWithNilBody(t *testing.T) {
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.Nil(t, err)
assert.Equal(t, 1, int(r.RetryCount))
assert.Equal(t, "valid", out.Data)
if err != nil {
t.Fatalf("expect no error, but got %v", err)
}
if e, a := 1, int(r.RetryCount); e != a {
t.Errorf("expect %d retry count, got %d", e, a)
}
if e, a := "valid", out.Data; e != a {
t.Errorf("expect %q output got %q", e, a)
}
}
func TestRequestRecoverTimeoutWithNilResponse(t *testing.T) {
@ -376,9 +445,15 @@ func TestRequestRecoverTimeoutWithNilResponse(t *testing.T) {
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.Nil(t, err)
assert.Equal(t, 1, int(r.RetryCount))
assert.Equal(t, "valid", out.Data)
if err != nil {
t.Fatalf("expect no error, but got %v", err)
}
if e, a := 1, int(r.RetryCount); e != a {
t.Errorf("expect %d retry count, got %d", e, a)
}
if e, a := "valid", out.Data; e != a {
t.Errorf("expect %q output got %q", e, a)
}
}
func TestRequest_NoBody(t *testing.T) {
@ -438,3 +513,280 @@ func TestRequest_NoBody(t *testing.T) {
}
}
}
func TestIsSerializationErrorRetryable(t *testing.T) {
testCases := []struct {
err error
expected bool
}{
{
err: awserr.New(request.ErrCodeSerialization, "foo error", nil),
expected: false,
},
{
err: awserr.New("ErrFoo", "foo error", nil),
expected: false,
},
{
err: nil,
expected: false,
},
{
err: awserr.New(request.ErrCodeSerialization, "foo error", stubConnectionResetError),
expected: true,
},
}
for i, c := range testCases {
r := &request.Request{
Error: c.err,
}
if r.IsErrorRetryable() != c.expected {
t.Errorf("Case %d: Expected %v, but received %v", i+1, c.expected, !c.expected)
}
}
}
func TestWithLogLevel(t *testing.T) {
r := &request.Request{}
opt := request.WithLogLevel(aws.LogDebugWithHTTPBody)
r.ApplyOptions(opt)
if !r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) {
t.Errorf("expect log level to be set, but was not, %v",
r.Config.LogLevel.Value())
}
}
func TestWithGetResponseHeader(t *testing.T) {
r := &request.Request{}
var val, val2 string
r.ApplyOptions(
request.WithGetResponseHeader("x-a-header", &val),
request.WithGetResponseHeader("x-second-header", &val2),
)
r.HTTPResponse = &http.Response{
Header: func() http.Header {
h := http.Header{}
h.Set("x-a-header", "first")
h.Set("x-second-header", "second")
return h
}(),
}
r.Handlers.Complete.Run(r)
if e, a := "first", val; e != a {
t.Errorf("expect %q header value got %q", e, a)
}
if e, a := "second", val2; e != a {
t.Errorf("expect %q header value got %q", e, a)
}
}
func TestWithGetResponseHeaders(t *testing.T) {
r := &request.Request{}
var headers http.Header
opt := request.WithGetResponseHeaders(&headers)
r.ApplyOptions(opt)
r.HTTPResponse = &http.Response{
Header: func() http.Header {
h := http.Header{}
h.Set("x-a-header", "headerValue")
return h
}(),
}
r.Handlers.Complete.Run(r)
if e, a := "headerValue", headers.Get("x-a-header"); e != a {
t.Errorf("expect %q header value got %q", e, a)
}
}
type connResetCloser struct {
}
func (rc *connResetCloser) Read(b []byte) (int, error) {
return 0, stubConnectionResetError
}
func (rc *connResetCloser) Close() error {
return nil
}
func TestSerializationErrConnectionReset(t *testing.T) {
count := 0
handlers := request.Handlers{}
handlers.Send.PushBack(func(r *request.Request) {
count++
r.HTTPResponse = &http.Response{}
r.HTTPResponse.Body = &connResetCloser{}
})
handlers.Sign.PushBackNamed(v4.SignRequestHandler)
handlers.Build.PushBackNamed(jsonrpc.BuildHandler)
handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler)
handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler)
handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler)
handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
op := &request.Operation{
Name: "op",
HTTPMethod: "POST",
HTTPPath: "/",
}
meta := metadata.ClientInfo{
ServiceName: "fooService",
SigningName: "foo",
SigningRegion: "foo",
Endpoint: "localhost",
APIVersion: "2001-01-01",
JSONVersion: "1.1",
TargetPrefix: "Foo",
}
cfg := unit.Session.Config.Copy()
cfg.MaxRetries = aws.Int(5)
req := request.New(
*cfg,
meta,
handlers,
client.DefaultRetryer{NumMaxRetries: 5},
op,
&struct {
}{},
&struct {
}{},
)
osErr := stubConnectionResetError
req.ApplyOptions(request.WithResponseReadTimeout(time.Second))
err := req.Send()
if err == nil {
t.Error("Expected rror 'SerializationError', but received nil")
}
if aerr, ok := err.(awserr.Error); ok && aerr.Code() != "SerializationError" {
t.Errorf("Expected 'SerializationError', but received %q", aerr.Code())
} else if !ok {
t.Errorf("Expected 'awserr.Error', but received %v", reflect.TypeOf(err))
} else if aerr.OrigErr().Error() != osErr.Error() {
t.Errorf("Expected %q, but received %q", osErr.Error(), aerr.OrigErr().Error())
}
if count != 6 {
t.Errorf("Expected '6', but received %d", count)
}
}
type testRetryer struct {
shouldRetry bool
}
func (d *testRetryer) MaxRetries() int {
return 3
}
// RetryRules returns the delay duration before retrying this request again
func (d *testRetryer) RetryRules(r *request.Request) time.Duration {
return time.Duration(time.Millisecond)
}
func (d *testRetryer) ShouldRetry(r *request.Request) bool {
d.shouldRetry = true
if r.Retryable != nil {
return *r.Retryable
}
if r.HTTPResponse.StatusCode >= 500 {
return true
}
return r.IsErrorRetryable()
}
func TestEnforceShouldRetryCheck(t *testing.T) {
tp := &http.Transport{
Proxy: http.ProxyFromEnvironment,
ResponseHeaderTimeout: 1 * time.Millisecond,
}
client := &http.Client{Transport: tp}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(5 * time.Millisecond)
}))
retryer := &testRetryer{}
s := awstesting.NewClient(&aws.Config{
Region: aws.String("mock-region"),
MaxRetries: aws.Int(0),
Endpoint: aws.String(server.URL),
DisableSSL: aws.Bool(true),
Retryer: retryer,
HTTPClient: client,
EnforceShouldRetryCheck: aws.Bool(true),
})
s.Handlers.Validate.Clear()
s.Handlers.Unmarshal.PushBack(unmarshal)
s.Handlers.UnmarshalError.PushBack(unmarshalError)
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
if err == nil {
t.Fatalf("expect error, but got nil")
}
if e, a := 3, int(r.RetryCount); e != a {
t.Errorf("expect %d retry count, got %d", e, a)
}
if !retryer.shouldRetry {
t.Errorf("expect 'true' for ShouldRetry, but got %v", retryer.shouldRetry)
}
}
type errReader struct {
err error
}
func (reader *errReader) Read(b []byte) (int, error) {
return 0, reader.err
}
func (reader *errReader) Close() error {
return nil
}
func TestLoggerNotIgnoringErrors(t *testing.T) {
s := awstesting.NewClient(&aws.Config{
Region: aws.String("mock-region"),
MaxRetries: aws.Int(0),
DisableSSL: aws.Bool(true),
LogLevel: aws.LogLevel(aws.LogDebugWithHTTPBody),
})
s.Handlers.Validate.Clear()
s.Handlers.Send.Clear()
s.Handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &http.Response{StatusCode: 200, Body: &errReader{errors.New("Foo error")}}
})
s.AddDebugHandlers()
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
if err == nil {
t.Error("expected error, but got nil")
}
if aerr, ok := err.(awserr.Error); !ok {
t.Errorf("expected awserr.Error, but got different error, %v", err)
} else if aerr.Code() != request.ErrCodeRead {
t.Errorf("expected %q, but received %q", request.ErrCodeRead, aerr.Code())
}
}

View File

@ -28,6 +28,8 @@ func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
var retryableCodes = map[string]struct{}{
"RequestError": {},
"RequestTimeout": {},
ErrCodeResponseTimeout: {},
"RequestTimeoutException": {}, // Glacier's flavor of RequestTimeout
}
var throttleCodes = map[string]struct{}{
@ -68,35 +70,85 @@ func isCodeExpiredCreds(code string) bool {
return ok
}
var validParentCodes = map[string]struct{}{
ErrCodeSerialization: struct{}{},
ErrCodeRead: struct{}{},
}
func isNestedErrorRetryable(parentErr awserr.Error) bool {
if parentErr == nil {
return false
}
if _, ok := validParentCodes[parentErr.Code()]; !ok {
return false
}
err := parentErr.OrigErr()
if err == nil {
return false
}
if aerr, ok := err.(awserr.Error); ok {
return isCodeRetryable(aerr.Code())
}
return isErrConnectionReset(err)
}
// IsErrorRetryable returns whether the error is retryable, based on its Code.
// Returns false if the request has no Error set.
func (r *Request) IsErrorRetryable() bool {
if r.Error != nil {
if err, ok := r.Error.(awserr.Error); ok {
return isCodeRetryable(err.Code())
// Returns false if error is nil.
func IsErrorRetryable(err error) bool {
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
return isCodeRetryable(aerr.Code()) || isNestedErrorRetryable(aerr)
}
}
return false
}
// IsErrorThrottle returns whether the error is to be throttled based on its code.
// Returns false if the request has no Error set
func (r *Request) IsErrorThrottle() bool {
if r.Error != nil {
if err, ok := r.Error.(awserr.Error); ok {
return isCodeThrottle(err.Code())
// Returns false if error is nil.
func IsErrorThrottle(err error) bool {
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
return isCodeThrottle(aerr.Code())
}
}
return false
}
// IsErrorExpired returns whether the error code is a credential expiry error.
// Returns false if the request has no Error set.
func (r *Request) IsErrorExpired() bool {
if r.Error != nil {
if err, ok := r.Error.(awserr.Error); ok {
return isCodeExpiredCreds(err.Code())
// IsErrorExpiredCreds returns whether the error code is a credential expiry error.
// Returns false if error is nil.
func IsErrorExpiredCreds(err error) bool {
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
return isCodeExpiredCreds(aerr.Code())
}
}
return false
}
// IsErrorRetryable returns whether the error is retryable, based on its Code.
// Returns false if the request has no Error set.
//
// Alias for the utility function IsErrorRetryable
func (r *Request) IsErrorRetryable() bool {
return IsErrorRetryable(r.Error)
}
// IsErrorThrottle returns whether the error is to be throttled based on its code.
// Returns false if the request has no Error set
//
// Alias for the utility function IsErrorThrottle
func (r *Request) IsErrorThrottle() bool {
return IsErrorThrottle(r.Error)
}
// IsErrorExpired returns whether the error code is a credential expiry error.
// Returns false if the request has no Error set.
//
// Alias for the utility function IsErrorExpiredCreds
func (r *Request) IsErrorExpired() bool {
return IsErrorExpiredCreds(r.Error)
}

View File

@ -0,0 +1,94 @@
package request
import (
"io"
"time"
"github.com/aws/aws-sdk-go/aws/awserr"
)
var timeoutErr = awserr.New(
ErrCodeResponseTimeout,
"read on body has reached the timeout limit",
nil,
)
type readResult struct {
n int
err error
}
// timeoutReadCloser will handle body reads that take too long.
// We will return a ErrReadTimeout error if a timeout occurs.
type timeoutReadCloser struct {
reader io.ReadCloser
duration time.Duration
}
// Read will spin off a goroutine to call the reader's Read method. We will
// select on the timer's channel or the read's channel. Whoever completes first
// will be returned.
func (r *timeoutReadCloser) Read(b []byte) (int, error) {
timer := time.NewTimer(r.duration)
c := make(chan readResult, 1)
go func() {
n, err := r.reader.Read(b)
timer.Stop()
c <- readResult{n: n, err: err}
}()
select {
case data := <-c:
return data.n, data.err
case <-timer.C:
return 0, timeoutErr
}
}
func (r *timeoutReadCloser) Close() error {
return r.reader.Close()
}
const (
// HandlerResponseTimeout is what we use to signify the name of the
// response timeout handler.
HandlerResponseTimeout = "ResponseTimeoutHandler"
)
// adaptToResponseTimeoutError is a handler that will replace any top level error
// to a ErrCodeResponseTimeout, if its child is that.
func adaptToResponseTimeoutError(req *Request) {
if err, ok := req.Error.(awserr.Error); ok {
aerr, ok := err.OrigErr().(awserr.Error)
if ok && aerr.Code() == ErrCodeResponseTimeout {
req.Error = aerr
}
}
}
// WithResponseReadTimeout is a request option that will wrap the body in a timeout read closer.
// This will allow for per read timeouts. If a timeout occurred, we will return the
// ErrCodeResponseTimeout.
//
// svc.PutObjectWithContext(ctx, params, request.WithTimeoutReadCloser(30 * time.Second)
func WithResponseReadTimeout(duration time.Duration) Option {
return func(r *Request) {
var timeoutHandler = NamedHandler{
HandlerResponseTimeout,
func(req *Request) {
req.HTTPResponse.Body = &timeoutReadCloser{
reader: req.HTTPResponse.Body,
duration: duration,
}
}}
// remove the handler so we are not stomping over any new durations.
r.Handlers.Send.RemoveByName(HandlerResponseTimeout)
r.Handlers.Send.PushBackNamed(timeoutHandler)
r.Handlers.Unmarshal.PushBack(adaptToResponseTimeoutError)
r.Handlers.UnmarshalError.PushBack(adaptToResponseTimeoutError)
}
}

View File

@ -0,0 +1,76 @@
package request_test
import (
"bytes"
"io/ioutil"
"net/http"
"testing"
"time"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/signer/v4"
"github.com/aws/aws-sdk-go/awstesting/unit"
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
)
func BenchmarkTimeoutReadCloser(b *testing.B) {
resp := `
{
"Bar": "qux"
}
`
handlers := request.Handlers{}
handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &http.Response{
StatusCode: http.StatusOK,
Body: ioutil.NopCloser(bytes.NewBuffer([]byte(resp))),
}
})
handlers.Sign.PushBackNamed(v4.SignRequestHandler)
handlers.Build.PushBackNamed(jsonrpc.BuildHandler)
handlers.Unmarshal.PushBackNamed(jsonrpc.UnmarshalHandler)
handlers.UnmarshalMeta.PushBackNamed(jsonrpc.UnmarshalMetaHandler)
handlers.UnmarshalError.PushBackNamed(jsonrpc.UnmarshalErrorHandler)
op := &request.Operation{
Name: "op",
HTTPMethod: "POST",
HTTPPath: "/",
}
meta := metadata.ClientInfo{
ServiceName: "fooService",
SigningName: "foo",
SigningRegion: "foo",
Endpoint: "localhost",
APIVersion: "2001-01-01",
JSONVersion: "1.1",
TargetPrefix: "Foo",
}
req := request.New(
*unit.Session.Config,
meta,
handlers,
client.DefaultRetryer{NumMaxRetries: 5},
op,
&struct {
Foo *string
}{},
&struct {
Bar *string
}{},
)
req.ApplyOptions(request.WithResponseReadTimeout(15 * time.Second))
for i := 0; i < b.N; i++ {
err := req.Send()
if err != nil {
b.Errorf("Expected no error, but received %v", err)
}
}
}

View File

@ -0,0 +1,118 @@
package request
import (
"bytes"
"io"
"io/ioutil"
"net/http"
"testing"
"time"
"github.com/aws/aws-sdk-go/aws/awserr"
)
type testReader struct {
duration time.Duration
count int
}
func (r *testReader) Read(b []byte) (int, error) {
if r.count > 0 {
r.count--
return len(b), nil
}
time.Sleep(r.duration)
return 0, io.EOF
}
func (r *testReader) Close() error {
return nil
}
func TestTimeoutReadCloser(t *testing.T) {
reader := timeoutReadCloser{
reader: &testReader{
duration: time.Second,
count: 5,
},
duration: time.Millisecond,
}
b := make([]byte, 100)
_, err := reader.Read(b)
if err != nil {
t.Log(err)
}
}
func TestTimeoutReadCloserSameDuration(t *testing.T) {
reader := timeoutReadCloser{
reader: &testReader{
duration: time.Millisecond,
count: 5,
},
duration: time.Millisecond,
}
b := make([]byte, 100)
_, err := reader.Read(b)
if err != nil {
t.Log(err)
}
}
func TestWithResponseReadTimeout(t *testing.T) {
r := Request{
HTTPResponse: &http.Response{
Body: ioutil.NopCloser(bytes.NewReader(nil)),
},
}
r.ApplyOptions(WithResponseReadTimeout(time.Second))
err := r.Send()
if err != nil {
t.Error(err)
}
v, ok := r.HTTPResponse.Body.(*timeoutReadCloser)
if !ok {
t.Error("Expected the body to be a timeoutReadCloser")
}
if v.duration != time.Second {
t.Errorf("Expected %v, but receive %v\n", time.Second, v.duration)
}
}
func TestAdaptToResponseTimeout(t *testing.T) {
testCases := []struct {
childErr error
r Request
expectedRootCode string
}{
{
childErr: awserr.New(ErrCodeResponseTimeout, "timeout!", nil),
r: Request{
Error: awserr.New("ErrTest", "FooBar", awserr.New(ErrCodeResponseTimeout, "timeout!", nil)),
},
expectedRootCode: ErrCodeResponseTimeout,
},
{
childErr: awserr.New(ErrCodeResponseTimeout+"1", "timeout!", nil),
r: Request{
Error: awserr.New("ErrTest", "FooBar", awserr.New(ErrCodeResponseTimeout+"1", "timeout!", nil)),
},
expectedRootCode: "ErrTest",
},
{
r: Request{
Error: awserr.New("ErrTest", "FooBar", nil),
},
expectedRootCode: "ErrTest",
},
}
for i, c := range testCases {
adaptToResponseTimeoutError(&c.r)
if aerr, ok := c.r.Error.(awserr.Error); !ok {
t.Errorf("Case %d: Expected 'awserr', but received %v", i+1, c.r.Error)
} else if aerr.Code() != c.expectedRootCode {
t.Errorf("Case %d: Expected %q, but received %s", i+1, c.expectedRootCode, aerr.Code())
}
}
}

287
vendor/github.com/aws/aws-sdk-go/aws/request/waiter.go generated vendored Normal file
View File

@ -0,0 +1,287 @@
package request
import (
"fmt"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/awsutil"
)
// WaiterResourceNotReadyErrorCode is the error code returned by a waiter when
// the waiter's max attempts have been exhausted.
const WaiterResourceNotReadyErrorCode = "ResourceNotReady"
// A WaiterOption is a function that will update the Waiter value's fields to
// configure the waiter.
type WaiterOption func(*Waiter)
// WithWaiterMaxAttempts returns the maximum number of times the waiter should
// attempt to check the resource for the target state.
func WithWaiterMaxAttempts(max int) WaiterOption {
return func(w *Waiter) {
w.MaxAttempts = max
}
}
// WaiterDelay will return a delay the waiter should pause between attempts to
// check the resource state. The passed in attempt is the number of times the
// Waiter has checked the resource state.
//
// Attempt is the number of attempts the Waiter has made checking the resource
// state.
type WaiterDelay func(attempt int) time.Duration
// ConstantWaiterDelay returns a WaiterDelay that will always return a constant
// delay the waiter should use between attempts. It ignores the number of
// attempts made.
func ConstantWaiterDelay(delay time.Duration) WaiterDelay {
return func(attempt int) time.Duration {
return delay
}
}
// WithWaiterDelay will set the Waiter to use the WaiterDelay passed in.
func WithWaiterDelay(delayer WaiterDelay) WaiterOption {
return func(w *Waiter) {
w.Delay = delayer
}
}
// WithWaiterLogger returns a waiter option to set the logger a waiter
// should use to log warnings and errors to.
func WithWaiterLogger(logger aws.Logger) WaiterOption {
return func(w *Waiter) {
w.Logger = logger
}
}
// WithWaiterRequestOptions returns a waiter option setting the request
// options for each request the waiter makes. Appends to waiter's request
// options already set.
func WithWaiterRequestOptions(opts ...Option) WaiterOption {
return func(w *Waiter) {
w.RequestOptions = append(w.RequestOptions, opts...)
}
}
// A Waiter provides the functionality to perform a blocking call which will
// wait for a resource state to be satisfied by a service.
//
// This type should not be used directly. The API operations provided in the
// service packages prefixed with "WaitUntil" should be used instead.
type Waiter struct {
Name string
Acceptors []WaiterAcceptor
Logger aws.Logger
MaxAttempts int
Delay WaiterDelay
RequestOptions []Option
NewRequest func([]Option) (*Request, error)
}
// ApplyOptions updates the waiter with the list of waiter options provided.
func (w *Waiter) ApplyOptions(opts ...WaiterOption) {
for _, fn := range opts {
fn(w)
}
}
// WaiterState are states the waiter uses based on WaiterAcceptor definitions
// to identify if the resource state the waiter is waiting on has occurred.
type WaiterState int
// String returns the string representation of the waiter state.
func (s WaiterState) String() string {
switch s {
case SuccessWaiterState:
return "success"
case FailureWaiterState:
return "failure"
case RetryWaiterState:
return "retry"
default:
return "unknown waiter state"
}
}
// States the waiter acceptors will use to identify target resource states.
const (
SuccessWaiterState WaiterState = iota // waiter successful
FailureWaiterState // waiter failed
RetryWaiterState // waiter needs to be retried
)
// WaiterMatchMode is the mode that the waiter will use to match the WaiterAcceptor
// definition's Expected attribute.
type WaiterMatchMode int
// Modes the waiter will use when inspecting API response to identify target
// resource states.
const (
PathAllWaiterMatch WaiterMatchMode = iota // match on all paths
PathWaiterMatch // match on specific path
PathAnyWaiterMatch // match on any path
PathListWaiterMatch // match on list of paths
StatusWaiterMatch // match on status code
ErrorWaiterMatch // match on error
)
// String returns the string representation of the waiter match mode.
func (m WaiterMatchMode) String() string {
switch m {
case PathAllWaiterMatch:
return "pathAll"
case PathWaiterMatch:
return "path"
case PathAnyWaiterMatch:
return "pathAny"
case PathListWaiterMatch:
return "pathList"
case StatusWaiterMatch:
return "status"
case ErrorWaiterMatch:
return "error"
default:
return "unknown waiter match mode"
}
}
// WaitWithContext will make requests for the API operation using NewRequest to
// build API requests. The request's response will be compared against the
// Waiter's Acceptors to determine the successful state of the resource the
// waiter is inspecting.
//
// The passed in context must not be nil. If it is nil a panic will occur. The
// Context will be used to cancel the waiter's pending requests and retry delays.
// Use aws.BackgroundContext if no context is available.
//
// The waiter will continue until the target state defined by the Acceptors,
// or the max attempts expires.
//
// Will return the WaiterResourceNotReadyErrorCode error code if the waiter's
// retryer ShouldRetry returns false. This normally will happen when the max
// wait attempts expires.
func (w Waiter) WaitWithContext(ctx aws.Context) error {
for attempt := 1; ; attempt++ {
req, err := w.NewRequest(w.RequestOptions)
if err != nil {
waiterLogf(w.Logger, "unable to create request %v", err)
return err
}
req.Handlers.Build.PushBack(MakeAddToUserAgentFreeFormHandler("Waiter"))
err = req.Send()
// See if any of the acceptors match the request's response, or error
for _, a := range w.Acceptors {
if matched, matchErr := a.match(w.Name, w.Logger, req, err); matched {
return matchErr
}
}
// The Waiter should only check the resource state MaxAttempts times
// This is here instead of in the for loop above to prevent delaying
// unnecessary when the waiter will not retry.
if attempt == w.MaxAttempts {
break
}
// Delay to wait before inspecting the resource again
delay := w.Delay(attempt)
if sleepFn := req.Config.SleepDelay; sleepFn != nil {
// Support SleepDelay for backwards compatibility and testing
sleepFn(delay)
} else if err := aws.SleepWithContext(ctx, delay); err != nil {
return awserr.New(CanceledErrorCode, "waiter context canceled", err)
}
}
return awserr.New(WaiterResourceNotReadyErrorCode, "exceeded wait attempts", nil)
}
// A WaiterAcceptor provides the information needed to wait for an API operation
// to complete.
type WaiterAcceptor struct {
State WaiterState
Matcher WaiterMatchMode
Argument string
Expected interface{}
}
// match returns if the acceptor found a match with the passed in request
// or error. True is returned if the acceptor made a match, error is returned
// if there was an error attempting to perform the match.
func (a *WaiterAcceptor) match(name string, l aws.Logger, req *Request, err error) (bool, error) {
result := false
var vals []interface{}
switch a.Matcher {
case PathAllWaiterMatch, PathWaiterMatch:
// Require all matches to be equal for result to match
vals, _ = awsutil.ValuesAtPath(req.Data, a.Argument)
if len(vals) == 0 {
break
}
result = true
for _, val := range vals {
if !awsutil.DeepEqual(val, a.Expected) {
result = false
break
}
}
case PathAnyWaiterMatch:
// Only a single match needs to equal for the result to match
vals, _ = awsutil.ValuesAtPath(req.Data, a.Argument)
for _, val := range vals {
if awsutil.DeepEqual(val, a.Expected) {
result = true
break
}
}
case PathListWaiterMatch:
// ignored matcher
case StatusWaiterMatch:
s := a.Expected.(int)
result = s == req.HTTPResponse.StatusCode
case ErrorWaiterMatch:
if aerr, ok := err.(awserr.Error); ok {
result = aerr.Code() == a.Expected.(string)
}
default:
waiterLogf(l, "WARNING: Waiter %s encountered unexpected matcher: %s",
name, a.Matcher)
}
if !result {
// If there was no matching result found there is nothing more to do
// for this response, retry the request.
return false, nil
}
switch a.State {
case SuccessWaiterState:
// waiter completed
return true, nil
case FailureWaiterState:
// Waiter failure state triggered
return true, awserr.New(WaiterResourceNotReadyErrorCode,
"failed waiting for successful resource state", err)
case RetryWaiterState:
// clear the error and retry the operation
return false, nil
default:
waiterLogf(l, "WARNING: Waiter %s encountered unexpected state: %s",
name, a.State)
return false, nil
}
}
func waiterLogf(logger aws.Logger, msg string, args ...interface{}) {
if logger != nil {
logger.Log(fmt.Sprintf(msg, args...))
}
}

View File

@ -0,0 +1,636 @@
package request_test
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/assert"
"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/request"
"github.com/aws/aws-sdk-go/awstesting"
"github.com/aws/aws-sdk-go/awstesting/unit"
"github.com/aws/aws-sdk-go/service/s3"
)
type mockClient struct {
*client.Client
}
type MockInput struct{}
type MockOutput struct {
States []*MockState
}
type MockState struct {
State *string
}
func (c *mockClient) MockRequest(input *MockInput) (*request.Request, *MockOutput) {
op := &request.Operation{
Name: "Mock",
HTTPMethod: "POST",
HTTPPath: "/",
}
if input == nil {
input = &MockInput{}
}
output := &MockOutput{}
req := c.NewRequest(op, input, output)
req.Data = output
return req, output
}
func BuildNewMockRequest(c *mockClient, in *MockInput) func([]request.Option) (*request.Request, error) {
return func(opts []request.Option) (*request.Request, error) {
req, _ := c.MockRequest(in)
req.ApplyOptions(opts...)
return req, nil
}
}
func TestWaiterPathAll(t *testing.T) {
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
Region: aws.String("mock-region"),
})}
svc.Handlers.Send.Clear() // mock sending
svc.Handlers.Unmarshal.Clear()
svc.Handlers.UnmarshalMeta.Clear()
svc.Handlers.ValidateResponse.Clear()
reqNum := 0
resps := []*MockOutput{
{ // Request 1
States: []*MockState{
{State: aws.String("pending")},
{State: aws.String("pending")},
},
},
{ // Request 2
States: []*MockState{
{State: aws.String("running")},
{State: aws.String("pending")},
},
},
{ // Request 3
States: []*MockState{
{State: aws.String("running")},
{State: aws.String("running")},
},
},
}
numBuiltReq := 0
svc.Handlers.Build.PushBack(func(r *request.Request) {
numBuiltReq++
})
svc.Handlers.Unmarshal.PushBack(func(r *request.Request) {
if reqNum >= len(resps) {
assert.Fail(t, "too many polling requests made")
return
}
r.Data = resps[reqNum]
reqNum++
})
w := request.Waiter{
MaxAttempts: 10,
Delay: request.ConstantWaiterDelay(0),
Acceptors: []request.WaiterAcceptor{
{
State: request.SuccessWaiterState,
Matcher: request.PathAllWaiterMatch,
Argument: "States[].State",
Expected: "running",
},
},
NewRequest: BuildNewMockRequest(svc, &MockInput{}),
}
err := w.WaitWithContext(aws.BackgroundContext())
assert.NoError(t, err)
assert.Equal(t, 3, numBuiltReq)
assert.Equal(t, 3, reqNum)
}
func TestWaiterPath(t *testing.T) {
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
Region: aws.String("mock-region"),
})}
svc.Handlers.Send.Clear() // mock sending
svc.Handlers.Unmarshal.Clear()
svc.Handlers.UnmarshalMeta.Clear()
svc.Handlers.ValidateResponse.Clear()
reqNum := 0
resps := []*MockOutput{
{ // Request 1
States: []*MockState{
{State: aws.String("pending")},
{State: aws.String("pending")},
},
},
{ // Request 2
States: []*MockState{
{State: aws.String("running")},
{State: aws.String("pending")},
},
},
{ // Request 3
States: []*MockState{
{State: aws.String("running")},
{State: aws.String("running")},
},
},
}
numBuiltReq := 0
svc.Handlers.Build.PushBack(func(r *request.Request) {
numBuiltReq++
})
svc.Handlers.Unmarshal.PushBack(func(r *request.Request) {
if reqNum >= len(resps) {
assert.Fail(t, "too many polling requests made")
return
}
r.Data = resps[reqNum]
reqNum++
})
w := request.Waiter{
MaxAttempts: 10,
Delay: request.ConstantWaiterDelay(0),
Acceptors: []request.WaiterAcceptor{
{
State: request.SuccessWaiterState,
Matcher: request.PathWaiterMatch,
Argument: "States[].State",
Expected: "running",
},
},
NewRequest: BuildNewMockRequest(svc, &MockInput{}),
}
err := w.WaitWithContext(aws.BackgroundContext())
assert.NoError(t, err)
assert.Equal(t, 3, numBuiltReq)
assert.Equal(t, 3, reqNum)
}
func TestWaiterFailure(t *testing.T) {
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
Region: aws.String("mock-region"),
})}
svc.Handlers.Send.Clear() // mock sending
svc.Handlers.Unmarshal.Clear()
svc.Handlers.UnmarshalMeta.Clear()
svc.Handlers.ValidateResponse.Clear()
reqNum := 0
resps := []*MockOutput{
{ // Request 1
States: []*MockState{
{State: aws.String("pending")},
{State: aws.String("pending")},
},
},
{ // Request 2
States: []*MockState{
{State: aws.String("running")},
{State: aws.String("pending")},
},
},
{ // Request 3
States: []*MockState{
{State: aws.String("running")},
{State: aws.String("stopping")},
},
},
}
numBuiltReq := 0
svc.Handlers.Build.PushBack(func(r *request.Request) {
numBuiltReq++
})
svc.Handlers.Unmarshal.PushBack(func(r *request.Request) {
if reqNum >= len(resps) {
assert.Fail(t, "too many polling requests made")
return
}
r.Data = resps[reqNum]
reqNum++
})
w := request.Waiter{
MaxAttempts: 10,
Delay: request.ConstantWaiterDelay(0),
Acceptors: []request.WaiterAcceptor{
{
State: request.SuccessWaiterState,
Matcher: request.PathAllWaiterMatch,
Argument: "States[].State",
Expected: "running",
},
{
State: request.FailureWaiterState,
Matcher: request.PathAnyWaiterMatch,
Argument: "States[].State",
Expected: "stopping",
},
},
NewRequest: BuildNewMockRequest(svc, &MockInput{}),
}
err := w.WaitWithContext(aws.BackgroundContext()).(awserr.Error)
assert.Error(t, err)
assert.Equal(t, request.WaiterResourceNotReadyErrorCode, err.Code())
assert.Equal(t, "failed waiting for successful resource state", err.Message())
assert.Equal(t, 3, numBuiltReq)
assert.Equal(t, 3, reqNum)
}
func TestWaiterError(t *testing.T) {
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
Region: aws.String("mock-region"),
})}
svc.Handlers.Send.Clear() // mock sending
svc.Handlers.Unmarshal.Clear()
svc.Handlers.UnmarshalMeta.Clear()
svc.Handlers.UnmarshalError.Clear()
svc.Handlers.ValidateResponse.Clear()
reqNum := 0
resps := []*MockOutput{
{ // Request 1
States: []*MockState{
{State: aws.String("pending")},
{State: aws.String("pending")},
},
},
{ // Request 1, error case retry
},
{ // Request 2, error case failure
},
{ // Request 3
States: []*MockState{
{State: aws.String("running")},
{State: aws.String("running")},
},
},
}
reqErrs := make([]error, len(resps))
reqErrs[1] = awserr.New("MockException", "mock exception message", nil)
reqErrs[2] = awserr.New("FailureException", "mock failure exception message", nil)
numBuiltReq := 0
svc.Handlers.Build.PushBack(func(r *request.Request) {
numBuiltReq++
})
svc.Handlers.Send.PushBack(func(r *request.Request) {
code := 200
if reqNum == 1 {
code = 400
}
r.HTTPResponse = &http.Response{
StatusCode: code,
Status: http.StatusText(code),
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
}
})
svc.Handlers.Unmarshal.PushBack(func(r *request.Request) {
if reqNum >= len(resps) {
assert.Fail(t, "too many polling requests made")
return
}
r.Data = resps[reqNum]
reqNum++
})
svc.Handlers.UnmarshalMeta.PushBack(func(r *request.Request) {
// If there was an error unmarshal error will be called instead of unmarshal
// need to increment count here also
if err := reqErrs[reqNum]; err != nil {
r.Error = err
reqNum++
}
})
w := request.Waiter{
MaxAttempts: 10,
Delay: request.ConstantWaiterDelay(0),
Acceptors: []request.WaiterAcceptor{
{
State: request.SuccessWaiterState,
Matcher: request.PathAllWaiterMatch,
Argument: "States[].State",
Expected: "running",
},
{
State: request.RetryWaiterState,
Matcher: request.ErrorWaiterMatch,
Argument: "",
Expected: "MockException",
},
{
State: request.FailureWaiterState,
Matcher: request.ErrorWaiterMatch,
Argument: "",
Expected: "FailureException",
},
},
NewRequest: BuildNewMockRequest(svc, &MockInput{}),
}
err := w.WaitWithContext(aws.BackgroundContext())
if err == nil {
t.Fatalf("expected error, but did not get one")
}
aerr := err.(awserr.Error)
if e, a := request.WaiterResourceNotReadyErrorCode, aerr.Code(); e != a {
t.Errorf("expect %q error code, got %q", e, a)
}
if e, a := 3, numBuiltReq; e != a {
t.Errorf("expect %d built requests got %d", e, a)
}
if e, a := 3, reqNum; e != a {
t.Errorf("expect %d reqNum got %d", e, a)
}
}
func TestWaiterStatus(t *testing.T) {
svc := &mockClient{Client: awstesting.NewClient(&aws.Config{
Region: aws.String("mock-region"),
})}
svc.Handlers.Send.Clear() // mock sending
svc.Handlers.Unmarshal.Clear()
svc.Handlers.UnmarshalMeta.Clear()
svc.Handlers.ValidateResponse.Clear()
reqNum := 0
svc.Handlers.Build.PushBack(func(r *request.Request) {
reqNum++
})
svc.Handlers.Send.PushBack(func(r *request.Request) {
code := 200
if reqNum == 3 {
code = 404
r.Error = awserr.New("NotFound", "Not Found", nil)
}
r.HTTPResponse = &http.Response{
StatusCode: code,
Status: http.StatusText(code),
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
}
})
w := request.Waiter{
MaxAttempts: 10,
Delay: request.ConstantWaiterDelay(0),
Acceptors: []request.WaiterAcceptor{
{
State: request.SuccessWaiterState,
Matcher: request.StatusWaiterMatch,
Argument: "",
Expected: 404,
},
},
NewRequest: BuildNewMockRequest(svc, &MockInput{}),
}
err := w.WaitWithContext(aws.BackgroundContext())
assert.NoError(t, err)
assert.Equal(t, 3, reqNum)
}
func TestWaiter_ApplyOptions(t *testing.T) {
w := request.Waiter{}
logger := aws.NewDefaultLogger()
w.ApplyOptions(
request.WithWaiterLogger(logger),
request.WithWaiterRequestOptions(request.WithLogLevel(aws.LogDebug)),
request.WithWaiterMaxAttempts(2),
request.WithWaiterDelay(request.ConstantWaiterDelay(5*time.Second)),
)
if e, a := logger, w.Logger; e != a {
t.Errorf("expect logger to be set, and match, was not, %v, %v", e, a)
}
if len(w.RequestOptions) != 1 {
t.Fatalf("expect request options to be set to only a single option, %v", w.RequestOptions)
}
r := request.Request{}
r.ApplyOptions(w.RequestOptions...)
if e, a := aws.LogDebug, r.Config.LogLevel.Value(); e != a {
t.Errorf("expect %v loglevel got %v", e, a)
}
if e, a := 2, w.MaxAttempts; e != a {
t.Errorf("expect %d retryer max attempts, got %d", e, a)
}
if e, a := 5*time.Second, w.Delay(0); e != a {
t.Errorf("expect %d retryer delay, got %d", e, a)
}
}
func TestWaiter_WithContextCanceled(t *testing.T) {
c := awstesting.NewClient()
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
reqCount := 0
w := request.Waiter{
Name: "TestWaiter",
MaxAttempts: 10,
Delay: request.ConstantWaiterDelay(1 * time.Millisecond),
Acceptors: []request.WaiterAcceptor{
{
State: request.SuccessWaiterState,
Matcher: request.StatusWaiterMatch,
Expected: 200,
},
},
Logger: aws.NewDefaultLogger(),
NewRequest: func(opts []request.Option) (*request.Request, error) {
req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
req.HTTPResponse = &http.Response{StatusCode: http.StatusNotFound}
req.Handlers.Clear()
req.Data = struct{}{}
req.Handlers.Send.PushBack(func(r *request.Request) {
if reqCount == 1 {
ctx.Error = fmt.Errorf("context canceled")
close(ctx.DoneCh)
}
reqCount++
})
return req, nil
},
}
err := w.WaitWithContext(ctx)
if err == nil {
t.Fatalf("expect waiter to be canceled.")
}
aerr := err.(awserr.Error)
if e, a := request.CanceledErrorCode, aerr.Code(); e != a {
t.Errorf("expect %q error code, got %q", e, a)
}
if e, a := 2, reqCount; e != a {
t.Errorf("expect %d requests, got %d", e, a)
}
}
func TestWaiter_WithContext(t *testing.T) {
c := awstesting.NewClient()
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
reqCount := 0
statuses := []int{http.StatusNotFound, http.StatusOK}
w := request.Waiter{
Name: "TestWaiter",
MaxAttempts: 10,
Delay: request.ConstantWaiterDelay(1 * time.Millisecond),
Acceptors: []request.WaiterAcceptor{
{
State: request.SuccessWaiterState,
Matcher: request.StatusWaiterMatch,
Expected: 200,
},
},
Logger: aws.NewDefaultLogger(),
NewRequest: func(opts []request.Option) (*request.Request, error) {
req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
req.HTTPResponse = &http.Response{StatusCode: statuses[reqCount]}
req.Handlers.Clear()
req.Data = struct{}{}
req.Handlers.Send.PushBack(func(r *request.Request) {
if reqCount == 1 {
ctx.Error = fmt.Errorf("context canceled")
close(ctx.DoneCh)
}
reqCount++
})
return req, nil
},
}
err := w.WaitWithContext(ctx)
if err != nil {
t.Fatalf("expect no error, got %v", err)
}
if e, a := 2, reqCount; e != a {
t.Errorf("expect %d requests, got %d", e, a)
}
}
func TestWaiter_AttemptsExpires(t *testing.T) {
c := awstesting.NewClient()
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
reqCount := 0
w := request.Waiter{
Name: "TestWaiter",
MaxAttempts: 2,
Delay: request.ConstantWaiterDelay(1 * time.Millisecond),
Acceptors: []request.WaiterAcceptor{
{
State: request.SuccessWaiterState,
Matcher: request.StatusWaiterMatch,
Expected: 200,
},
},
Logger: aws.NewDefaultLogger(),
NewRequest: func(opts []request.Option) (*request.Request, error) {
req := c.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
req.HTTPResponse = &http.Response{StatusCode: http.StatusNotFound}
req.Handlers.Clear()
req.Data = struct{}{}
req.Handlers.Send.PushBack(func(r *request.Request) {
reqCount++
})
return req, nil
},
}
err := w.WaitWithContext(ctx)
if err == nil {
t.Fatalf("expect error did not get one")
}
aerr := err.(awserr.Error)
if e, a := request.WaiterResourceNotReadyErrorCode, aerr.Code(); e != a {
t.Errorf("expect %q error code, got %q", e, a)
}
if e, a := 2, reqCount; e != a {
t.Errorf("expect %d requests, got %d", e, a)
}
}
func TestWaiterNilInput(t *testing.T) {
// Code generation doesn't have a great way to verify the code is correct
// other than being run via unit tests in the SDK. This should be fixed
// So code generation can be validated independently.
client := s3.New(unit.Session)
client.Handlers.Validate.Clear()
client.Handlers.Send.Clear() // mock sending
client.Handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &http.Response{
StatusCode: http.StatusOK,
}
})
client.Handlers.Unmarshal.Clear()
client.Handlers.UnmarshalMeta.Clear()
client.Handlers.ValidateResponse.Clear()
client.Config.SleepDelay = func(dur time.Duration) {}
// Ensure waiters do not panic on nil input. It doesn't make sense to
// call a waiter without an input, Validation will
err := client.WaitUntilBucketExists(nil)
if err != nil {
t.Fatalf("expect no error, but got %v", err)
}
}
func TestWaiterWithContextNilInput(t *testing.T) {
// Code generation doesn't have a great way to verify the code is correct
// other than being run via unit tests in the SDK. This should be fixed
// So code generation can be validated independently.
client := s3.New(unit.Session)
client.Handlers.Validate.Clear()
client.Handlers.Send.Clear() // mock sending
client.Handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &http.Response{
StatusCode: http.StatusOK,
}
})
client.Handlers.Unmarshal.Clear()
client.Handlers.UnmarshalMeta.Clear()
client.Handlers.ValidateResponse.Clear()
// Ensure waiters do not panic on nil input
ctx := &awstesting.FakeContext{DoneCh: make(chan struct{})}
err := client.WaitUntilBucketExistsWithContext(ctx, nil,
request.WithWaiterDelay(request.ConstantWaiterDelay(0)),
request.WithWaiterMaxAttempts(1),
)
if err != nil {
t.Fatalf("expect no error, but got %v", err)
}
}

View File

@ -23,7 +23,7 @@ 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
SharedConfigEnable will create the session as if the AWS_SDK_LOAD_CONFIG
environment variable was set.
Creating Sessions
@ -84,7 +84,7 @@ override the shared config state (AWS_SDK_LOAD_CONFIG).
// Force enable Shared Config support
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: SharedConfigEnable,
SharedConfigState: session.SharedConfigEnable,
}))
Adding Handlers
@ -125,8 +125,7 @@ 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 file (~/.aws/credentials) over those in the shared config 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

View File

@ -218,7 +218,7 @@ type Options struct {
//
// // Force enable Shared Config support
// sess := session.Must(session.NewSessionWithOptions(session.Options{
// SharedConfigState: SharedConfigEnable,
// SharedConfigState: session.SharedConfigEnable,
// }))
func NewSessionWithOptions(opts Options) (*Session, error) {
var envCfg envConfig

View File

@ -0,0 +1,7 @@
package v4
// WithUnsignedPayload will enable and set the UnsignedPayload field to
// true of the signer.
func WithUnsignedPayload(v4 *Signer) {
v4.UnsignedPayload = true
}

View File

@ -194,6 +194,10 @@ type Signer struct {
// This value should only be used for testing. If it is nil the default
// time.Now will be used.
currentTimeFn func() time.Time
// UnsignedPayload will prevent signing of the payload. This will only
// work for services that have support for this.
UnsignedPayload bool
}
// NewSigner returns a Signer pointer configured with the credentials and optional
@ -227,6 +231,7 @@ type signingCtx struct {
isPresign bool
formattedTime string
formattedShortTime string
unsignedPayload bool
bodyDigest string
signedHeaders string
@ -317,6 +322,7 @@ func (v4 Signer) signWithBody(r *http.Request, body io.ReadSeeker, service, regi
ServiceName: service,
Region: region,
DisableURIPathEscaping: v4.DisableURIPathEscaping,
unsignedPayload: v4.UnsignedPayload,
}
for key := range ctx.Query {
@ -409,7 +415,18 @@ var SignRequestHandler = request.NamedHandler{
func SignSDKRequest(req *request.Request) {
signSDKRequestWithCurrTime(req, time.Now)
}
func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time) {
// BuildNamedHandler will build a generic handler for signing.
func BuildNamedHandler(name string, opts ...func(*Signer)) request.NamedHandler {
return request.NamedHandler{
Name: name,
Fn: func(req *request.Request) {
signSDKRequestWithCurrTime(req, time.Now, opts...)
},
}
}
func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time, opts ...func(*Signer)) {
// If the request does not need to be signed ignore the signing of the
// request if the AnonymousCredentials object is used.
if req.Config.Credentials == credentials.AnonymousCredentials {
@ -441,6 +458,10 @@ func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time
v4.DisableRequestBodyOverwrite = true
})
for _, opt := range opts {
opt(v4)
}
signingTime := req.Time
if !req.LastSignedAt.IsZero() {
signingTime = req.LastSignedAt
@ -634,14 +655,14 @@ func (ctx *signingCtx) buildSignature() {
func (ctx *signingCtx) buildBodyDigest() {
hash := ctx.Request.Header.Get("X-Amz-Content-Sha256")
if hash == "" {
if ctx.isPresign && ctx.ServiceName == "s3" {
if ctx.unsignedPayload || (ctx.isPresign && ctx.ServiceName == "s3") {
hash = "UNSIGNED-PAYLOAD"
} else if ctx.Body == nil {
hash = emptyStringSHA256
} else {
hash = hex.EncodeToString(makeSha256Reader(ctx.Body))
}
if ctx.ServiceName == "s3" || ctx.ServiceName == "glacier" {
if ctx.unsignedPayload || ctx.ServiceName == "s3" || ctx.ServiceName == "glacier" {
ctx.Request.Header.Set("X-Amz-Content-Sha256", hash)
}
}

12
vendor/github.com/aws/aws-sdk-go/aws/url.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// +build go1.8
package aws
import "net/url"
// URLHostname will extract the Hostname without port from the URL value.
//
// Wrapper of net/url#URL.Hostname for backwards Go version compatibility.
func URLHostname(url *url.URL) string {
return url.Hostname()
}

29
vendor/github.com/aws/aws-sdk-go/aws/url_1_7.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
// +build !go1.8
package aws
import (
"net/url"
"strings"
)
// URLHostname will extract the Hostname without port from the URL value.
//
// Copy of Go 1.8's net/url#URL.Hostname functionality.
func URLHostname(url *url.URL) string {
return stripPort(url.Host)
}
// stripPort is copy of Go 1.8 url#URL.Hostname functionality.
// https://golang.org/src/net/url/url.go
func stripPort(hostport string) string {
colon := strings.IndexByte(hostport, ':')
if colon == -1 {
return hostport
}
if i := strings.IndexByte(hostport, ']'); i != -1 {
return strings.TrimPrefix(hostport[:i], "[")
}
return hostport[:colon]
}

View File

@ -5,4 +5,4 @@ package aws
const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK
const SDKVersion = "1.7.9"
const SDKVersion = "1.8.20"

View File

@ -0,0 +1,94 @@
// +build integration
package main
import (
"fmt"
"os"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
// Searches the buckets of an account that match the prefix, and deletes
// those buckets, and all objects within. Before deleting will prompt user
// to confirm bucket should be deleted. Positive confirmation is required.
//
// Usage:
// go run deleteBuckets.go <bucketPrefix>
func main() {
sess := session.Must(session.NewSession())
svc := s3.New(sess)
buckets, err := svc.ListBuckets(&s3.ListBucketsInput{})
if err != nil {
panic(fmt.Sprintf("failed to list buckets, %v", err))
}
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "bucket prefix required")
os.Exit(1)
}
bucketPrefix := os.Args[1]
var failed bool
for _, b := range buckets.Buckets {
bucket := aws.StringValue(b.Name)
if !strings.HasPrefix(bucket, bucketPrefix) {
continue
}
fmt.Printf("Delete bucket %q? [y/N]: ", bucket)
var v string
if _, err := fmt.Scanln(&v); err != nil || !(v == "Y" || v == "y") {
fmt.Println("\tSkipping")
continue
}
fmt.Println("\tDeleting")
if err := deleteBucket(svc, bucket); err != nil {
fmt.Fprintf(os.Stderr, "failed to delete bucket %q, %v", bucket, err)
failed = true
}
}
if failed {
os.Exit(1)
}
}
func deleteBucket(svc *s3.S3, bucket string) error {
bucketName := &bucket
objs, err := svc.ListObjects(&s3.ListObjectsInput{Bucket: bucketName})
if err != nil {
return fmt.Errorf("failed to list bucket %q objects, %v", bucketName, err)
}
for _, o := range objs.Contents {
svc.DeleteObject(&s3.DeleteObjectInput{Bucket: bucketName, Key: o.Key})
}
uploads, err := svc.ListMultipartUploads(&s3.ListMultipartUploadsInput{Bucket: bucketName})
if err != nil {
return fmt.Errorf("failed to list bucket %q multipart objects, %v", bucketName, err)
}
for _, u := range uploads.Uploads {
svc.AbortMultipartUpload(&s3.AbortMultipartUploadInput{
Bucket: bucketName,
Key: u.Key,
UploadId: u.UploadId,
})
}
_, err = svc.DeleteBucket(&s3.DeleteBucketInput{Bucket: bucketName})
if err != nil {
return fmt.Errorf("failed to delete bucket %q, %v", bucketName, err)
}
return nil
}

View File

@ -0,0 +1,27 @@
// +build integration
package s3manager
import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/awstesting/integration"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
)
func TestGetBucketRegion(t *testing.T) {
expectRegion := aws.StringValue(integration.Session.Config.Region)
ctx := aws.BackgroundContext()
region, err := s3manager.GetBucketRegion(ctx, integration.Session,
aws.StringValue(bucketName), expectRegion)
if err != nil {
t.Fatalf("expect no error, got %v", err)
}
if e, a := expectRegion, region; e != a {
t.Errorf("expect %s bucket region, got %s", e, a)
}
}

View File

@ -1,6 +1,6 @@
// +build integration
// Package s3manager provides
// Package s3manager provides integration tests for the service/s3/s3manager package
package s3manager
import (
@ -9,12 +9,13 @@ import (
"fmt"
"io"
"os"
"regexp"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/awstesting/integration"
"github.com/aws/aws-sdk-go/service/s3"
@ -26,45 +27,64 @@ var integMD512MB = fmt.Sprintf("%x", md5.Sum(integBuf12MB))
var bucketName *string
func TestMain(m *testing.M) {
setup()
defer teardown() // only called if we panic
result := m.Run()
teardown()
if err := setup(); err != nil {
panic(fmt.Sprintf("failed to setup integration test, %v", err))
}
var result int
defer func() {
if err := teardown(); err != nil {
fmt.Fprintf(os.Stderr, "teardown failed, %v", err)
}
if r := recover(); r != nil {
fmt.Println("S3Manager integration test hit a panic,", r)
result = 1
}
os.Exit(result)
}()
result = m.Run()
}
func setup() {
// Create a bucket for testing
func setup() error {
svc := s3.New(integration.Session)
// Create a bucket for testing
bucketName = aws.String(
fmt.Sprintf("aws-sdk-go-integration-%d-%s", time.Now().Unix(), integration.UniqueID()))
for i := 0; i < 10; i++ {
_, err := svc.CreateBucket(&s3.CreateBucketInput{Bucket: bucketName})
if err == nil {
break
}
if err != nil {
return fmt.Errorf("failed to create bucket %q, %v", *bucketName, err)
}
for {
_, err := svc.HeadBucket(&s3.HeadBucketInput{Bucket: bucketName})
if err == nil {
break
}
time.Sleep(1 * time.Second)
err = svc.WaitUntilBucketExists(&s3.HeadBucketInput{Bucket: bucketName})
if err != nil {
return fmt.Errorf("failed to wait for bucket %q to exist, %v", bucketName, err)
}
return nil
}
// Delete the bucket
func teardown() {
func teardown() error {
svc := s3.New(integration.Session)
objs, _ := svc.ListObjects(&s3.ListObjectsInput{Bucket: bucketName})
objs, err := svc.ListObjects(&s3.ListObjectsInput{Bucket: bucketName})
if err != nil {
return fmt.Errorf("failed to list bucket %q objects, %v", bucketName, err)
}
for _, o := range objs.Contents {
svc.DeleteObject(&s3.DeleteObjectInput{Bucket: bucketName, Key: o.Key})
}
uploads, _ := svc.ListMultipartUploads(&s3.ListMultipartUploadsInput{Bucket: bucketName})
uploads, err := svc.ListMultipartUploads(&s3.ListMultipartUploadsInput{Bucket: bucketName})
if err != nil {
return fmt.Errorf("failed to list bucket %q multipart objects, %v", bucketName, err)
}
for _, u := range uploads.Uploads {
svc.AbortMultipartUpload(&s3.AbortMultipartUploadInput{
Bucket: bucketName,
@ -73,7 +93,12 @@ func teardown() {
})
}
svc.DeleteBucket(&s3.DeleteBucketInput{Bucket: bucketName})
_, err = svc.DeleteBucket(&s3.DeleteBucketInput{Bucket: bucketName})
if err != nil {
return fmt.Errorf("failed to delete bucket %q, %v", bucketName, err)
}
return nil
}
type dlwriter struct {
@ -106,8 +131,12 @@ func validate(t *testing.T, key string, md5value string) {
w := newDLWriter(1024 * 1024 * 20)
n, err := mgr.Download(w, params)
assert.NoError(t, err)
assert.Equal(t, md5value, fmt.Sprintf("%x", md5.Sum(w.buf[0:n])))
if err != nil {
t.Fatalf("expect no error, got %v", err)
}
if e, a := md5value, fmt.Sprintf("%x", md5.Sum(w.buf[0:n])); e != a {
t.Errorf("expect %s md5 value, got %s", e, a)
}
}
func TestUploadConcurrently(t *testing.T) {
@ -119,9 +148,17 @@ func TestUploadConcurrently(t *testing.T) {
Body: bytes.NewReader(integBuf12MB),
})
assert.NoError(t, err)
assert.NotEqual(t, "", out.UploadID)
assert.Regexp(t, `^https?://.+/`+key+`$`, out.Location)
if err != nil {
t.Fatalf("expect no error, got %v", err)
}
if len(out.UploadID) == 0 {
t.Errorf("expect upload ID but was empty")
}
re := regexp.MustCompile(`^https?://.+/` + key + `$`)
if e, a := re.String(), out.Location; !re.MatchString(a) {
t.Errorf("expect %s to match URL regexp %q, did not", e, a)
}
validate(t, key, integMD512MB)
}
@ -149,15 +186,25 @@ func TestUploadFailCleanup(t *testing.T) {
Key: &key,
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()
if err == nil {
t.Fatalf("expect error, but did not get one")
}
aerr := err.(awserr.Error)
if e, a := "MissingRegion", aerr.Code(); strings.Contains(a, e) {
t.Errorf("expect %q to not be in error code %q", e, a)
}
uploadID := ""
merr := err.(s3manager.MultiUploadFailure)
if uploadID = merr.UploadID(); len(uploadID) == 0 {
t.Errorf("expect upload ID to not be empty, but was")
}
assert.NotEmpty(t, uploadID)
_, err = svc.ListParts(&s3.ListPartsInput{
Bucket: bucketName, Key: &key, UploadId: &uploadID})
assert.Error(t, err)
Bucket: bucketName, Key: &key, UploadId: &uploadID,
})
if err == nil {
t.Errorf("expect error for list parts, but got none")
}
}

View File

@ -2,6 +2,7 @@ package awstesting
import (
"io"
"time"
"github.com/aws/aws-sdk-go/private/util"
)
@ -65,3 +66,29 @@ func (r *ReadCloser) Close() error {
func SortedKeys(m map[string]interface{}) []string {
return util.SortedKeys(m)
}
// A FakeContext provides a simple stub implementation of a Context
type FakeContext struct {
Error error
DoneCh chan struct{}
}
// Deadline always will return not set
func (c *FakeContext) Deadline() (deadline time.Time, ok bool) {
return time.Time{}, false
}
// Done returns a read channel for listening to the Done event
func (c *FakeContext) Done() <-chan struct{} {
return c.DoneCh
}
// Err returns the error, is nil if not set.
func (c *FakeContext) Err() error {
return c.Error
}
// Value ignores the Value and always returns nil
func (c *FakeContext) Value(key interface{}) interface{} {
return nil
}

View File

@ -16,6 +16,18 @@
<script type="text/javascript" src="/sdk-for-go/api/lib/godoc/jquery.treeview.js"></script>
<script type="text/javascript" src="/sdk-for-go/api/lib/godoc/jquery.treeview.edit.js"></script>
<script type="text/javascript" src="https://media.amazonwebservices.com/js/sitecatalyst/s_code.min.js"></script>
<script type="text/javascript">
// Documentation Service Name
s.prop66 = 'AWS SDK for Go';
s.eVar66 = 'D=c66';
// Documentation Guide Name
s.prop65 = 'API Reference';
s.eVar65 = 'D=c65';
var s_code = s.t();
if (s_code) document.write(s_code);
</script>
<script>
((window.gitter = {}).chat = {}).options = {
room: 'aws/aws-sdk-go'

View File

@ -77,7 +77,9 @@
{{ if (not (is_paginator .)) }}
{{ if (ne .Name "Validate") }}
{{$name_html := html .Name}}
{{ if not (is_op_deprecated $.PDoc.Name .Name) -}}
<dd><a href="#{{$tname_html}}.{{$name_html}}">{{client_html $ .Decl false | sanitize}}</a></dd>
{{ end -}}
{{end}}
{{end}}
{{end}}
@ -254,7 +256,11 @@
{{range .Methods}}
{{$name_html := html .Name}}
{{ if is_op_deprecated $.PDoc.Name .Name -}}
<h3 id="{{$tname_html}}.{{$name_html}}">func ({{html .Recv}}) <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a><div class="deprecated">Deprecated</div></h3>
{{ else }}
<h3 id="{{$tname_html}}.{{$name_html}}">func ({{html .Recv}}) <a href="{{posLink_url $ .Decl}}">{{$name_html}}</a></h3>
{{ end -}}
<pre>{{node_html $ .Decl true}}</pre>
{{comment_html .Doc}}
{{$name := printf "%s_%s" $tname .Name}}

View File

@ -3,11 +3,18 @@
overflow:hidden;
}
a > img {
max-height:70%;
float:left;
padding-left:22px;
padding-top:8px;
div.deprecated {
background-color: #a39f9f;
border-radius: 5px;
font-weight: bold;
display: inline;
padding: 2px;
overflow: auto;
color: #ffffff;
font-family: "Georgia", Times, serif;
text-align: center;
font-size: small;
margin-left: 5px;
}
.packages {
@ -758,13 +765,6 @@ a.error {
padding: 10px;
}
a > img {
max-height:100%;
float:left;
padding-left:10px;
padding-top:2px;
}
div#mobile-nav {
display:inline-block;
float:right;

405
vendor/github.com/aws/aws-sdk-go/doc.go generated vendored Normal file
View File

@ -0,0 +1,405 @@
// Package sdk is the official AWS SDK for the Go programming language.
//
// The AWS SDK for Go provides APIs and utilities that developers can use to
// build Go applications that use AWS services, such as Amazon Elastic Compute
// Cloud (Amazon EC2) and Amazon Simple Storage Service (Amazon S3).
//
// The SDK removes the complexity of coding directly against a web service
// interface. It hides a lot of the lower-level plumbing, such as authentication,
// request retries, and error handling.
//
// The SDK also includes helpful utilities on top of the AWS APIs that add additional
// capabilities and functionality. For example, the Amazon S3 Download and Upload
// Manager will automatically split up large objects into multiple parts and
// transfer them concurrently.
//
// See the s3manager package documentation for more information.
// https://docs.aws.amazon.com/sdk-for-go/api/service/s3/s3manager/
//
// Getting More Information
//
// Checkout the Getting Started Guide and API Reference Docs detailed the SDK's
// components and details on each AWS client the SDK supports.
//
// The Getting Started Guide provides examples and detailed description of how
// to get setup with the SDK.
// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/welcome.html
//
// The API Reference Docs include a detailed breakdown of the SDK's components
// such as utilities and AWS clients. Use this as a reference of the Go types
// included with the SDK, such as AWS clients, API operations, and API parameters.
// https://docs.aws.amazon.com/sdk-for-go/api/
//
// Overview of SDK's Packages
//
// The SDK is composed of two main components, SDK core, and service clients.
// The SDK core packages are all available under the aws package at the root of
// the SDK. Each client for a supported AWS service is available within its own
// package under the service folder at the root of the SDK.
//
// * aws - SDK core, provides common shared types such as Config, Logger,
// and utilities to make working with API parameters easier.
//
// * awserr - Provides the error interface that the SDK will use for all
// errors that occur in the SDK's processing. This includes service API
// response errors as well. The Error type is made up of a code and message.
// Cast the SDK's returned error type to awserr.Error and call the Code
// method to compare returned error to specific error codes. See the package's
// documentation for additional values that can be extracted such as RequestId.
//
// * credentials - Provides the types and built in credentials providers
// the SDK will use to retrieve AWS credentials to make API requests with.
// Nested under this folder are also additional credentials providers such as
// stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles.
//
// * endpoints - Provides the AWS Regions and Endpoints metadata for the SDK.
// Use this to lookup AWS service endpoint information such as which services
// are in a region, and what regions a service is in. Constants are also provided
// for all region identifiers, e.g UsWest2RegionID for "us-west-2".
//
// * session - Provides initial default configuration, and load
// configuration from external sources such as environment and shared
// credentials file.
//
// * request - Provides the API request sending, and retry logic for the SDK.
// This package also includes utilities for defining your own request
// retryer, and configuring how the SDK processes the request.
//
// * service - Clients for AWS services. All services supported by the SDK are
// available under this folder.
//
// How to Use the SDK's AWS Service Clients
//
// The SDK includes the Go types and utilities you can use to make requests to
// AWS service APIs. Within the service folder at the root of the SDK you'll find
// a package for each AWS service the SDK supports. All service clients follows
// a common pattern of creation and usage.
//
// When creating a client for an AWS service you'll first need to have a Session
// value constructed. The Session provides shared configuration that can be shared
// between your service clients. When service clients are created you can pass
// in additional configuration via the aws.Config type to override configuration
// provided by in the Session to create service client instances with custom
// configuration.
//
// Once the service's client is created you can use it to make API requests the
// AWS service. These clients are safe to use concurrently.
//
// Configuring the SDK
//
// In the AWS SDK for Go, you can configure settings for service clients, such
// as the log level and maximum number of retries. Most settings are optional;
// however, for each service client, you must specify a region and your credentials.
// The SDK uses these values to send requests to the correct AWS region and sign
// requests with the correct credentials. You can specify these values as part
// of a session or as environment variables.
//
// See the SDK's configuration guide for more information.
// https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html
//
// See the session package documentation for more information on how to use Session
// with the SDK.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/session/
//
// See the Config type in the aws package for more information on configuration
// options.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
//
// Configuring Credentials
//
// When using the SDK you'll generally need your AWS credentials to authenticate
// with AWS services. The SDK supports multiple methods of supporting these
// credentials. By default the SDK will source credentials automatically from
// its default credential chain. See the session package for more information
// on this chain, and how to configure it. The common items in the credential
// chain are the following:
//
// * Environment Credentials - Set of environment variables that are useful
// when sub processes are created for specific roles.
//
// * Shared Credentials file (~/.aws/credentials) - This file stores your
// credentials based on a profile name and is useful for local development.
//
// * EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials
// to application running on an EC2 instance. This removes the need to manage
// credential files in production.
//
// Credentials can be configured in code as well by setting the Config's Credentials
// value to a custom provider or using one of the providers included with the
// SDK to bypass the default credential chain and use a custom one. This is
// helpful when you want to instruct the SDK to only use a specific set of
// credentials or providers.
//
// This example creates a credential provider for assuming an IAM role, "myRoleARN"
// and configures the S3 service client to use that role for API requests.
//
// // Initial credentials loaded from SDK's default credential chain. Such as
// // the environment, shared credentials (~/.aws/credentials), or EC2 Instance
// // Role. These credentials will be used to to make the STS Assume Role API.
// sess := session.Must(session.NewSession())
//
// // Create the credentials from AssumeRoleProvider to assume the role
// // referenced by the "myRoleARN" ARN.
// creds := stscreds.NewCredentials(sess, "myRoleArn")
//
// // Create service client value configured for credentials
// // from assumed role.
// svc := s3.New(sess, &aws.Config{Credentials: creds})/
//
// See the credentials package documentation for more information on credential
// providers included with the SDK, and how to customize the SDK's usage of
// credentials.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials
//
// The SDK has support for the shared configuration file (~/.aws/config). This
// support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1",
// or enabling the feature in code when creating a Session via the
// Option's SharedConfigState parameter.
//
// sess := session.Must(session.NewSessionWithOptions(session.Options{
// SharedConfigState: session.SharedConfigEnable,
// }))
//
// Configuring AWS Region
//
// In addition to the credentials you'll need to specify the region the SDK
// will use to make AWS API requests to. In the SDK you can specify the region
// either with an environment variable, or directly in code when a Session or
// service client is created. The last value specified in code wins if the region
// is specified multiple ways.
//
// To set the region via the environment variable set the "AWS_REGION" to the
// region you want to the SDK to use. Using this method to set the region will
// allow you to run your application in multiple regions without needing additional
// code in the application to select the region.
//
// AWS_REGION=us-west-2
//
// The endpoints package includes constants for all regions the SDK knows. The
// values are all suffixed with RegionID. These values are helpful, because they
// reduce the need to type the region string manually.
//
// To set the region on a Session use the aws package's Config struct parameter
// Region to the AWS region you want the service clients created from the session to
// use. This is helpful when you want to create multiple service clients, and
// all of the clients make API requests to the same region.
//
// sess := session.Must(session.NewSession(&aws.Config{
// Region: aws.String(endpoints.UsWest2RegionID),
// }))
//
// See the endpoints package for the AWS Regions and Endpoints metadata.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/
//
// In addition to setting the region when creating a Session you can also set
// the region on a per service client bases. This overrides the region of a
// Session. This is helpful when you want to create service clients in specific
// regions different from the Session's region.
//
// svc := s3.New(sess, &aws.Config{
// Region: aws.String(ednpoints.UsWest2RegionID),
// })
//
// See the Config type in the aws package for more information and additional
// options such as setting the Endpoint, and other service client configuration options.
// https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
//
// Making API Requests
//
// Once the client is created you can make an API request to the service.
// Each API method takes a input parameter, and returns the service response
// and an error. The SDK provides methods for making the API call in multiple ways.
//
// In this list we'll use the S3 ListObjects API as an example for the different
// ways of making API requests.
//
// * ListObjects - Base API operation that will make the API request to the service.
//
// * ListObjectsRequest - API methods suffixed with Request will construct the
// API request, but not send it. This is also helpful when you want to get a
// presigned URL for a request, and share the presigned URL instead of your
// application making the request directly.
//
// * ListObjectsPages - Same as the base API operation, but uses a callback to
// automatically handle pagination of the API's response.
//
// * ListObjectsWithContext - Same as base API operation, but adds support for
// the Context pattern. This is helpful for controlling the canceling of in
// flight requests. See the Go standard library context package for more
// information. This method also takes request package's Option functional
// options as the variadic argument for modifying how the request will be
// made, or extracting information from the raw HTTP response.
//
// * ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for
// the Context pattern. Similar to ListObjectsWithContext this method also
// takes the request package's Option function option types as the variadic
// argument.
//
// In addition to the API operations the SDK also includes several higher level
// methods that abstract checking for and waiting for an AWS resource to be in
// a desired state. In this list we'll use WaitUntilBucketExists to demonstrate
// the different forms of waiters.
//
// * WaitUntilBucketExists. - Method to make API request to query an AWS service for
// a resource's state. Will return successfully when that state is accomplished.
//
// * WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds
// support for the Context pattern. In addition these methods take request
// package's WaiterOptions to configure the waiter, and how underlying request
// will be made by the SDK.
//
// The API method will document which error codes the service might return for
// the operation. These errors will also be available as const strings prefixed
// with "ErrCode" in the service client's package. If there are no errors listed
// in the API's SDK documentation you'll need to consult the AWS service's API
// documentation for the errors that could be returned.
//
// ctx := context.Background()
//
// result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
// Bucket: aws.String("my-bucket"),
// Key: aws.String("my-key"),
// })
// if err != nil {
// // Cast err to awserr.Error to handle specific error codes.
// aerr, ok := err.(awserr.Error)
// if ok && aerr.Code() == s3.ErrCodeNoSuchKey {
// // Specific error code handling
// }
// return err
// }
//
// // Make sure to close the body when done with it for S3 GetObject APIs or
// // will leak connections.
// defer result.Body.Close()
//
// fmt.Println("Object Size:", aws.StringValue(result.ContentLength))
//
// API Request Pagination and Resource Waiters
//
// Pagination helper methods are suffixed with "Pages", and provide the
// functionality needed to round trip API page requests. Pagination methods
// take a callback function that will be called for each page of the API's response.
//
// objects := []string{}
// err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{
// Bucket: aws.String(myBucket),
// }, func(p *s3.ListObjectsOutput, lastPage bool) bool {
// for _, o := range p.Contents {
// objects = append(objects, aws.StringValue(o.Key))
// }
// return true // continue paging
// })
// if err != nil {
// panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err))
// }
//
// fmt.Println("Objects in bucket:", objects)
//
// Waiter helper methods provide the functionality to wait for an AWS resource
// state. These methods abstract the logic needed to to check the state of an
// AWS resource, and wait until that resource is in a desired state. The waiter
// will block until the resource is in the state that is desired, an error occurs,
// or the waiter times out. If a resource times out the error code returned will
// be request.WaiterResourceNotReadyErrorCode.
//
// err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{
// Bucket: aws.String(myBucket),
// })
// if err != nil {
// aerr, ok := err.(awserr.Error)
// if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode {
// fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist")
// }
// panic(fmt.Errorf("failed to wait for bucket to exist, %v", err))
// }
// fmt.Println("Bucket", myBucket, "exists")
//
// Complete SDK Example
//
// This example shows a complete working Go file which will upload a file to S3
// and use the Context pattern to implement timeout logic that will cancel the
// request if it takes too long. This example highlights how to use sessions,
// create a service client, make a request, handle the error, and process the
// response.
//
// package main
//
// import (
// "context"
// "flag"
// "fmt"
// "os"
// "time"
//
// "github.com/aws/aws-sdk-go/aws"
// "github.com/aws/aws-sdk-go/aws/awserr"
// "github.com/aws/aws-sdk-go/aws/request"
// "github.com/aws/aws-sdk-go/aws/session"
// "github.com/aws/aws-sdk-go/service/s3"
// )
//
// // Uploads a file to S3 given a bucket and object key. Also takes a duration
// // value to terminate the update if it doesn't complete within that time.
// //
// // The AWS Region needs to be provided in the AWS shared config or on the
// // environment variable as `AWS_REGION`. Credentials also must be provided
// // Will default to shared config file, but can load from environment if provided.
// //
// // Usage:
// // # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
// // go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
// func main() {
// var bucket, key string
// var timeout time.Duration
//
// flag.StringVar(&bucket, "b", "", "Bucket name.")
// flag.StringVar(&key, "k", "", "Object key name.")
// flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
// flag.Parse()
//
// // All clients require a Session. The Session provides the client with
// // shared configuration such as region, endpoint, and credentials. A
// // Session should be shared where possible to take advantage of
// // configuration and credential caching. See the session package for
// // more information.
// sess := session.Must(session.NewSession())
//
// // Create a new instance of the service's client with a Session.
// // Optional aws.Config values can also be provided as variadic arguments
// // to the New function. This option allows you to provide service
// // specific configuration.
// svc := s3.New(sess)
//
// // Create a context with a timeout that will abort the upload if it takes
// // more than the passed in timeout.
// ctx := context.Background()
// var cancelFn func()
// if timeout > 0 {
// ctx, cancelFn = context.WithTimeout(ctx, timeout)
// }
// // Ensure the context is canceled to prevent leaking.
// // See context package for more information, https://golang.org/pkg/context/
// defer cancelFn()
//
// // Uploads the object to S3. The Context will interrupt the request if the
// // timeout expires.
// _, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
// Bucket: aws.String(bucket),
// Key: aws.String(key),
// Body: os.Stdin,
// })
// if err != nil {
// if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
// // If the SDK can determine the request or retry delay was canceled
// // by a context the CanceledErrorCode error code will be returned.
// fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
// } else {
// fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
// }
// os.Exit(1)
// }
//
// fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
// }
package sdk

View File

@ -3,4 +3,12 @@ Custom Endpoint Example
This example provides examples on how you can provide custom endpoints, and logic to how endpoints are resolved by the SDK.
The example creates multiple clients with different endpoint configuraiton. From a custom endpoint resolver that wraps the defeault resolver so that any S3 service client created uses the custom endpoint, to how you can provide your own logic to a single service's endpoint resolving.
The example creates multiple clients with different endpoint configuration. From a custom endpoint resolver that wraps the default resolver so that any Amazon S3 service client created uses the custom endpoint, to how you can provide your own logic to a single service's endpoint resolving.
Usage
---
```sh
go run -tags example customeEndpoint.go
```

View File

@ -1,7 +1,7 @@
Enumerate Regions and Endpoints Example
===
Demostrates how the SDK's endpoints can be enumerated over to discover regions, services, and endpoints defined by the SDK's Regions and Endpoints metadata.
Demonstrates how the SDK's endpoints can be enumerated over to discover regions, services, and endpoints defined by the SDK's Regions and Endpoints metadata.
Usage
---
@ -10,7 +10,7 @@ The following parameters can be used to enumerate the SDK's partition metadata.
Example:
go run enumEndpoints.go -p aws -services -r us-west-2
go run -tags example enumEndpoints.go -p aws -services -r us-west-2
Output:

View File

@ -0,0 +1,13 @@
# Example
Uploads a file to S3 given a bucket and object key. Also takes a duration
value to terminate the update if it doesn't complete within that time.
The AWS Region needs to be provided in the AWS shared config or on the
environment variable as `AWS_REGION`. Credentials also must be provided
Will default to shared config file, but can load from environment if provided.
## Usage:
# Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
go run -tags example withContext.go -b mybucket -k myKey -d 10m < myfile.txt

View File

@ -0,0 +1,71 @@
// +build example,go1.7
package main
import (
"context"
"flag"
"fmt"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
// Uploads a file to S3 given a bucket and object key. Also takes a duration
// value to terminate the update if it doesn't complete within that time.
//
// The AWS Region needs to be provided in the AWS shared config or on the
// environment variable as `AWS_REGION`. Credentials also must be provided
// Will default to shared config file, but can load from environment if provided.
//
// Usage:
// # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
// go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
func main() {
var bucket, key string
var timeout time.Duration
flag.StringVar(&bucket, "b", "", "Bucket name.")
flag.StringVar(&key, "k", "", "Object key name.")
flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
flag.Parse()
sess := session.Must(session.NewSession())
svc := s3.New(sess)
// Create a context with a timeout that will abort the upload if it takes
// more than the passed in timeout.
ctx := context.Background()
var cancelFn func()
if timeout > 0 {
ctx, cancelFn = context.WithTimeout(ctx, timeout)
}
// Ensure the context is canceled to prevent leaking.
// See context package for more information, https://golang.org/pkg/context/
defer cancelFn()
// Uploads the object to S3. The Context will interrupt the request if the
// timeout expires.
_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: os.Stdin,
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
// If the SDK can determine the request or retry delay was canceled
// by a context the CanceledErrorCode error code will be returned.
fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
} else {
fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
}
os.Exit(1)
}
fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
}

View File

@ -13,6 +13,7 @@ type Item struct {
Data map[string]interface{}
}
```
Use Go tags to define what the name is of the attribute in your DynamoDB table. See [AWS SDK for Go API Reference: Marshal](https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/dynamodbattribute/#Marshal) for more information.
In DynamoDB the structure of the item to be returned will be:
```json
@ -28,7 +29,7 @@ In DynamoDB the structure of the item to be returned will be:
## Usage
`scanItems.go -table "<table_name>" -region "<optional_region>"`
`go run -tags example scanItems.go -table "<table_name>" -region "<optional_region>"`
## Output

View File

@ -6,6 +6,7 @@ methods connecting to DynamoDB, or as `unitTest` demonstrates, create your own
## Test-compatible DynamoDB field
If you use `*dynamodb.DynamoDB` as a field, you will be unable to unit test it,
as documented in #88. Cast it instead as `dynamodbiface.DynamoDBAPI`:
```go
type ItemGetter struct {
DynamoDB dynamodbiface.DynamoDBAPI
@ -14,6 +15,7 @@ type ItemGetter struct {
## Querying actual DynamoDB
You'll need an `*aws.Config` and `*session.Session` for these to work correctly:
```go
// Setup
var getter = new(ItemGetter)
@ -30,6 +32,7 @@ Construct a `fakeDynamoDB` and add the necessary methods for each of those
structs (custom ones for `ItemGetter` and [whatever methods you're using for
DynamoDB](https://github.com/aws/aws-sdk-go/blob/master/service/dynamodb/dynamodbiface/interface.go)),
and you're good to go!
```go
type fakeDynamoDB struct {
dynamodbiface.DynamoDBAPI
@ -42,7 +45,7 @@ getter.DynamoDB.GetItem(/* ... */)
## Output
```
$ go test -cover
$ go test -tags example -cover
PASS
coverage: 100.0% of statements
ok _/Users/shatil/workspace/aws-sdk-go/example/service/dynamodb/unitTest 0.008s

View File

@ -1,11 +1,11 @@
# Example
filter_ec2_by_tag is an example using the AWS SDK for Go to list ec2 instaces that match provided tag name filter.
This is an example using the AWS SDK for Go to list ec2 instances that match provided tag name filter.
# Usage
The example uses the the bucket name provided, and lists all object keys in a bucket.
The example uses the bucket name provided, and lists all object keys in a bucket.
```sh
go run -tags example filter_ec2_by_tag.go <name_filter>

View File

@ -1,13 +1,13 @@
# Example
concatObjects is an example using the AWS SDK for Go to concatenate two objects together.
This is an example using the AWS SDK for Go to concatenate two objects together.
We use `UploadPartCopy` which uses an object for a part. Here in this example we have two parts, or in other words
two objects that we want to concatenate together.
# Usage
The example uses the the bucket name provided, two keys for each object, and lastly the output key.
The example uses the bucket name provided, two keys for each object, and lastly the output key.
```sh
AWS_REGION=<region> go run -tags example concatenateObjects.go <bucket> <key for object 1> <key for object 2> <key for output>

View File

@ -1,11 +1,11 @@
# Example
listObjects is an example using the AWS SDK for Go to list objects' key in a S3 bucket.
This is an example using the AWS SDK for Go to list objects' key in a S3 bucket.
# Usage
The example uses the the bucket name provided, and lists all object keys in a bucket.
The example uses the bucket name provided, and lists all object keys in a bucket.
```sh
go run -tags example listObjects.go <bucket>

View File

@ -1,6 +1,6 @@
## Example
listObjectsConcurrentlv is an example using the AWS SDK for Go concurrently to list the encrypted objects in the S3 buckets owned by an account.
This is an example using the AWS SDK for Go concurrently to list the encrypted objects in the S3 buckets owned by an account.
## Usage

View File

@ -1,3 +1,5 @@
// +build example
package main
import (

View File

@ -1,9 +1,9 @@
# Example
This example shows how the SDK's API interfaces can be used by your code intead of the concrete service client type directly. Using this pattern allows you to mock out your code's usage of the SDK's service client for testing.
This example shows how the SDK's API interfaces can be used by your code instead of the concrete service client type directly. Using this pattern allows you to mock out your code's usage of the SDK's service client for testing.
# Usage
Use the `go test` tool to verify the `Queue` type's `GetMessages` function correctly unmarshals the SQS message responses.
`go test ./`
`go test -tags example ifaceExample.go`

View File

@ -1,3 +1,5 @@
// +build example
package main
import (

View File

@ -1,3 +1,5 @@
// +build example
package main
import (

View File

@ -150,6 +150,23 @@
{"shape":"TooManyRequestsException"}
]
},
"CreateRequestValidator":{
"name":"CreateRequestValidator",
"http":{
"method":"POST",
"requestUri":"/restapis/{restapi_id}/requestvalidators",
"responseCode":201
},
"input":{"shape":"CreateRequestValidatorRequest"},
"output":{"shape":"RequestValidator"},
"errors":[
{"shape":"BadRequestException"},
{"shape":"UnauthorizedException"},
{"shape":"NotFoundException"},
{"shape":"LimitExceededException"},
{"shape":"TooManyRequestsException"}
]
},
"CreateResource":{
"name":"CreateResource",
"http":{
@ -435,6 +452,22 @@
{"shape":"ConflictException"}
]
},
"DeleteRequestValidator":{
"name":"DeleteRequestValidator",
"http":{
"method":"DELETE",
"requestUri":"/restapis/{restapi_id}/requestvalidators/{requestvalidator_id}",
"responseCode":202
},
"input":{"shape":"DeleteRequestValidatorRequest"},
"errors":[
{"shape":"UnauthorizedException"},
{"shape":"NotFoundException"},
{"shape":"TooManyRequestsException"},
{"shape":"BadRequestException"},
{"shape":"ConflictException"}
]
},
"DeleteResource":{
"name":"DeleteResource",
"http":{
@ -917,6 +950,35 @@
{"shape":"TooManyRequestsException"}
]
},
"GetRequestValidator":{
"name":"GetRequestValidator",
"http":{
"method":"GET",
"requestUri":"/restapis/{restapi_id}/requestvalidators/{requestvalidator_id}"
},
"input":{"shape":"GetRequestValidatorRequest"},
"output":{"shape":"RequestValidator"},
"errors":[
{"shape":"UnauthorizedException"},
{"shape":"NotFoundException"},
{"shape":"TooManyRequestsException"}
]
},
"GetRequestValidators":{
"name":"GetRequestValidators",
"http":{
"method":"GET",
"requestUri":"/restapis/{restapi_id}/requestvalidators"
},
"input":{"shape":"GetRequestValidatorsRequest"},
"output":{"shape":"RequestValidators"},
"errors":[
{"shape":"BadRequestException"},
{"shape":"UnauthorizedException"},
{"shape":"NotFoundException"},
{"shape":"TooManyRequestsException"}
]
},
"GetResource":{
"name":"GetResource",
"http":{
@ -1515,6 +1577,21 @@
{"shape":"TooManyRequestsException"}
]
},
"UpdateRequestValidator":{
"name":"UpdateRequestValidator",
"http":{
"method":"PATCH",
"requestUri":"/restapis/{restapi_id}/requestvalidators/{requestvalidator_id}"
},
"input":{"shape":"UpdateRequestValidatorRequest"},
"output":{"shape":"RequestValidator"},
"errors":[
{"shape":"UnauthorizedException"},
{"shape":"NotFoundException"},
{"shape":"BadRequestException"},
{"shape":"TooManyRequestsException"}
]
},
"UpdateResource":{
"name":"UpdateResource",
"http":{
@ -1902,6 +1979,20 @@
"contentType":{"shape":"String"}
}
},
"CreateRequestValidatorRequest":{
"type":"structure",
"required":["restApiId"],
"members":{
"restApiId":{
"shape":"String",
"location":"uri",
"locationName":"restapi_id"
},
"name":{"shape":"String"},
"validateRequestBody":{"shape":"Boolean"},
"validateRequestParameters":{"shape":"Boolean"}
}
},
"CreateResourceRequest":{
"type":"structure",
"required":[
@ -2243,6 +2334,25 @@
}
}
},
"DeleteRequestValidatorRequest":{
"type":"structure",
"required":[
"restApiId",
"requestValidatorId"
],
"members":{
"restApiId":{
"shape":"String",
"location":"uri",
"locationName":"restapi_id"
},
"requestValidatorId":{
"shape":"String",
"location":"uri",
"locationName":"requestvalidator_id"
}
}
},
"DeleteResourceRequest":{
"type":"structure",
"required":[
@ -2671,6 +2781,11 @@
"shape":"String",
"location":"uri",
"locationName":"deployment_id"
},
"embed":{
"shape":"ListOfString",
"location":"querystring",
"locationName":"embed"
}
}
},
@ -3026,6 +3141,46 @@
}
}
},
"GetRequestValidatorRequest":{
"type":"structure",
"required":[
"restApiId",
"requestValidatorId"
],
"members":{
"restApiId":{
"shape":"String",
"location":"uri",
"locationName":"restapi_id"
},
"requestValidatorId":{
"shape":"String",
"location":"uri",
"locationName":"requestvalidator_id"
}
}
},
"GetRequestValidatorsRequest":{
"type":"structure",
"required":["restApiId"],
"members":{
"restApiId":{
"shape":"String",
"location":"uri",
"locationName":"restapi_id"
},
"position":{
"shape":"String",
"location":"querystring",
"locationName":"position"
},
"limit":{
"shape":"NullableInteger",
"location":"querystring",
"locationName":"limit"
}
}
},
"GetResourceRequest":{
"type":"structure",
"required":[
@ -3042,6 +3197,11 @@
"shape":"String",
"location":"uri",
"locationName":"resource_id"
},
"embed":{
"shape":"ListOfString",
"location":"querystring",
"locationName":"embed"
}
}
},
@ -3063,6 +3223,11 @@
"shape":"NullableInteger",
"location":"querystring",
"locationName":"limit"
},
"embed":{
"shape":"ListOfString",
"location":"querystring",
"locationName":"embed"
}
}
},
@ -3464,6 +3629,10 @@
"type":"list",
"member":{"shape":"PatchOperation"}
},
"ListOfRequestValidator":{
"type":"list",
"member":{"shape":"RequestValidator"}
},
"ListOfResource":{
"type":"list",
"member":{"shape":"Resource"}
@ -3562,6 +3731,7 @@
"authorizationType":{"shape":"String"},
"authorizerId":{"shape":"String"},
"apiKeyRequired":{"shape":"NullableBoolean"},
"requestValidatorId":{"shape":"String"},
"operationName":{"shape":"String"},
"requestParameters":{"shape":"MapOfStringToBoolean"},
"requestModels":{"shape":"MapOfStringToString"},
@ -3758,7 +3928,8 @@
"apiKeyRequired":{"shape":"Boolean"},
"operationName":{"shape":"String"},
"requestParameters":{"shape":"MapOfStringToBoolean"},
"requestModels":{"shape":"MapOfStringToString"}
"requestModels":{"shape":"MapOfStringToString"},
"requestValidatorId":{"shape":"String"}
}
},
"PutMethodResponseRequest":{
@ -3847,6 +4018,25 @@
"period":{"shape":"QuotaPeriodType"}
}
},
"RequestValidator":{
"type":"structure",
"members":{
"id":{"shape":"String"},
"name":{"shape":"String"},
"validateRequestBody":{"shape":"Boolean"},
"validateRequestParameters":{"shape":"Boolean"}
}
},
"RequestValidators":{
"type":"structure",
"members":{
"position":{"shape":"String"},
"items":{
"shape":"ListOfRequestValidator",
"locationName":"item"
}
}
},
"Resource":{
"type":"structure",
"members":{
@ -4381,6 +4571,26 @@
"patchOperations":{"shape":"ListOfPatchOperation"}
}
},
"UpdateRequestValidatorRequest":{
"type":"structure",
"required":[
"restApiId",
"requestValidatorId"
],
"members":{
"restApiId":{
"shape":"String",
"location":"uri",
"locationName":"restapi_id"
},
"requestValidatorId":{
"shape":"String",
"location":"uri",
"locationName":"requestvalidator_id"
},
"patchOperations":{"shape":"ListOfPatchOperation"}
}
},
"UpdateResourceRequest":{
"type":"structure",
"required":[

File diff suppressed because one or more lines are too long

View File

@ -367,7 +367,8 @@
"enum":[
"ecs:service:DesiredCount",
"ec2:spot-fleet-request:TargetCapacity",
"elasticmapreduce:instancegroup:InstanceCount"
"elasticmapreduce:instancegroup:InstanceCount",
"appstream:fleet:DesiredCapacity"
]
},
"ScalableTarget":{
@ -469,7 +470,8 @@
"enum":[
"ecs",
"elasticmapreduce",
"ec2"
"ec2",
"appstream"
]
},
"StepAdjustment":{

View File

@ -1,6 +1,6 @@
{
"version": "2.0",
"service": "<p>With Application Auto Scaling, you can automatically scale your AWS resources. The experience similar to that of <a href=\"https://aws.amazon.com/autoscaling/\">Auto Scaling</a>. You can use Application Auto Scaling to accomplish the following tasks:</p> <ul> <li> <p>Define scaling policies to automatically scale your AWS resources</p> </li> <li> <p>Scale your resources in response to CloudWatch alarms</p> </li> <li> <p>View the history of your scaling events</p> </li> </ul> <p>Application Auto Scaling can scale the following AWS resources:</p> <ul> <li> <p>Amazon ECS services. For more information, see <a href=\"http://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-auto-scaling.html\">Service Auto Scaling</a> in the <i>Amazon EC2 Container Service Developer Guide</i>.</p> </li> <li> <p>Amazon EC2 Spot fleets. For more information, see <a href=\"http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/fleet-auto-scaling.html\">Automatic Scaling for Spot Fleet</a> in the <i>Amazon EC2 User Guide</i>.</p> </li> <li> <p>Amazon EMR clusters. For more information, see <a href=\"http://docs.aws.amazon.com/ElasticMapReduce/latest/ManagementGuide/emr-automatic-scaling.html\">Using Automatic Scaling in Amazon EMR</a> in the <i>Amazon EMR Management Guide</i>.</p> </li> </ul> <p>For a list of supported regions, see <a href=\"http://docs.aws.amazon.com/general/latest/gr/rande.html#as-app_region\">AWS Regions and Endpoints: Application Auto Scaling</a> in the <i>AWS General Reference</i>.</p>",
"service": "<p>With Application Auto Scaling, you can automatically scale your AWS resources. The experience similar to that of <a href=\"https://aws.amazon.com/autoscaling/\">Auto Scaling</a>. You can use Application Auto Scaling to accomplish the following tasks:</p> <ul> <li> <p>Define scaling policies to automatically scale your AWS resources</p> </li> <li> <p>Scale your resources in response to CloudWatch alarms</p> </li> <li> <p>View the history of your scaling events</p> </li> </ul> <p>Application Auto Scaling can scale the following AWS resources:</p> <ul> <li> <p>Amazon ECS services. For more information, see <a href=\"http://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-auto-scaling.html\">Service Auto Scaling</a> in the <i>Amazon EC2 Container Service Developer Guide</i>.</p> </li> <li> <p>Amazon EC2 Spot fleets. For more information, see <a href=\"http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/fleet-auto-scaling.html\">Automatic Scaling for Spot Fleet</a> in the <i>Amazon EC2 User Guide</i>.</p> </li> <li> <p>Amazon EMR clusters. For more information, see <a href=\"http://docs.aws.amazon.com/ElasticMapReduce/latest/ManagementGuide/emr-automatic-scaling.html\">Using Automatic Scaling in Amazon EMR</a> in the <i>Amazon EMR Management Guide</i>.</p> </li> <li> <p>AppStream 2.0 fleets. For more information, see <a href=\"http://docs.aws.amazon.com/appstream2/latest/developerguide/autoscaling.html\">Autoscaling Amazon AppStream 2.0 Resources</a> in the <i>Amazon AppStream 2.0 Developer Guide</i>.</p> </li> </ul> <p>For a list of supported regions, see <a href=\"http://docs.aws.amazon.com/general/latest/gr/rande.html#as-app_region\">AWS Regions and Endpoints: Application Auto Scaling</a> in the <i>AWS General Reference</i>.</p>",
"operations": {
"DeleteScalingPolicy": "<p>Deletes the specified Application Auto Scaling scaling policy.</p> <p>Deleting a policy deletes the underlying alarm action, but does not delete the CloudWatch alarm associated with the scaling policy, even if it no longer has an associated action.</p> <p>To create a scaling policy or update an existing one, see <a>PutScalingPolicy</a>.</p>",
"DeregisterScalableTarget": "<p>Deregisters a scalable target.</p> <p>Deregistering a scalable target deletes the scaling policies that are associated with it.</p> <p>To create a scalable target or update an existing one, see <a>RegisterScalableTarget</a>.</p>",
@ -209,42 +209,42 @@
"base": null,
"refs": {
"DeleteScalingPolicyRequest$PolicyName": "<p>The name of the scaling policy.</p>",
"DeleteScalingPolicyRequest$ResourceId": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>",
"DeregisterScalableTargetRequest$ResourceId": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>",
"DescribeScalingActivitiesRequest$ResourceId": "<p>The identifier of the resource associated with the scaling activity. This string consists of the resource type and unique identifier. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>",
"DescribeScalingPoliciesRequest$ResourceId": "<p>The identifier of the resource associated with the scaling policy. This string consists of the resource type and unique identifier. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>",
"PutScalingPolicyRequest$ResourceId": "<p>The identifier of the resource associated with the scaling policy. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>",
"DeleteScalingPolicyRequest$ResourceId": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>",
"DeregisterScalableTargetRequest$ResourceId": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>",
"DescribeScalingActivitiesRequest$ResourceId": "<p>The identifier of the resource associated with the scaling activity. This string consists of the resource type and unique identifier. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>",
"DescribeScalingPoliciesRequest$ResourceId": "<p>The identifier of the resource associated with the scaling policy. This string consists of the resource type and unique identifier. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>",
"PutScalingPolicyRequest$ResourceId": "<p>The identifier of the resource associated with the scaling policy. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>",
"PutScalingPolicyResponse$PolicyARN": "<p>The Amazon Resource Name (ARN) of the resulting scaling policy.</p>",
"RegisterScalableTargetRequest$ResourceId": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>",
"RegisterScalableTargetRequest$ResourceId": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>",
"RegisterScalableTargetRequest$RoleARN": "<p>The ARN of an IAM role that allows Application Auto Scaling to modify the scalable target on your behalf. This parameter is required when you register a scalable target and optional when you update one.</p>",
"ResourceIdsMaxLen1600$member": null,
"ScalableTarget$ResourceId": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>",
"ScalableTarget$ResourceId": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>",
"ScalableTarget$RoleARN": "<p>The ARN of an IAM role that allows Application Auto Scaling to modify the scalable target on your behalf.</p>",
"ScalingActivity$ResourceId": "<p>The identifier of the resource associated with the scaling activity. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>",
"ScalingActivity$ResourceId": "<p>The identifier of the resource associated with the scaling activity. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>",
"ScalingPolicy$PolicyARN": "<p>The Amazon Resource Name (ARN) of the scaling policy.</p>",
"ScalingPolicy$ResourceId": "<p>The identifier of the resource associated with the scaling policy. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>"
"ScalingPolicy$ResourceId": "<p>The identifier of the resource associated with the scaling policy. This string consists of the resource type and unique identifier.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>"
}
},
"ResourceIdsMaxLen1600": {
"base": null,
"refs": {
"DescribeScalableTargetsRequest$ResourceIds": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> </ul>",
"DescribeScalableTargetsRequest$ResourceIds": "<p>The identifier of the resource associated with the scalable target. This string consists of the resource type and unique identifier. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p>ECS service - The resource type is <code>service</code> and the unique identifier is the cluster name and service name. Example: <code>service/default/sample-webapp</code>.</p> </li> <li> <p>Spot fleet request - The resource type is <code>spot-fleet-request</code> and the unique identifier is the Spot fleet request ID. Example: <code>spot-fleet-request/sfr-73fbd2ce-aa30-494c-8788-1cee4EXAMPLE</code>.</p> </li> <li> <p>EMR cluster - The resource type is <code>instancegroup</code> and the unique identifier is the cluster ID and instance group ID. Example: <code>instancegroup/j-2EEZNYKUA1NTV/ig-1791Y4E1L8YI0</code>.</p> </li> <li> <p>AppStream 2.0 fleet - The resource type is <code>fleet</code> and the unique identifier is the fleet name. Example: <code>fleet/sample-fleet</code>.</p> </li> </ul>",
"DescribeScalingPoliciesRequest$PolicyNames": "<p>The names of the scaling policies to describe.</p>"
}
},
"ScalableDimension": {
"base": null,
"refs": {
"DeleteScalingPolicyRequest$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>",
"DeregisterScalableTargetRequest$ScalableDimension": "<p>The scalable dimension associated with the scalable target. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>",
"DescribeScalableTargetsRequest$ScalableDimension": "<p>The scalable dimension associated with the scalable target. This string consists of the service namespace, resource type, and scaling property. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>",
"DescribeScalingActivitiesRequest$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>",
"DescribeScalingPoliciesRequest$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>",
"PutScalingPolicyRequest$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>",
"RegisterScalableTargetRequest$ScalableDimension": "<p>The scalable dimension associated with the scalable target. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>",
"ScalableTarget$ScalableDimension": "<p>The scalable dimension associated with the scalable target. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>",
"ScalingActivity$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>",
"ScalingPolicy$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> </ul>"
"DeleteScalingPolicyRequest$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>",
"DeregisterScalableTargetRequest$ScalableDimension": "<p>The scalable dimension associated with the scalable target. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>",
"DescribeScalableTargetsRequest$ScalableDimension": "<p>The scalable dimension associated with the scalable target. This string consists of the service namespace, resource type, and scaling property. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>",
"DescribeScalingActivitiesRequest$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>",
"DescribeScalingPoliciesRequest$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property. If you specify a scalable dimension, you must also specify a resource ID.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>",
"PutScalingPolicyRequest$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>",
"RegisterScalableTargetRequest$ScalableDimension": "<p>The scalable dimension associated with the scalable target. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>",
"ScalableTarget$ScalableDimension": "<p>The scalable dimension associated with the scalable target. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>",
"ScalingActivity$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>",
"ScalingPolicy$ScalableDimension": "<p>The scalable dimension. This string consists of the service namespace, resource type, and scaling property.</p> <ul> <li> <p> <code>ecs:service:DesiredCount</code> - The desired task count of an ECS service.</p> </li> <li> <p> <code>ec2:spot-fleet-request:TargetCapacity</code> - The target capacity of a Spot fleet request.</p> </li> <li> <p> <code>elasticmapreduce:instancegroup:InstanceCount</code> - The instance count of an EMR Instance Group.</p> </li> <li> <p> <code>appstream:fleet:DesiredCapacity</code> - The desired capacity of an AppStream 2.0 fleet.</p> </li> </ul>"
}
},
"ScalableTarget": {

View File

@ -2,21 +2,21 @@
"pagination": {
"DescribeScalableTargets": {
"input_token": "NextToken",
"output_token": "NextToken",
"limit_key": "MaxResults",
"output_token": "NextToken",
"result_key": "ScalableTargets"
},
"DescribeScalingPolicies": {
"input_token": "NextToken",
"output_token": "NextToken",
"limit_key": "MaxResults",
"result_key": "ScalingPolicies"
},
"DescribeScalingActivities": {
"input_token": "NextToken",
"output_token": "NextToken",
"limit_key": "MaxResults",
"output_token": "NextToken",
"result_key": "ScalingActivities"
},
"DescribeScalingPolicies": {
"input_token": "NextToken",
"limit_key": "MaxResults",
"output_token": "NextToken",
"result_key": "ScalingPolicies"
}
}
}

View File

@ -22,7 +22,8 @@
"output":{"shape":"AssociateFleetResult"},
"errors":[
{"shape":"LimitExceededException"},
{"shape":"ResourceNotFoundException"}
{"shape":"ResourceNotFoundException"},
{"shape":"ConcurrentModificationException"}
]
},
"CreateFleet":{
@ -38,7 +39,8 @@
{"shape":"ResourceNotAvailableException"},
{"shape":"ResourceNotFoundException"},
{"shape":"LimitExceededException"},
{"shape":"InvalidRoleException"}
{"shape":"InvalidRoleException"},
{"shape":"ConcurrentModificationException"}
]
},
"CreateStack":{
@ -51,7 +53,8 @@
"output":{"shape":"CreateStackResult"},
"errors":[
{"shape":"LimitExceededException"},
{"shape":"ResourceAlreadyExistsException"}
{"shape":"ResourceAlreadyExistsException"},
{"shape":"ConcurrentModificationException"}
]
},
"CreateStreamingURL":{
@ -65,7 +68,8 @@
"errors":[
{"shape":"ResourceNotFoundException"},
{"shape":"ResourceNotAvailableException"},
{"shape":"OperationNotPermittedException"}
{"shape":"OperationNotPermittedException"},
{"shape":"InvalidParameterCombinationException"}
]
},
"DeleteFleet":{
@ -78,7 +82,8 @@
"output":{"shape":"DeleteFleetResult"},
"errors":[
{"shape":"ResourceInUseException"},
{"shape":"ResourceNotFoundException"}
{"shape":"ResourceNotFoundException"},
{"shape":"ConcurrentModificationException"}
]
},
"DeleteStack":{
@ -91,7 +96,8 @@
"output":{"shape":"DeleteStackResult"},
"errors":[
{"shape":"ResourceInUseException"},
{"shape":"ResourceNotFoundException"}
{"shape":"ResourceNotFoundException"},
{"shape":"ConcurrentModificationException"}
]
},
"DescribeFleets":{
@ -125,7 +131,10 @@
"requestUri":"/"
},
"input":{"shape":"DescribeSessionsRequest"},
"output":{"shape":"DescribeSessionsResult"}
"output":{"shape":"DescribeSessionsResult"},
"errors":[
{"shape":"InvalidParameterCombinationException"}
]
},
"DescribeStacks":{
"name":"DescribeStacks",
@ -149,7 +158,8 @@
"output":{"shape":"DisassociateFleetResult"},
"errors":[
{"shape":"ResourceInUseException"},
{"shape":"ResourceNotFoundException"}
{"shape":"ResourceNotFoundException"},
{"shape":"ConcurrentModificationException"}
]
},
"ExpireSession":{
@ -189,7 +199,9 @@
"output":{"shape":"StartFleetResult"},
"errors":[
{"shape":"ResourceNotFoundException"},
{"shape":"LimitExceededException"}
{"shape":"OperationNotPermittedException"},
{"shape":"LimitExceededException"},
{"shape":"ConcurrentModificationException"}
]
},
"StopFleet":{
@ -201,7 +213,8 @@
"input":{"shape":"StopFleetRequest"},
"output":{"shape":"StopFleetResult"},
"errors":[
{"shape":"ResourceNotFoundException"}
{"shape":"ResourceNotFoundException"},
{"shape":"ConcurrentModificationException"}
]
},
"UpdateFleet":{
@ -216,7 +229,10 @@
{"shape":"ResourceInUseException"},
{"shape":"LimitExceededException"},
{"shape":"InvalidRoleException"},
{"shape":"ResourceNotFoundException"}
{"shape":"ResourceNotFoundException"},
{"shape":"ResourceNotAvailableException"},
{"shape":"InvalidParameterCombinationException"},
{"shape":"ConcurrentModificationException"}
]
},
"UpdateStack":{
@ -270,7 +286,15 @@
"members":{
}
},
"AuthenticationType":{
"type":"string",
"enum":[
"API",
"SAML"
]
},
"Boolean":{"type":"boolean"},
"BooleanObject":{"type":"boolean"},
"ComputeCapacity":{
"type":"structure",
"required":["DesiredInstances"],
@ -288,6 +312,13 @@
"Available":{"shape":"Integer"}
}
},
"ConcurrentModificationException":{
"type":"structure",
"members":{
"Message":{"shape":"ErrorMessage"}
},
"exception":true
},
"CreateFleetRequest":{
"type":"structure",
"required":[
@ -305,7 +336,8 @@
"MaxUserDurationInSeconds":{"shape":"Integer"},
"DisconnectTimeoutInSeconds":{"shape":"Integer"},
"Description":{"shape":"Description"},
"DisplayName":{"shape":"DisplayName"}
"DisplayName":{"shape":"DisplayName"},
"EnableDefaultInternetAccess":{"shape":"BooleanObject"}
}
},
"CreateFleetResult":{
@ -413,7 +445,8 @@
"FleetName":{"shape":"String"},
"UserId":{"shape":"UserId"},
"NextToken":{"shape":"String"},
"Limit":{"shape":"Integer"}
"Limit":{"shape":"Integer"},
"AuthenticationType":{"shape":"AuthenticationType"}
}
},
"DescribeSessionsResult":{
@ -497,7 +530,8 @@
"State":{"shape":"FleetState"},
"VpcConfig":{"shape":"VpcConfig"},
"CreatedTime":{"shape":"Timestamp"},
"FleetErrors":{"shape":"FleetErrors"}
"FleetErrors":{"shape":"FleetErrors"},
"EnableDefaultInternetAccess":{"shape":"BooleanObject"}
}
},
"FleetError":{
@ -550,6 +584,7 @@
"DisplayName":{"shape":"String"},
"State":{"shape":"ImageState"},
"Visibility":{"shape":"VisibilityType"},
"ImageBuilderSupported":{"shape":"Boolean"},
"Platform":{"shape":"PlatformType"},
"Description":{"shape":"String"},
"StateChangeReason":{"shape":"ImageStateChangeReason"},
@ -585,6 +620,13 @@
]
},
"Integer":{"type":"integer"},
"InvalidParameterCombinationException":{
"type":"structure",
"members":{
"Message":{"shape":"ErrorMessage"}
},
"exception":true
},
"InvalidRoleException":{
"type":"structure",
"members":{
@ -692,7 +734,8 @@
"UserId":{"shape":"UserId"},
"StackName":{"shape":"String"},
"FleetName":{"shape":"String"},
"State":{"shape":"SessionState"}
"State":{"shape":"SessionState"},
"AuthenticationType":{"shape":"AuthenticationType"}
}
},
"SessionList":{
@ -773,7 +816,8 @@
"DisconnectTimeoutInSeconds":{"shape":"Integer"},
"DeleteVpcConfig":{"shape":"Boolean"},
"Description":{"shape":"Description"},
"DisplayName":{"shape":"DisplayName"}
"DisplayName":{"shape":"DisplayName"},
"EnableDefaultInternetAccess":{"shape":"BooleanObject"}
}
},
"UpdateFleetResult":{

View File

@ -10,7 +10,7 @@
"DeleteStack": "<p>Deletes the stack. After this operation completes, the environment can no longer be activated, and any reservations made for the stack are released.</p>",
"DescribeFleets": "<p>If fleet names are provided, this operation describes the specified fleets; otherwise, all the fleets in the account are described.</p>",
"DescribeImages": "<p>Describes the images. If a list of names is not provided, all images in your account are returned. This operation does not return a paginated result.</p>",
"DescribeSessions": "<p>Describes the streaming sessions for a stack and a fleet. If a user ID is provided, this operation returns streaming sessions for only that user. Pass this value for the <code>nextToken</code> parameter in a subsequent call to this operation to retrieve the next set of items.</p>",
"DescribeSessions": "<p>Describes the streaming sessions for a stack and a fleet. If a user ID is provided, this operation returns streaming sessions for only that user. Pass this value for the <code>nextToken</code> parameter in a subsequent call to this operation to retrieve the next set of items. If an authentication type is not provided, the operation defaults to users authenticated using a streaming url.</p>",
"DescribeStacks": "<p>If stack names are not provided, this operation describes the specified stacks; otherwise, all stacks in the account are described. Pass the <code>nextToken</code> value in a subsequent call to this operation to retrieve the next set of items.</p>",
"DisassociateFleet": "<p>Disassociates a fleet from a stack.</p>",
"ExpireSession": "<p>This operation immediately stops a streaming session.</p>",
@ -18,7 +18,7 @@
"ListAssociatedStacks": "<p>Lists all stacks to which the specified fleet is associated.</p>",
"StartFleet": "<p>Starts a fleet.</p>",
"StopFleet": "<p>Stops a fleet.</p>",
"UpdateFleet": "<p>Updates an existing fleet. All the attributes except the fleet name can be updated in the <b>STOPPED</b> state. Only <b>ComputeCapacity</b> and <b>ImageName</b> can be updated in any other state. </p>",
"UpdateFleet": "<p>Updates an existing fleet. All the attributes except the fleet name can be updated in the <b>STOPPED</b> state. When a fleet is in the <b>RUNNING</b> state, only <code>DisplayName</code> and <code>ComputeCapacity</code> can be updated. A fleet cannot be updated in a status of <b>STARTING</b> or <b>STOPPING</b>.</p>",
"UpdateStack": "<p>Updates the specified fields in the stack with the specified name.</p>"
},
"shapes": {
@ -53,13 +53,29 @@
"refs": {
}
},
"AuthenticationType": {
"base": null,
"refs": {
"DescribeSessionsRequest$AuthenticationType": "<p>The authentication method of the user. It can be <code>API</code> for a user authenticated using a streaming url or <code>SAML</code> for a SAML federated user. If an authentication type is not provided, the operation defaults to users authenticated using a streaming url.</p>",
"Session$AuthenticationType": "<p>The authentication method of the user for whom the session was created. It can be <code>API</code> for a user authenticated using a streaming url or <code>SAML</code> for a SAML federated user.</p>"
}
},
"Boolean": {
"base": null,
"refs": {
"Application$Enabled": "<p>An application can be disabled after image creation if there is a problem.</p>",
"Image$ImageBuilderSupported": "<p>Indicates whether an image builder can be launched from this image.</p>",
"UpdateFleetRequest$DeleteVpcConfig": "<p>Delete the VPC association for the specified fleet.</p>"
}
},
"BooleanObject": {
"base": null,
"refs": {
"CreateFleetRequest$EnableDefaultInternetAccess": "<p>Enable/Disable default Internet access from fleet.</p>",
"Fleet$EnableDefaultInternetAccess": "<p>Default Internet access from the fleet. True (Enabled), False (Disabled).</p>",
"UpdateFleetRequest$EnableDefaultInternetAccess": "<p>Enable/Disable default Internet access from fleet.</p>"
}
},
"ComputeCapacity": {
"base": "<p>The capacity configuration for the fleet.</p>",
"refs": {
@ -73,6 +89,11 @@
"Fleet$ComputeCapacityStatus": "<p>The capacity information for the fleet.</p>"
}
},
"ConcurrentModificationException": {
"base": "<p>An API error occurred, please try again.</p>",
"refs": {
}
},
"CreateFleetRequest": {
"base": "<p>Contains the parameters for the new fleet to create.</p>",
"refs": {
@ -192,8 +213,10 @@
}
},
"ErrorMessage": {
"base": null,
"base": "<p>The error message in the exception.</p>",
"refs": {
"ConcurrentModificationException$Message": null,
"InvalidParameterCombinationException$Message": null,
"InvalidRoleException$Message": null,
"LimitExceededException$Message": null,
"OperationNotPermittedException$Message": null,
@ -298,6 +321,11 @@
"UpdateFleetRequest$DisconnectTimeoutInSeconds": "<p>The time after disconnection when a session is considered to have ended. When the user reconnects after a disconnection, the user is connected to the same instance within this time interval.</p>"
}
},
"InvalidParameterCombinationException": {
"base": "<p>Indicates an incorrect combination of parameters, or a missing parameter.</p>",
"refs": {
}
},
"InvalidRoleException": {
"base": "<p>The specified role is invalid.</p>",
"refs": {
@ -554,7 +582,7 @@
}
},
"VpcConfig": {
"base": "<p>The VPC in which the fleet is launched.</p>",
"base": "<p>VPC configuration information.</p>",
"refs": {
"CreateFleetRequest$VpcConfig": "<p>The VPC configuration for the fleet.</p>",
"Fleet$VpcConfig": "<p>The VPC configuration for the fleet.</p>",

View File

@ -0,0 +1,4 @@
{
"pagination": {
}
}

View File

@ -221,6 +221,28 @@
}
},
"shapes":{
"AttemptContainerDetail":{
"type":"structure",
"members":{
"containerInstanceArn":{"shape":"String"},
"taskArn":{"shape":"String"},
"exitCode":{"shape":"Integer"},
"reason":{"shape":"String"}
}
},
"AttemptDetail":{
"type":"structure",
"members":{
"container":{"shape":"AttemptContainerDetail"},
"startedAt":{"shape":"Long"},
"stoppedAt":{"shape":"Long"},
"statusReason":{"shape":"String"}
}
},
"AttemptDetails":{
"type":"list",
"member":{"shape":"AttemptDetail"}
},
"Boolean":{"type":"boolean"},
"CEState":{
"type":"string",
@ -333,6 +355,7 @@
"maxvCpus":{"shape":"Integer"},
"desiredvCpus":{"shape":"Integer"},
"instanceTypes":{"shape":"StringList"},
"imageId":{"shape":"String"},
"subnets":{"shape":"StringList"},
"securityGroupIds":{"shape":"StringList"},
"ec2KeyPair":{"shape":"String"},
@ -367,7 +390,8 @@
"user":{"shape":"String"},
"exitCode":{"shape":"Integer"},
"reason":{"shape":"String"},
"containerInstanceArn":{"shape":"String"}
"containerInstanceArn":{"shape":"String"},
"taskArn":{"shape":"String"}
}
},
"ContainerOverrides":{
@ -588,6 +612,7 @@
"status":{"shape":"String"},
"type":{"shape":"String"},
"parameters":{"shape":"ParametersMap"},
"retryStrategy":{"shape":"RetryStrategy"},
"containerProperties":{"shape":"ContainerProperties"}
}
},
@ -624,8 +649,10 @@
"jobId":{"shape":"String"},
"jobQueue":{"shape":"String"},
"status":{"shape":"JobStatus"},
"attempts":{"shape":"AttemptDetails"},
"statusReason":{"shape":"String"},
"createdAt":{"shape":"Long"},
"retryStrategy":{"shape":"RetryStrategy"},
"startedAt":{"shape":"Long"},
"stoppedAt":{"shape":"Long"},
"dependsOn":{"shape":"JobDependencyList"},
@ -741,7 +768,8 @@
"jobDefinitionName":{"shape":"String"},
"type":{"shape":"JobDefinitionType"},
"parameters":{"shape":"ParametersMap"},
"containerProperties":{"shape":"ContainerProperties"}
"containerProperties":{"shape":"ContainerProperties"},
"retryStrategy":{"shape":"RetryStrategy"}
}
},
"RegisterJobDefinitionResponse":{
@ -757,6 +785,12 @@
"revision":{"shape":"Integer"}
}
},
"RetryStrategy":{
"type":"structure",
"members":{
"attempts":{"shape":"Integer"}
}
},
"ServerException":{
"type":"structure",
"members":{
@ -784,7 +818,8 @@
"dependsOn":{"shape":"JobDependencyList"},
"jobDefinition":{"shape":"String"},
"parameters":{"shape":"ParametersMap"},
"containerOverrides":{"shape":"ContainerOverrides"}
"containerOverrides":{"shape":"ContainerOverrides"},
"retryStrategy":{"shape":"RetryStrategy"}
}
},
"SubmitJobResponse":{

View File

@ -3,7 +3,7 @@
"service": "<p>AWS Batch enables you to run batch computing workloads on the AWS Cloud. Batch computing is a common way for developers, scientists, and engineers to access large amounts of compute resources, and AWS Batch removes the undifferentiated heavy lifting of configuring and managing the required infrastructure. AWS Batch will be familiar to users of traditional batch computing software. This service can efficiently provision resources in response to jobs submitted in order to eliminate capacity constraints, reduce compute costs, and deliver results quickly.</p> <p>As a fully managed service, AWS Batch enables developers, scientists, and engineers to run batch computing workloads of any scale. AWS Batch automatically provisions compute resources and optimizes the workload distribution based on the quantity and scale of the workloads. With AWS Batch, there is no need to install or manage batch computing software, which allows you to focus on analyzing results and solving problems. AWS Batch reduces operational complexities, saves time, and reduces costs, which makes it easy for developers, scientists, and engineers to run their batch jobs in the AWS Cloud.</p>",
"operations": {
"CancelJob": "<p>Cancels jobs in an AWS Batch job queue. Jobs that are in the <code>SUBMITTED</code>, <code>PENDING</code>, or <code>RUNNABLE</code> state are cancelled. Jobs that have progressed to <code>STARTING</code> or <code>RUNNING</code> are not cancelled (but the API operation still succeeds, even if no jobs are cancelled); these jobs must be terminated with the <a>TerminateJob</a> operation.</p>",
"CreateComputeEnvironment": "<p>Creates an AWS Batch compute environment. You can create <code>MANAGED</code> or <code>UNMANAGED</code>compute environments.</p> <p>In a managed compute environment, AWS Batch manages the compute resources within the environment, based on the compute resources that you specify. Instances launched into a managed compute environment use the latest Amazon ECS-optimized AMI. You can choose to use Amazon EC2 On-Demand instances in your managed compute environment, or you can use Amazon EC2 Spot instances that only launch when the Spot bid price is below a specified percentage of the On-Demand price.</p> <p>In an unmanaged compute environment, you can manage your own compute resources. This provides more compute resource configuration options, such as using a custom AMI, but you must ensure that your AMI meets the Amazon ECS container instance AMI specification. For more information, see <a href=\"http://docs.aws.amazon.com/AmazonECS/latest/developerguide/container_instance_AMIs.html\">Container Instance AMIs</a> in the <i>Amazon EC2 Container Service Developer Guide</i>. After you have created your unmanaged compute environment, you can use the <a>DescribeComputeEnvironments</a> operation to find the Amazon ECS cluster that is associated with it and then manually launch your container instances into that Amazon ECS cluster. For more information, see <a href=\"http://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html\">Launching an Amazon ECS Container Instance</a> in the <i>Amazon EC2 Container Service Developer Guide</i>.</p>",
"CreateComputeEnvironment": "<p>Creates an AWS Batch compute environment. You can create <code>MANAGED</code> or <code>UNMANAGED</code> compute environments.</p> <p>In a managed compute environment, AWS Batch manages the compute resources within the environment, based on the compute resources that you specify. Instances launched into a managed compute environment use the latest Amazon ECS-optimized AMI. You can choose to use Amazon EC2 On-Demand instances in your managed compute environment, or you can use Amazon EC2 Spot instances that only launch when the Spot bid price is below a specified percentage of the On-Demand price.</p> <p>In an unmanaged compute environment, you can manage your own compute resources. This provides more compute resource configuration options, such as using a custom AMI, but you must ensure that your AMI meets the Amazon ECS container instance AMI specification. For more information, see <a href=\"http://docs.aws.amazon.com/AmazonECS/latest/developerguide/container_instance_AMIs.html\">Container Instance AMIs</a> in the <i>Amazon EC2 Container Service Developer Guide</i>. After you have created your unmanaged compute environment, you can use the <a>DescribeComputeEnvironments</a> operation to find the Amazon ECS cluster that is associated with it and then manually launch your container instances into that Amazon ECS cluster. For more information, see <a href=\"http://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html\">Launching an Amazon ECS Container Instance</a> in the <i>Amazon EC2 Container Service Developer Guide</i>.</p>",
"CreateJobQueue": "<p>Creates an AWS Batch job queue. When you create a job queue, you associate one or more compute environments to the queue and assign an order of preference for the compute environments.</p> <p>You also set a priority to the job queue that determines the order in which the AWS Batch scheduler places jobs onto its associated compute environments. For example, if a compute environment is associated with more than one job queue, the job queue with a higher priority is given preference for scheduling jobs to that compute environment.</p>",
"DeleteComputeEnvironment": "<p>Deletes an AWS Batch compute environment.</p> <p>Before you can delete a compute environment, you must set its state to <code>DISABLED</code> with the <a>UpdateComputeEnvironment</a> API operation and disassociate it from any job queues with the <a>UpdateJobQueue</a> API operation.</p>",
"DeleteJobQueue": "<p>Deletes the specified job queue. You must first disable submissions for a queue with the <a>UpdateJobQueue</a> operation and terminate any jobs that have not completed with the <a>TerminateJob</a>.</p> <p>It is not necessary to disassociate compute environments from a queue before submitting a <code>DeleteJobQueue</code> request. </p>",
@ -20,6 +20,24 @@
"UpdateJobQueue": "<p>Updates a job queue.</p>"
},
"shapes": {
"AttemptContainerDetail": {
"base": "<p>An object representing the details of a container that is part of a job attempt.</p>",
"refs": {
"AttemptDetail$container": "<p>Details about the container in this job attempt.</p>"
}
},
"AttemptDetail": {
"base": "<p>An object representing a job attempt.</p>",
"refs": {
"AttemptDetails$member": null
}
},
"AttemptDetails": {
"base": null,
"refs": {
"JobDetail$attempts": "<p>A list of job attempts associated with this job.</p>"
}
},
"Boolean": {
"base": null,
"refs": {
@ -237,6 +255,7 @@
"Integer": {
"base": null,
"refs": {
"AttemptContainerDetail$exitCode": "<p>The exit code for the job attempt. A non-zero exit code is considered a failure.</p>",
"ComputeEnvironmentOrder$order": "<p>The order of the compute environment.</p>",
"ComputeResource$minvCpus": "<p>The minimum number of EC2 vCPUs that an environment should maintain. </p>",
"ComputeResource$maxvCpus": "<p>The maximum number of EC2 vCPUs that an environment can reach. </p>",
@ -260,6 +279,7 @@
"JobQueueDetail$priority": "<p>The priority of the job queue. </p>",
"ListJobsRequest$maxResults": "<p>The maximum number of results returned by <code>ListJobs</code> in paginated output. When this parameter is used, <code>ListJobs</code> only returns <code>maxResults</code> results in a single page along with a <code>nextToken</code> response element. The remaining results of the initial request can be seen by sending another <code>ListJobs</code> request with the returned <code>nextToken</code> value. This value can be between 1 and 100. If this parameter is not used, then <code>ListJobs</code> returns up to 100 results and a <code>nextToken</code> value if applicable.</p>",
"RegisterJobDefinitionResponse$revision": "<p>The revision of the job definition.</p>",
"RetryStrategy$attempts": "<p>The number of times to move a job to the <code>RUNNABLE</code> status. You may specify between 1 and 10 attempts. If <code>attempts</code> is greater than one, the job is retried if it fails until it has moved to <code>RUNNABLE</code> that many times.</p>",
"Ulimit$hardLimit": "<p>The hard limit for the <code>ulimit</code> type.</p>",
"Ulimit$softLimit": "<p>The soft limit for the <code>ulimit</code> type.</p>",
"UpdateJobQueueRequest$priority": "<p>The priority of the job queue. Job queues with a higher priority (or a lower integer value for the <code>priority</code> parameter) are evaluated first when associated with same compute environment. Priority is determined in ascending order, for example, a job queue with a priority value of <code>1</code> is given scheduling preference over a job queue with a priority value of <code>10</code>.</p>"
@ -307,7 +327,7 @@
"base": null,
"refs": {
"JobDetail$dependsOn": "<p>A list of job names or IDs on which this job depends.</p>",
"SubmitJobRequest$dependsOn": "<p>A list of job names or IDs on which this job depends. A job can depend upon a maximum of 100 jobs. </p>"
"SubmitJobRequest$dependsOn": "<p>A list of job IDs on which this job depends. A job can depend upon a maximum of 100 jobs. </p>"
}
},
"JobDetail": {
@ -372,13 +392,15 @@
"Long": {
"base": null,
"refs": {
"AttemptDetail$startedAt": "<p>The Unix timestamp for when the attempt was started (when the task transitioned from the <code>PENDING</code> state to the <code>RUNNING</code> state).</p>",
"AttemptDetail$stoppedAt": "<p>The Unix timestamp for when the attempt was stopped (when the task transitioned from the <code>RUNNING</code> state to the <code>STOPPED</code> state).</p>",
"JobDetail$createdAt": "<p>The Unix timestamp for when the job was created (when the task entered the <code>PENDING</code> state). </p>",
"JobDetail$startedAt": "<p>The Unix timestamp for when the job was started (when the task transitioned from the <code>PENDING</code> state to the <code>RUNNING</code> state). </p>",
"JobDetail$stoppedAt": "<p>The Unix timestamp for when the job was stopped (when the task transitioned from the <code>RUNNING</code> state to the <code>STOPPED</code> state).</p>"
}
},
"MountPoint": {
"base": "<p>Details on a volume mount point that is used in a job's container properties.</p>",
"base": "<p>Details on a Docker volume mount point that is used in a job's container properties.</p>",
"refs": {
"MountPoints$member": null
}
@ -409,6 +431,15 @@
"refs": {
}
},
"RetryStrategy": {
"base": "<p>The retry strategy associated with a job.</p>",
"refs": {
"JobDefinition$retryStrategy": "<p>The retry strategy to use for failed jobs that are submitted with this job definition.</p>",
"JobDetail$retryStrategy": "<p>The retry strategy to use for this job if an attempt fails.</p>",
"RegisterJobDefinitionRequest$retryStrategy": "<p>The retry strategy to use for failed jobs that are submitted with this job definition. Any retry strategy that is specified during a <a>SubmitJob</a> operation overrides the retry strategy defined here.</p>",
"SubmitJobRequest$retryStrategy": "<p>The retry strategy to use for failed jobs from this <a>SubmitJob</a> operation. When a retry strategy is specified here, it overrides the retry strategy defined in the job definition.</p>"
}
},
"ServerException": {
"base": "<p>These errors are usually caused by a server issue.</p>",
"refs": {
@ -417,6 +448,10 @@
"String": {
"base": null,
"refs": {
"AttemptContainerDetail$containerInstanceArn": "<p>The Amazon Resource Name (ARN) of the Amazon ECS container instance that hosts the job attempt.</p>",
"AttemptContainerDetail$taskArn": "<p>The Amazon Resource Name (ARN) of the Amazon ECS task that is associated with the job attempt.</p>",
"AttemptContainerDetail$reason": "<p>A short (255 max characters) human-readable string to provide additional details about a running or stopped container.</p>",
"AttemptDetail$statusReason": "<p>A short, human-readable string to provide additional details about the current status of the job attempt.</p>",
"CancelJobRequest$jobId": "<p>A list of up to 100 job IDs to cancel.</p>",
"CancelJobRequest$reason": "<p>A message to attach to the job that explains the reason for cancelling it. This message is returned by future <a>DescribeJobs</a> operations on the job. This message is also recorded in the AWS Batch activity logs. </p>",
"ClientException$message": null,
@ -426,6 +461,7 @@
"ComputeEnvironmentDetail$statusReason": "<p>A short, human-readable string to provide additional details about the current status of the compute environment.</p>",
"ComputeEnvironmentDetail$serviceRole": "<p>The service role associated with the compute environment that allows AWS Batch to make calls to AWS API operations on your behalf.</p>",
"ComputeEnvironmentOrder$computeEnvironment": "<p>The Amazon Resource Name (ARN) of the compute environment.</p>",
"ComputeResource$imageId": "<p>The Amazon Machine Image (AMI) ID used for instances launched in the compute environment.</p>",
"ComputeResource$ec2KeyPair": "<p>The EC2 key pair that is used for instances launched in the compute environment.</p>",
"ComputeResource$instanceRole": "<p>The Amazon ECS instance role applied to Amazon EC2 instances in a compute environment.</p>",
"ComputeResource$spotIamFleetRole": "<p>The Amazon Resource Name (ARN) of the Amazon EC2 Spot Fleet IAM role applied to a <code>SPOT</code> compute environment.</p>",
@ -434,6 +470,7 @@
"ContainerDetail$user": "<p>The user name to use inside the container.</p>",
"ContainerDetail$reason": "<p>A short (255 max characters) human-readable string to provide additional details about a running or stopped container.</p>",
"ContainerDetail$containerInstanceArn": "<p>The Amazon Resource Name (ARN) of the container instance on which the container is running.</p>",
"ContainerDetail$taskArn": "<p>The Amazon Resource Name (ARN) of the Amazon ECS task that is associated with the container job.</p>",
"ContainerProperties$image": "<p>The image used to start a container. This string is passed directly to the Docker daemon. Images in the Docker Hub registry are available by default. Other repositories are specified with <code> <i>repository-url</i>/<i>image</i>:<i>tag</i> </code>. Up to 255 letters (uppercase and lowercase), numbers, hyphens, underscores, colons, periods, forward slashes, and number signs are allowed. This parameter maps to <code>Image</code> in the <a href=\"https://docs.docker.com/engine/reference/api/docker_remote_api_v1.23/#create-a-container\">Create a container</a> section of the <a href=\"https://docs.docker.com/engine/reference/api/docker_remote_api_v1.23/\">Docker Remote API</a> and the <code>IMAGE</code> parameter of <a href=\"https://docs.docker.com/engine/reference/run/\">docker run</a>.</p> <ul> <li> <p>Images in Amazon ECR repositories use the full registry and repository URI (for example, <code>012345678910.dkr.ecr.&lt;region-name&gt;.amazonaws.com/&lt;repository-name&gt;</code>). </p> </li> <li> <p>Images in official repositories on Docker Hub use a single name (for example, <code>ubuntu</code> or <code>mongo</code>).</p> </li> <li> <p>Images in other repositories on Docker Hub are qualified with an organization name (for example, <code>amazon/amazon-ecs-agent</code>).</p> </li> <li> <p>Images in other online repositories are qualified further by a domain name (for example, <code>quay.io/assemblyline/ubuntu</code>).</p> </li> </ul>",
"ContainerProperties$jobRoleArn": "<p>The Amazon Resource Name (ARN) of the IAM role that the container can assume for AWS permissions.</p>",
"ContainerProperties$user": "<p>The user name to use inside the container. This parameter maps to <code>User</code> in the <a href=\"https://docs.docker.com/engine/reference/api/docker_remote_api_v1.23/#create-a-container\">Create a container</a> section of the <a href=\"https://docs.docker.com/engine/reference/api/docker_remote_api_v1.23/\">Docker Remote API</a> and the <code>--user</code> option to <a href=\"https://docs.docker.com/engine/reference/run/\">docker run</a>.</p>",
@ -485,7 +522,7 @@
"RegisterJobDefinitionResponse$jobDefinitionArn": "<p>The Amazon Resource Name (ARN) of the job definition. </p>",
"ServerException$message": null,
"StringList$member": null,
"SubmitJobRequest$jobName": "<p>The name of the job.</p>",
"SubmitJobRequest$jobName": "<p>The name of the job. A name must be 1 to 128 characters in length.</p> <p>Pattern: ^[a-zA-Z0-9_]+$</p>",
"SubmitJobRequest$jobQueue": "<p>The job queue into which the job will be submitted. You can specify either the name or the Amazon Resource Name (ARN) of the queue. </p>",
"SubmitJobRequest$jobDefinition": "<p>The job definition used by this job. This value can be either a <code>name:revision</code> or the Amazon Resource Name (ARN) for the job definition.</p>",
"SubmitJobResponse$jobName": "<p>The name of the job. </p>",

View File

@ -0,0 +1,4 @@
{
"pagination": {
}
}

View File

@ -71,7 +71,8 @@
{"shape":"ResourceNotFoundException"},
{"shape":"LinkNameAlreadyInUseException"},
{"shape":"InvalidAttachmentException"},
{"shape":"ValidationException"}
{"shape":"ValidationException"},
{"shape":"FacetValidationException"}
]
},
"AttachPolicy":{
@ -689,7 +690,8 @@
{"shape":"DirectoryNotEnabledException"},
{"shape":"InvalidArnException"},
{"shape":"ResourceNotFoundException"},
{"shape":"InvalidNextTokenException"}
{"shape":"InvalidNextTokenException"},
{"shape":"FacetValidationException"}
]
},
"ListObjectChildren":{
@ -1292,7 +1294,8 @@
"members":{
"ObjectReference":{"shape":"ObjectReference"},
"NextToken":{"shape":"NextToken"},
"MaxResults":{"shape":"NumberResults"}
"MaxResults":{"shape":"NumberResults"},
"FacetFilter":{"shape":"SchemaFacet"}
}
},
"BatchListObjectAttributesResponse":{
@ -2342,7 +2345,8 @@
"shape":"ConsistencyLevel",
"location":"header",
"locationName":"x-amz-consistency-level"
}
},
"FacetFilter":{"shape":"SchemaFacet"}
}
},
"ListObjectAttributesResponse":{

View File

@ -1477,7 +1477,9 @@
"refs": {
"AddFacetToObjectRequest$SchemaFacet": "<p>Identifiers for the facet that you are adding to the object.</p>",
"BatchAddFacetToObject$SchemaFacet": "<p>Represents the facet being added to the object.</p>",
"BatchListObjectAttributes$FacetFilter": "<p>Used to filter the list of object attributes associated with a certain facet.</p>",
"BatchRemoveFacetFromObject$SchemaFacet": "<p>The facet to remove from the object.</p>",
"ListObjectAttributesRequest$FacetFilter": "<p>Used to filter the list of object attributes associated with a certain facet.</p>",
"RemoveFacetFromObjectRequest$SchemaFacet": "<p>The facet to remove.</p>",
"SchemaFacetList$member": null
}

View File

@ -16,7 +16,10 @@
"method":"POST",
"requestUri":"/"
},
"input":{"shape":"CancelUpdateStackInput"}
"input":{"shape":"CancelUpdateStackInput"},
"errors":[
{"shape":"TokenAlreadyExistsException"}
]
},
"ContinueUpdateRollback":{
"name":"ContinueUpdateRollback",
@ -28,7 +31,10 @@
"output":{
"shape":"ContinueUpdateRollbackOutput",
"resultWrapper":"ContinueUpdateRollbackResult"
}
},
"errors":[
{"shape":"TokenAlreadyExistsException"}
]
},
"CreateChangeSet":{
"name":"CreateChangeSet",
@ -61,6 +67,7 @@
"errors":[
{"shape":"LimitExceededException"},
{"shape":"AlreadyExistsException"},
{"shape":"TokenAlreadyExistsException"},
{"shape":"InsufficientCapabilitiesException"}
]
},
@ -85,7 +92,10 @@
"method":"POST",
"requestUri":"/"
},
"input":{"shape":"DeleteStackInput"}
"input":{"shape":"DeleteStackInput"},
"errors":[
{"shape":"TokenAlreadyExistsException"}
]
},
"DescribeAccountLimits":{
"name":"DescribeAccountLimits",
@ -188,7 +198,8 @@
"errors":[
{"shape":"InvalidChangeSetStatusException"},
{"shape":"ChangeSetNotFoundException"},
{"shape":"InsufficientCapabilitiesException"}
{"shape":"InsufficientCapabilitiesException"},
{"shape":"TokenAlreadyExistsException"}
]
},
"GetStackPolicy":{
@ -318,7 +329,8 @@
"resultWrapper":"UpdateStackResult"
},
"errors":[
{"shape":"InsufficientCapabilitiesException"}
{"shape":"InsufficientCapabilitiesException"},
{"shape":"TokenAlreadyExistsException"}
]
},
"ValidateTemplate":{
@ -366,7 +378,8 @@
"type":"structure",
"required":["StackName"],
"members":{
"StackName":{"shape":"StackName"}
"StackName":{"shape":"StackName"},
"ClientRequestToken":{"shape":"ClientRequestToken"}
}
},
"Capabilities":{
@ -479,6 +492,12 @@
"type":"list",
"member":{"shape":"Change"}
},
"ClientRequestToken":{
"type":"string",
"max":128,
"min":1,
"pattern":"[a-zA-Z][-a-zA-Z0-9]*"
},
"ClientToken":{
"type":"string",
"max":128,
@ -490,7 +509,8 @@
"members":{
"StackName":{"shape":"StackNameOrId"},
"RoleARN":{"shape":"RoleARN"},
"ResourcesToSkip":{"shape":"ResourcesToSkip"}
"ResourcesToSkip":{"shape":"ResourcesToSkip"},
"ClientRequestToken":{"shape":"ClientRequestToken"}
}
},
"ContinueUpdateRollbackOutput":{
@ -545,7 +565,8 @@
"OnFailure":{"shape":"OnFailure"},
"StackPolicyBody":{"shape":"StackPolicyBody"},
"StackPolicyURL":{"shape":"StackPolicyURL"},
"Tags":{"shape":"Tags"}
"Tags":{"shape":"Tags"},
"ClientRequestToken":{"shape":"ClientRequestToken"}
}
},
"CreateStackOutput":{
@ -574,7 +595,8 @@
"members":{
"StackName":{"shape":"StackName"},
"RetainResources":{"shape":"RetainResources"},
"RoleARN":{"shape":"RoleARN"}
"RoleARN":{"shape":"RoleARN"},
"ClientRequestToken":{"shape":"ClientRequestToken"}
}
},
"DeletionTime":{"type":"timestamp"},
@ -712,7 +734,8 @@
"required":["ChangeSetName"],
"members":{
"ChangeSetName":{"shape":"ChangeSetNameOrId"},
"StackName":{"shape":"StackNameOrId"}
"StackName":{"shape":"StackNameOrId"},
"ClientRequestToken":{"shape":"ClientRequestToken"}
}
},
"ExecuteChangeSetOutput":{
@ -1167,7 +1190,8 @@
"Timestamp":{"shape":"Timestamp"},
"ResourceStatus":{"shape":"ResourceStatus"},
"ResourceStatusReason":{"shape":"ResourceStatusReason"},
"ResourceProperties":{"shape":"ResourceProperties"}
"ResourceProperties":{"shape":"ResourceProperties"},
"ClientRequestToken":{"shape":"ClientRequestToken"}
}
},
"StackEvents":{
@ -1372,6 +1396,17 @@
"min":1
},
"Timestamp":{"type":"timestamp"},
"TokenAlreadyExistsException":{
"type":"structure",
"members":{
},
"error":{
"code":"TokenAlreadyExistsException",
"httpStatusCode":400,
"senderFault":true
},
"exception":true
},
"TransformName":{"type":"string"},
"TransformsList":{
"type":"list",
@ -1394,7 +1429,8 @@
"StackPolicyBody":{"shape":"StackPolicyBody"},
"StackPolicyURL":{"shape":"StackPolicyURL"},
"NotificationARNs":{"shape":"NotificationARNs"},
"Tags":{"shape":"Tags"}
"Tags":{"shape":"Tags"},
"ClientRequestToken":{"shape":"ClientRequestToken"}
}
},
"UpdateStackOutput":{

View File

@ -1,10 +1,10 @@
{
"version": "2.0",
"service": "<fullname>AWS CloudFormation</fullname> <p>AWS CloudFormation allows you to create and manage AWS infrastructure deployments predictably and repeatedly. You can use AWS CloudFormation to leverage AWS products, such as Amazon Elastic Compute Cloud, Amazon Elastic Block Store, Amazon Simple Notification Service, Elastic Load Balancing, and Auto Scaling to build highly-reliable, highly scalable, cost-effective applications without creating or configuring the underlying AWS infrastructure.</p> <p>With AWS CloudFormation, you declare all of your resources and dependencies in a template file. The template defines a collection of resources as a single unit called a stack. AWS CloudFormation creates and deletes all member resources of the stack together and manages all dependencies between the resources for you.</p> <p>For more information about AWS CloudFormation, see the <a href=\"http://aws.amazon.com/cloudformation/\">AWS CloudFormation Product Page</a>.</p> <p>Amazon CloudFormation makes use of other AWS products. For additional technical information about a specific AWS product, see its <a href=\"http://docs.aws.amazon.com/\">technical documentation</a>.</p>",
"service": "<fullname>AWS CloudFormation</fullname> <p>AWS CloudFormation allows you to create and manage AWS infrastructure deployments predictably and repeatedly. You can use AWS CloudFormation to leverage AWS products, such as Amazon Elastic Compute Cloud, Amazon Elastic Block Store, Amazon Simple Notification Service, Elastic Load Balancing, and Auto Scaling to build highly-reliable, highly scalable, cost-effective applications without creating or configuring the underlying AWS infrastructure.</p> <p>With AWS CloudFormation, you declare all of your resources and dependencies in a template file. The template defines a collection of resources as a single unit called a stack. AWS CloudFormation creates and deletes all member resources of the stack together and manages all dependencies between the resources for you.</p> <p>For more information about AWS CloudFormation, see the <a href=\"http://aws.amazon.com/cloudformation/\">AWS CloudFormation Product Page</a>.</p> <p>Amazon CloudFormation makes use of other AWS products. If you need additional technical information about a specific AWS product, you can find the product's technical documentation at <a href=\"http://docs.aws.amazon.com/\">docs.aws.amazon.com</a>.</p>",
"operations": {
"CancelUpdateStack": "<p>Cancels an update on the specified stack. If the call completes successfully, the stack rolls back the update and reverts to the previous stack configuration.</p> <note> <p>You can cancel only stacks that are in the UPDATE_IN_PROGRESS state.</p> </note>",
"ContinueUpdateRollback": "<p>For a specified stack that is in the <code>UPDATE_ROLLBACK_FAILED</code> state, continues rolling it back to the <code>UPDATE_ROLLBACK_COMPLETE</code> state. Depending on the cause of the failure, you can manually <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/troubleshooting.html#troubleshooting-errors-update-rollback-failed\"> fix the error</a> and continue the rollback. By continuing the rollback, you can return your stack to a working state (the <code>UPDATE_ROLLBACK_COMPLETE</code> state), and then try to update the stack again.</p> <p>A stack goes into the <code>UPDATE_ROLLBACK_FAILED</code> state when AWS CloudFormation cannot roll back all changes after a failed stack update. For example, you might have a stack that is rolling back to an old database instance that was deleted outside of AWS CloudFormation. Because AWS CloudFormation doesn't know the database was deleted, it assumes that the database instance still exists and attempts to roll back to it, causing the update rollback to fail.</p>",
"CreateChangeSet": "<p>Creates a list of changes for a stack. AWS CloudFormation generates the change set by comparing the template's information with the information that you submit. A change set can help you understand which resources AWS CloudFormation will change, and how it will change them, before you update your stack. Change sets allow you to check before making a change to avoid deleting or replacing critical resources.</p> <p>AWS CloudFormation doesn't make any changes to the stack when you create a change set. To make the specified changes, you must execute the change set by using the <a>ExecuteChangeSet</a> action.</p> <p>After the call successfully completes, AWS CloudFormation starts creating the change set. To check the status of the change set, use the <a>DescribeChangeSet</a> action.</p>",
"CreateChangeSet": "<p>Creates a list of changes that will be applied to a stack so that you can review the changes before executing them. You can create a change set for a stack that doesn't exist or an existing stack. If you create a change set for a stack that doesn't exist, the change set shows all of the resources that AWS CloudFormation will create. If you create a change set for an existing stack, AWS CloudFormation compares the stack's information with the information that you submit in the change set and lists the differences. Use change sets to understand which resources AWS CloudFormation will create or change, and how it will change resources in an existing stack, before you create or update a stack.</p> <p>To create a change set for a stack that doesn't exist, for the <code>ChangeSetType</code> parameter, specify <code>CREATE</code>. To create a change set for an existing stack, specify <code>UPDATE</code> for the <code>ChangeSetType</code> parameter. After the <code>CreateChangeSet</code> call successfully completes, AWS CloudFormation starts creating the change set. To check the status of the change set or to review it, use the <a>DescribeChangeSet</a> action.</p> <p>When you are satisfied with the changes the change set will make, execute the change set by using the <a>ExecuteChangeSet</a> action. AWS CloudFormation doesn't make changes until you execute the change set.</p>",
"CreateStack": "<p>Creates a stack as specified in the template. After the call completes successfully, the stack creation starts. You can check the status of the stack via the <a>DescribeStacks</a> API.</p>",
"DeleteChangeSet": "<p>Deletes the specified change set. Deleting change sets ensures that no one executes the wrong change set.</p> <p>If the call successfully completes, AWS CloudFormation successfully deleted the change set.</p>",
"DeleteStack": "<p>Deletes a specified stack. Once the call completes successfully, stack deletion starts. Deleted stacks do not show up in the <a>DescribeStacks</a> API if the deletion has been completed successfully.</p>",
@ -188,6 +188,18 @@
"DescribeChangeSetOutput$Changes": "<p>A list of <code>Change</code> structures that describes the resources AWS CloudFormation changes if you execute the change set.</p>"
}
},
"ClientRequestToken": {
"base": null,
"refs": {
"CancelUpdateStackInput$ClientRequestToken": "<p>A unique identifier for this <code>CancelUpdateStack</code> request. Specify this token if you plan to retry requests so that AWS CloudFormation knows that you're not attempting to cancel an update on a stack with the same name. You might retry <code>CancelUpdateStack</code> requests to ensure that AWS CloudFormation successfully received them.</p>",
"ContinueUpdateRollbackInput$ClientRequestToken": "<p>A unique identifier for this <code>ContinueUpdateRollback</code> request. Specify this token if you plan to retry requests so that AWS CloudFormation knows that you're not attempting to continue the rollback to a stack with the same name. You might retry <code>ContinueUpdateRollback</code> requests to ensure that AWS CloudFormation successfully received them.</p>",
"CreateStackInput$ClientRequestToken": "<p>A unique identifier for this <code>CreateStack</code> request. Specify this token if you plan to retry requests so that AWS CloudFormation knows that you're not attempting to create a stack with the same name. You might retry <code>CreateStack</code> requests to ensure that AWS CloudFormation successfully received them.</p>",
"DeleteStackInput$ClientRequestToken": "<p>A unique identifier for this <code>DeleteStack</code> request. Specify this token if you plan to retry requests so that AWS CloudFormation knows that you're not attempting to delete a stack with the same name. You might retry <code>DeleteStack</code> requests to ensure that AWS CloudFormation successfully received them.</p>",
"ExecuteChangeSetInput$ClientRequestToken": "<p>A unique identifier for this <code>ExecuteChangeSet</code> request. Specify this token if you plan to retry requests so that AWS CloudFormation knows that you're not attempting to execute a change set to update a stack with the same name. You might retry <code>ExecuteChangeSet</code> requests to ensure that AWS CloudFormation successfully received them.</p>",
"StackEvent$ClientRequestToken": "<p>The token passed to the operation that generated this event.</p> <p>For example, if you execute a <code>CreateStack</code> operation with the token <code>token1</code>, then all the <code>StackEvents</code> generated by that operation will have <code>ClientRequestToken</code> set as <code>token1</code>.</p>",
"UpdateStackInput$ClientRequestToken": "<p>A unique identifier for this <code>UpdateStack</code> request. Specify this token if you plan to retry requests so that AWS CloudFormation knows that you're not attempting to update a stack with the same name. You might retry <code>UpdateStack</code> requests to ensure that AWS CloudFormation successfully received them.</p>"
}
},
"ClientToken": {
"base": null,
"refs": {
@ -582,7 +594,7 @@
"base": null,
"refs": {
"CreateChangeSetInput$NotificationARNs": "<p>The Amazon Resource Names (ARNs) of Amazon Simple Notification Service (Amazon SNS) topics that AWS CloudFormation associates with the stack. To remove all associated notification topics, specify an empty list.</p>",
"CreateStackInput$NotificationARNs": "<p>The Simple Notification Service (SNS) topic ARNs to publish stack related events. You can find your SNS topic ARNs using the <a href=\"https://console.aws.amazon.com/sns\">SNS console</a> or your Command Line Interface (CLI).</p>",
"CreateStackInput$NotificationARNs": "<p>The Simple Notification Service (SNS) topic ARNs to publish stack related events. You can find your SNS topic ARNs using the SNS console or your Command Line Interface (CLI).</p>",
"DescribeChangeSetOutput$NotificationARNs": "<p>The ARNs of the Amazon Simple Notification Service (Amazon SNS) topics that will be associated with the stack if you execute the change set.</p>",
"Stack$NotificationARNs": "<p>SNS topic ARNs to which stack related events are published.</p>",
"UpdateStackInput$NotificationARNs": "<p>Amazon Simple Notification Service topic Amazon Resource Names (ARNs) that AWS CloudFormation associates with the stack. Specify an empty list to remove all notification topics.</p>"
@ -800,7 +812,7 @@
"ResourcesToSkip": {
"base": null,
"refs": {
"ContinueUpdateRollbackInput$ResourcesToSkip": "<p>A list of the logical IDs of the resources that AWS CloudFormation skips during the continue update rollback operation. You can specify only resources that are in the <code>UPDATE_FAILED</code> state because a rollback failed. You can't specify resources that are in the <code>UPDATE_FAILED</code> state for other reasons, for example, because an update was canceled. To check why a resource update failed, use the <a>DescribeStackResources</a> action, and view the resource status reason. </p> <important> <p>Specify this property to skip rolling back resources that AWS CloudFormation can't successfully roll back. We recommend that you <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/troubleshooting.html#troubleshooting-errors-update-rollback-failed\"> troubleshoot</a> resources before skipping them. AWS CloudFormation sets the status of the specified resources to <code>UPDATE_COMPLETE</code> and continues to roll back the stack. After the rollback is complete, the state of the skipped resources will be inconsistent with the state of the resources in the stack template. Before performing another stack update, you must update the stack or resources to be consistent with each other. If you don't, subsequent stack updates might fail, and the stack will become unrecoverable. </p> </important> <p>Specify the minimum number of resources required to successfully roll back your stack. For example, a failed resource update might cause dependent resources to fail. In this case, it might not be necessary to skip the dependent resources. </p> <p>To specify resources in a nested stack, use the following format: <code>NestedStackName.ResourceLogicalID</code>. You can specify a nested stack resource (the logical ID of an <code>AWS::CloudFormation::Stack</code> resource) only if it's in one of the following states: <code>DELETE_IN_PROGRESS</code>, <code>DELETE_COMPLETE</code>, or <code>DELETE_FAILED</code>. </p>"
"ContinueUpdateRollbackInput$ResourcesToSkip": "<p>A list of the logical IDs of the resources that AWS CloudFormation skips during the continue update rollback operation. You can specify only resources that are in the <code>UPDATE_FAILED</code> state because a rollback failed. You can't specify resources that are in the <code>UPDATE_FAILED</code> state for other reasons, for example, because an update was canceled. To check why a resource update failed, use the <a>DescribeStackResources</a> action, and view the resource status reason. </p> <important> <p>Specify this property to skip rolling back resources that AWS CloudFormation can't successfully roll back. We recommend that you <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/troubleshooting.html#troubleshooting-errors-update-rollback-failed\"> troubleshoot</a> resources before skipping them. AWS CloudFormation sets the status of the specified resources to <code>UPDATE_COMPLETE</code> and continues to roll back the stack. After the rollback is complete, the state of the skipped resources will be inconsistent with the state of the resources in the stack template. Before performing another stack update, you must update the stack or resources to be consistent with each other. If you don't, subsequent stack updates might fail, and the stack will become unrecoverable. </p> </important> <p>Specify the minimum number of resources required to successfully roll back your stack. For example, a failed resource update might cause dependent resources to fail. In this case, it might not be necessary to skip the dependent resources. </p> <p>To specify resources in a nested stack, use the following format: <code>NestedStackName.ResourceLogicalID</code>. If the <code>ResourceLogicalID</code> is a stack resource (<code>Type: AWS::CloudFormation::Stack</code>), it must be in one of the following states: <code>DELETE_IN_PROGRESS</code>, <code>DELETE_COMPLETE</code>, or <code>DELETE_FAILED</code>. </p>"
}
},
"RetainResources": {
@ -1048,7 +1060,7 @@
"EstimateTemplateCostInput$TemplateBody": "<p>Structure containing the template body with a minimum length of 1 byte and a maximum length of 51,200 bytes. (For more information, go to <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.)</p> <p>Conditional: You must pass <code>TemplateBody</code> or <code>TemplateURL</code>. If both are passed, only <code>TemplateBody</code> is used.</p>",
"GetTemplateOutput$TemplateBody": "<p>Structure containing the template body. (For more information, go to <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.)</p> <p>AWS CloudFormation returns the same template that was used when the stack was created.</p>",
"GetTemplateSummaryInput$TemplateBody": "<p>Structure containing the template body with a minimum length of 1 byte and a maximum length of 51,200 bytes. For more information about templates, see <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.</p> <p>Conditional: You must specify only one of the following parameters: <code>StackName</code>, <code>TemplateBody</code>, or <code>TemplateURL</code>.</p>",
"UpdateStackInput$TemplateBody": "<p>Structure containing the template body with a minimum length of 1 byte and a maximum length of 51,200 bytes. (For more information, go to <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.)</p> <p>Conditional: You must specify either the <code>TemplateBody</code> or the <code>TemplateURL</code> parameter, but not both.</p>",
"UpdateStackInput$TemplateBody": "<p>Structure containing the template body with a minimum length of 1 byte and a maximum length of 51,200 bytes. (For more information, go to <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.)</p> <p>Conditional: You must specify only one of the following parameters: <code>TemplateBody</code>, <code>TemplateURL</code>, or set the <code>UsePreviousTemplate</code> to <code>true</code>.</p>",
"ValidateTemplateInput$TemplateBody": "<p>Structure containing the template body with a minimum length of 1 byte and a maximum length of 51,200 bytes. For more information, go to <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.</p> <p>Conditional: You must pass <code>TemplateURL</code> or <code>TemplateBody</code>. If both are passed, only <code>TemplateBody</code> is used.</p>"
}
},
@ -1084,7 +1096,7 @@
"CreateStackInput$TemplateURL": "<p>Location of file containing the template body. The URL must point to a template (max size: 460,800 bytes) that is located in an Amazon S3 bucket. For more information, go to the <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.</p> <p>Conditional: You must specify either the <code>TemplateBody</code> or the <code>TemplateURL</code> parameter, but not both.</p>",
"EstimateTemplateCostInput$TemplateURL": "<p>Location of file containing the template body. The URL must point to a template that is located in an Amazon S3 bucket. For more information, go to <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.</p> <p>Conditional: You must pass <code>TemplateURL</code> or <code>TemplateBody</code>. If both are passed, only <code>TemplateBody</code> is used.</p>",
"GetTemplateSummaryInput$TemplateURL": "<p>Location of file containing the template body. The URL must point to a template (max size: 460,800 bytes) that is located in an Amazon S3 bucket. For more information about templates, see <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.</p> <p>Conditional: You must specify only one of the following parameters: <code>StackName</code>, <code>TemplateBody</code>, or <code>TemplateURL</code>.</p>",
"UpdateStackInput$TemplateURL": "<p>Location of file containing the template body. The URL must point to a template that is located in an Amazon S3 bucket. For more information, go to <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.</p> <p>Conditional: You must specify either the <code>TemplateBody</code> or the <code>TemplateURL</code> parameter, but not both.</p>",
"UpdateStackInput$TemplateURL": "<p>Location of file containing the template body. The URL must point to a template that is located in an Amazon S3 bucket. For more information, go to <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.</p> <p>Conditional: You must specify only one of the following parameters: <code>TemplateBody</code>, <code>TemplateURL</code>, or set the <code>UsePreviousTemplate</code> to <code>true</code>.</p>",
"ValidateTemplateInput$TemplateURL": "<p>Location of file containing the template body. The URL must point to a template (max size: 460,800 bytes) that is located in an Amazon S3 bucket. For more information, go to <a href=\"http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html\">Template Anatomy</a> in the AWS CloudFormation User Guide.</p> <p>Conditional: You must pass <code>TemplateURL</code> or <code>TemplateBody</code>. If both are passed, only <code>TemplateBody</code> is used.</p>"
}
},
@ -1104,6 +1116,11 @@
"StackResourceSummary$LastUpdatedTimestamp": "<p>Time the status was updated.</p>"
}
},
"TokenAlreadyExistsException": {
"base": "<p>A client request token already exists.</p>",
"refs": {
}
},
"TransformName": {
"base": null,
"refs": {
@ -1137,7 +1154,7 @@
"base": null,
"refs": {
"CreateChangeSetInput$UsePreviousTemplate": "<p>Whether to reuse the template that is associated with the stack to create the change set.</p>",
"UpdateStackInput$UsePreviousTemplate": "<p>Reuse the existing template that is associated with the stack that you are updating.</p>"
"UpdateStackInput$UsePreviousTemplate": "<p>Reuse the existing template that is associated with the stack that you are updating.</p> <p>Conditional: You must specify only one of the following parameters: <code>TemplateBody</code>, <code>TemplateURL</code>, or set the <code>UsePreviousTemplate</code> to <code>true</code>.</p>"
}
},
"UsePreviousValue": {

View File

@ -1,158 +1,5 @@
{
"version": "1.0",
"examples": {
"CancelUpdateStack": [
{
"input": {
"StackName": "MyStack"
},
"comments": {
"input": {
},
"output": {
}
},
"description": "This example cancels an update of the specified stack.",
"id": "to-cancel-a-stack-update-that-is-in-progress-1472747085196",
"title": "To cancel a stack update in progress"
}
],
"UpdateStack": [
{
"input": {
"NotificationARNs": [
],
"Parameters": [
{
"ParameterKey": "KeyPairName",
"ParameterValue": "ExampleKeyPair"
},
{
"ParameterKey": "SubnetIDs",
"ParameterValue": "ExampleSubnetID1, ExampleSubnetID2"
}
],
"ResourceTypes": [
],
"StackName": "MyStack",
"Tags": [
],
"TemplateURL": "https://s3.amazonaws.com/example/updated.template"
},
"output": {
"StackId": ""
},
"comments": {
"input": {
},
"output": {
}
},
"description": "This example updates the template and input parameters for the specified stack.",
"id": "to-update-an-aws-cloudformation-stack-1472841931621",
"title": "To update an AWS CloudFormation stack"
},
{
"input": {
"NotificationARNs": [
],
"Parameters": [
{
"ParameterKey": "KeyPairName",
"UsePreviousValue": true
},
{
"ParameterKey": "SubnetIDs",
"ParameterValue": "SampleSubnetID1, UpdatedSampleSubnetID2"
}
],
"ResourceTypes": [
],
"StackName": "MyStack",
"Tags": [
],
"TemplateURL": "https://s3.amazonaws.com/example/updated.template"
},
"output": {
"StackId": ""
},
"comments": {
"input": {
},
"output": {
}
},
"description": "This example updates only the the specified parameter value for the specified stack. If you don't specify a parameter value, AWS CloudFormation uses the default value from the template.",
"id": "to-update-an-aws-cloudformation-stack-1472841931621",
"title": "To update an AWS CloudFormation stack"
},
{
"input": {
"Capabilities": [
],
"NotificationARNs": [
"arn:aws:sns:use-east-1:123456789012:mytopic1",
"arn:aws:sns:us-east-1:123456789012:mytopic2"
],
"Parameters": [
],
"ResourceTypes": [
],
"StackName": "MyStack",
"Tags": [
],
"TemplateURL": "https://s3.amazonaws.com/example/updated.template",
"UsePreviousTemplate": true
},
"output": {
"StackId": ""
},
"comments": {
"input": {
},
"output": {
}
},
"description": "This example adds two stack notification topics to the specified stack.",
"id": "to-update-an-aws-cloudformation-stack-1472841931621",
"title": "To update an AWS CloudFormation stack"
}
],
"ValidateTemplate": [
{
"input": {
"TemplateBody": "MyTemplate.json"
},
"output": {
"Capabilities": [
],
"CapabilitiesReason": "",
"Description": "AWS CloudFormation Example Template S3_Bucket: An example template that shows how to create a publicly-accessible S3 bucket. IMPORTANT: This template creates an S3 bucket. You will be billed for the AWS resources used if you create a stack from this template.",
"Parameters": [
]
},
"comments": {
"input": {
},
"output": {
}
},
"description": "This example validates the specified template.",
"id": "to-validate-an-aws-cloudformation-template-1472839072307",
"title": "To validate an AWS CloudFormation template"
}
]
}
}

View File

@ -13,6 +13,16 @@
"output_token": "NextToken",
"result_key": "Stacks"
},
"ListExports": {
"input_token": "NextToken",
"output_token": "NextToken",
"result_key": "Exports"
},
"ListImports": {
"input_token": "NextToken",
"output_token": "NextToken",
"result_key": "Imports"
},
"ListStackResources": {
"input_token": "NextToken",
"output_token": "NextToken",

View File

@ -152,6 +152,31 @@
"state": "failure"
}
]
},
"ChangeSetCreateComplete": {
"delay": 30,
"operation": "DescribeChangeSet",
"maxAttempts": 120,
"description": "Wait until change set status is CREATE_COMPLETE.",
"acceptors": [
{
"argument": "Status",
"expected": "CREATE_COMPLETE",
"matcher": "path",
"state": "success"
},
{
"argument": "Status",
"expected": "FAILED",
"matcher": "path",
"state": "failure"
},
{
"expected": "ValidationError",
"matcher": "error",
"state": "failure"
}
]
}
}
}

Some files were not shown because too many files have changed in this diff Show More