mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-20 13:28:17 +00:00
Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
633c43a672 | ||
|
|
0833693372 | ||
|
|
77c07ba96e | ||
|
|
6847bb7924 | ||
|
|
f0deaf707d | ||
|
|
e113944027 | ||
|
|
1cf9131ae2 | ||
|
|
da142a8e97 | ||
|
|
6c81e3b95f | ||
|
|
a0089a2521 | ||
|
|
11768f6232 | ||
|
|
675c17737f | ||
|
|
735a93d000 | ||
|
|
67d2c2ed4a | ||
|
|
f931e15653 | ||
|
|
34169174a8 | ||
|
|
ebf33964c7 | ||
|
|
38a5e12d66 | ||
|
|
04ab218fa0 | ||
|
|
950c353f90 | ||
|
|
aff09b1108 | ||
|
|
6da691f874 | ||
|
|
22c99aa535 | ||
|
|
5fa209acfa | ||
|
|
d72879e109 | ||
|
|
337f3631ff | ||
|
|
b3993dc874 | ||
|
|
11c04dd6c4 | ||
|
|
b29e449d4a | ||
|
|
430f2f84fb | ||
|
|
52c6b5755b | ||
|
|
958bc63293 | ||
|
|
94ed0fe515 | ||
|
|
bb8233ceff | ||
|
|
6221bed190 | ||
|
|
1ffeb181e7 | ||
|
|
759ba1cbf4 | ||
|
|
12f2c41273 | ||
|
|
2174741376 | ||
|
|
31dd8fc5b1 | ||
|
|
77f4811779 | ||
|
|
7050a45134 | ||
|
|
3b64f1e102 | ||
|
|
6c4c79e2cc | ||
|
|
3975ebc21a | ||
|
|
ec95e5f97e | ||
|
|
72b1a4bc5c | ||
|
|
16447efca3 | ||
|
|
524d593c5c | ||
|
|
3b644474c4 | ||
|
|
42e6ced2b0 | ||
|
|
f018370628 | ||
|
|
c9a8bc1121 | ||
|
|
8c7cbb12dd | ||
|
|
b02f7775c5 | ||
|
|
f9a0e671b7 | ||
|
|
70fb22cad6 | ||
|
|
2ae00db6a9 | ||
|
|
f9577ab540 | ||
|
|
6a2786a5c4 | ||
|
|
924aa6fb29 | ||
|
|
e2cd44f9d8 | ||
|
|
187415430f | ||
|
|
afac2fb46a | ||
|
|
20fd433f75 | ||
|
|
1e3824057b |
@@ -8,6 +8,7 @@ go:
|
||||
before_install:
|
||||
- source ./bin/consider-early-travis-exit.sh
|
||||
- sudo apt-get install tree
|
||||
- go get -u github.com/opennota/check/cmd/varcheck
|
||||
- go get -u github.com/golang/lint/golint
|
||||
- go get -u golang.org/x/tools/cmd/goimports
|
||||
- go get -u github.com/onsi/ginkgo/ginkgo
|
||||
|
||||
128
Gopkg.lock
generated
128
Gopkg.lock
generated
@@ -17,6 +17,54 @@
|
||||
pruneopts = ""
|
||||
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9299ad32dcec0f92ad06773f73426bd46a21efa96f6a8138c287bb185933e77e"
|
||||
name = "github.com/aws/aws-sdk-go"
|
||||
packages = [
|
||||
"aws",
|
||||
"aws/awserr",
|
||||
"aws/awsutil",
|
||||
"aws/client",
|
||||
"aws/client/metadata",
|
||||
"aws/corehandlers",
|
||||
"aws/credentials",
|
||||
"aws/credentials/ec2rolecreds",
|
||||
"aws/credentials/endpointcreds",
|
||||
"aws/credentials/stscreds",
|
||||
"aws/csm",
|
||||
"aws/defaults",
|
||||
"aws/ec2metadata",
|
||||
"aws/endpoints",
|
||||
"aws/request",
|
||||
"aws/session",
|
||||
"aws/signer/v4",
|
||||
"internal/sdkio",
|
||||
"internal/sdkrand",
|
||||
"internal/sdkuri",
|
||||
"internal/shareddefaults",
|
||||
"private/protocol",
|
||||
"private/protocol/eventstream",
|
||||
"private/protocol/eventstream/eventstreamapi",
|
||||
"private/protocol/query",
|
||||
"private/protocol/query/queryutil",
|
||||
"private/protocol/rest",
|
||||
"private/protocol/restxml",
|
||||
"private/protocol/xml/xmlutil",
|
||||
"service/s3",
|
||||
"service/sts",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "daed0c76021ea9c4e659e3ec80bcd2d657297100"
|
||||
version = "v1.15.12"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:98e84060475ed245c3b355042afd43a74aa7d32efe50658f4f995977916f9fc3"
|
||||
name = "github.com/bgentry/go-netrc"
|
||||
packages = ["netrc"]
|
||||
pruneopts = ""
|
||||
revision = "9fd32a8b3d3d3f9d43c341bfe098430e07609480"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
@@ -52,6 +100,14 @@
|
||||
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:858b7fe7b0f4bc7ef9953926828f2816ea52d01a88d72d1c45bc8c108f23c356"
|
||||
name = "github.com/go-ini/ini"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "358ee7663966325963d4e8b2e1fbd570c5195153"
|
||||
version = "v1.38.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e116a4866bffeec941056a1fcfd37e520fad1ee60e4e3579719f19a43c392e10"
|
||||
@@ -137,6 +193,41 @@
|
||||
revision = "ee43cbb60db7bd22502942cccbc39059117352ab"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f5d25fd7bdda08e39e01193ef94a1ebf7547b1b931bcdec785d08050598f306c"
|
||||
name = "github.com/hashicorp/go-cleanhttp"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "d5fe4b57a186c716b0e00b8c301cbd9b4182694d"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:fd15b3f6aac9d0fe68c6e38922282e0d2e88cd77b927ac3dd842e363645522c0"
|
||||
name = "github.com/hashicorp/go-getter"
|
||||
packages = [
|
||||
".",
|
||||
"helper/url",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "4bda8fa99001c61db3cad96b421d4c12a81f256d"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2cf6c60c74eacadd31652674364af55c8d54a86b8ea193548f1c37f8c9af8f9c"
|
||||
name = "github.com/hashicorp/go-safetemp"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "b1a1dbde6fdc11e3ae79efd9039009e22d4ae240"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:139bdc2c89779b8ff8b1150be28f889b0ed964e6da96f32cbc9035bd4642881c"
|
||||
name = "github.com/hashicorp/go-version"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "270f2f71b1ee587f3b609f00f422b76a6b28f348"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
@@ -145,6 +236,13 @@
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6f49eae0c1e5dab1dafafee34b207aeb7a42303105960944828c2079b92fc88e"
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "0b12d6b5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9eab2325abbed0ebcee9d44bb3660a69d5d10e42d5ac4a0e77f7a6ea22bfce88"
|
||||
name = "github.com/json-iterator/go"
|
||||
@@ -165,6 +263,22 @@
|
||||
pruneopts = ""
|
||||
revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:83854f6b1d2ce047b69657e3a87ba7602f4c5505e8bdfd02ab857db8e983bde1"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "58046073cbffe2f25d425fe1331102f55cf719de"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:51c98e2c9a8d0a724a69f46421876af14e12132cb02f1d0e144785d752247162"
|
||||
name = "github.com/mitchellh/go-testing-interface"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0c0ff2a89c1bb0d01887e1dac043ad7efbf3ec77482ef058ac423d13497e16fd"
|
||||
name = "github.com/modern-go/concurrent"
|
||||
@@ -205,6 +319,19 @@
|
||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ee723e6a1962a196eeba1b24f82af61a4f60f8821d7aa96d48e787f8337bcffc"
|
||||
name = "github.com/ulikunitz/xz"
|
||||
packages = [
|
||||
".",
|
||||
"internal/hash",
|
||||
"internal/xlog",
|
||||
"lzma",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "0c6b41e72360850ca4f98dc341fd999726ea007f"
|
||||
version = "v0.5.4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9e548233d0dc00e74be262e54a9d1bbe7e4c19e5951083520261740e37daeb02"
|
||||
@@ -362,6 +489,7 @@
|
||||
"github.com/evanphx/json-patch",
|
||||
"github.com/ghodss/yaml",
|
||||
"github.com/golang/glog",
|
||||
"github.com/hashicorp/go-getter",
|
||||
"github.com/pkg/errors",
|
||||
"github.com/spf13/cobra",
|
||||
"k8s.io/api/core/v1",
|
||||
|
||||
@@ -49,10 +49,14 @@
|
||||
name = "k8s.io/client-go"
|
||||
version = "7.0.0"
|
||||
|
||||
[[constraint]]
|
||||
[[override]]
|
||||
branch = "master"
|
||||
name = "k8s.io/utils"
|
||||
|
||||
[[constraint]]
|
||||
[[override]]
|
||||
branch = "master"
|
||||
name = "github.com/go-openapi/spec"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/go-getter"
|
||||
|
||||
@@ -127,7 +127,7 @@ This tool is sponsored by [sig-cli] ([KEP]).
|
||||
[examples]: examples/README.md
|
||||
[imageBase]: docs/base.jpg
|
||||
[imageOverlay]: docs/overlay.jpg
|
||||
[install]: INSTALL.md
|
||||
[install]: docs/INSTALL.md
|
||||
[kubernetes style]: docs/glossary.md#kubernetes-style-object
|
||||
[kustomization]: docs/glossary.md#kustomization
|
||||
[overlay]: docs/glossary.md#overlay
|
||||
|
||||
@@ -41,14 +41,14 @@ function testGoLint {
|
||||
diff -u <(echo -n) <(go_dirs | xargs -0 golint --min_confidence 0.85 )
|
||||
}
|
||||
|
||||
# Not using the 'goimports' check because it reports hyphens in imported
|
||||
# package names as errors, and we vendor in packages that have
|
||||
# hyphens in their names.
|
||||
function testGoMetalinter {
|
||||
diff -u <(echo -n) <(go_dirs | xargs -0 gometalinter.v2 --disable-all --deadline 5m \
|
||||
--enable=misspell \
|
||||
--enable=structcheck \
|
||||
--enable=deadcode \
|
||||
# Disabling 'goimports' because it reports hyphens in imported package \
|
||||
# names as errors, and we have to vendor them in regardless. \
|
||||
# --enable=goimports \
|
||||
--enable=varcheck \
|
||||
--enable=goconst \
|
||||
--enable=unparam \
|
||||
@@ -60,7 +60,6 @@ function testGoMetalinter {
|
||||
--dupl-threshold=400 --enable=dupl)
|
||||
}
|
||||
|
||||
|
||||
function testGoVet {
|
||||
go vet -all ./...
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[Kubernetes Community Code of Conduct]: https://git.k8s.io/community/code-of-conduct.md
|
||||
|
||||
# Code of Conduct
|
||||
|
||||
This project has adopted the
|
||||
[Kubernetes Community Code of Conduct].
|
||||
4
docs/CODE_OF_CONDUCT.md
Normal file
4
docs/CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Kustomize Community Code of Conduct
|
||||
|
||||
Kustomize contributers expected to adhere to
|
||||
the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
||||
@@ -3,7 +3,13 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Download a binary from the [release page].
|
||||
On macOS, you can install kustomize with Homebrew package
|
||||
manager:
|
||||
|
||||
brew install kustomize
|
||||
|
||||
For all operating systems, download a binary from the
|
||||
[release page].
|
||||
|
||||
Or try this to grab the latest official release
|
||||
using the command line:
|
||||
23
docs/README.md
Normal file
23
docs/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Kustomize docs
|
||||
|
||||
* [installation instructions](INSTALL.md)
|
||||
|
||||
* [kustomization.yaml](kustomization.yaml) - Example of a
|
||||
[kustomization](glossary.md#kustomization)
|
||||
with explanations of each field.
|
||||
|
||||
* [workflow](workflows.md) - Some steps one might take in using
|
||||
bespoke and off-the-shelf configurations.
|
||||
|
||||
* [glossary](glossary.md) - An attempt to disambiguiate terminology.
|
||||
|
||||
* [eschewed features](eschewedFeatures.md) - Why certain features are (currently)
|
||||
not supported in Kustomize.
|
||||
|
||||
* [contributing guidelines](CONTRIBUTING.md) - Please read before sending a PR.
|
||||
|
||||
* [code of conduct](CODE_OF_CONDUCT.md)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -285,7 +285,7 @@ The _target_ is the argument to `kustomize build`, e.g.:
|
||||
> kustomize build $target
|
||||
> ```
|
||||
|
||||
`$target` must be a path to a directory that
|
||||
`$target` must be a path or a url to a directory that
|
||||
immediately contains a [kustomization].
|
||||
|
||||
The target contains, or refers to, all the information
|
||||
|
||||
@@ -83,15 +83,29 @@ secretGenerator:
|
||||
tls.key: "cat secret/tls.key"
|
||||
type: "kubernetes.io/tls"
|
||||
- name: downloaded_secret
|
||||
# timeoutSeconds specifies the number of seconds to
|
||||
# wait for the commands below. It defaults to 5 seconds.
|
||||
timeoutSeconds: 30
|
||||
commands:
|
||||
username: "curl -s https://path/to/secrets/username.yaml"
|
||||
password: "curl -s https://path/to/secrets/password.yaml"
|
||||
type: Opaque
|
||||
- name: env_file_secret
|
||||
# envCommand is similar to command but outputs lines of key=val pairs
|
||||
# i.e. a Docker .env file or a .ini file.
|
||||
# you can only specify one envCommand per secret.
|
||||
envCommand: printf \"DB_USERNAME=admin\nDB_PASSWORD=somepw\"
|
||||
type: Opaque
|
||||
|
||||
# Each entry in this list should resolve to a directory
|
||||
# containing a kustomization file, else the
|
||||
# customization fails.
|
||||
#
|
||||
# The entry could be a relative path pointing to a local directory
|
||||
# or a url pointing to a directory in a remote repo.
|
||||
# The url should follow hashicorp/go-getter URL format
|
||||
# https://github.com/hashicorp/go-getter#url-format
|
||||
#
|
||||
# The presence of this field means this file (the file
|
||||
# you a reading) is an _overlay_ that further
|
||||
# customizes information coming from these _bases_.
|
||||
@@ -102,6 +116,9 @@ secretGenerator:
|
||||
# etc. that differ from the common base).
|
||||
bases:
|
||||
- ../../base
|
||||
- github.com/kubernetes-sigs/kustomize//examples/multibases?ref=v1.0.6
|
||||
- github.com/Liujingfang1/mysql
|
||||
- github.com/Liujingfang1/kustomize//examples/helloWorld?ref=test-branch
|
||||
|
||||
# Each entry in this list should resolve to
|
||||
# a partial or complete resource definition file.
|
||||
|
||||
@@ -21,14 +21,17 @@ use and maintain a configuration.
|
||||
|
||||
## Bespoke configuration
|
||||
|
||||
In this workflow, all configuration files are owned by
|
||||
the user. No content is incorporated from version
|
||||
In this workflow, all configuration (resource YAML) files
|
||||
are owned by the user. No content is incorporated from version
|
||||
control repositories owned by others.
|
||||
|
||||
![bespoke config workflow image][workflowBespoke]
|
||||
|
||||
#### 1) create a directory in version control
|
||||
|
||||
Speculate some overall cluster application called _ldap_;
|
||||
we want to keep its configuration in its own repo.
|
||||
|
||||
> ```
|
||||
> git init ~/ldap
|
||||
> ```
|
||||
|
||||
@@ -37,4 +37,6 @@ go get github.com/kubernetes-sigs/kustomize
|
||||
|
||||
* [image tags](imageTags.md) - Updating image tags without applying a patch.
|
||||
|
||||
* [multibases](multibases/README.md) - Composing three variants (dev, staging, production) with a common base.
|
||||
* [multibases](multibases/README.md) - Composing three variants (dev, staging, production) with a common base.
|
||||
|
||||
* [remote target](remoteBuild.md) - Building a kustomization from a github URL
|
||||
|
||||
@@ -109,8 +109,8 @@ configuration is to
|
||||
|
||||
This latter change initiates rolling update to the pods
|
||||
in the deployment. The older configMap, when no longer
|
||||
referenced by any other resource, is eventually garbage
|
||||
collected.
|
||||
referenced by any other resource, is eventually [garbage
|
||||
collected](https://github.com/kubernetes-sigs/kustomize/issues/242).
|
||||
|
||||
### How this works with kustomize
|
||||
|
||||
|
||||
58
examples/remoteBuild.md
Normal file
58
examples/remoteBuild.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# remote targets
|
||||
|
||||
`kustomize build` can be run against a url. The effect is the same as cloing the repo, checking out the specified ref,
|
||||
then running `kustomize build` against the desired directory in the local copy.
|
||||
|
||||
Take `github.com/kubernetes-sigs/kustomize//examples/multibases?ref=v1.0.6` as an example.
|
||||
According to [multibases](multibases/README.md) demo, this kustomization contains three Pod objects with names as
|
||||
`cluster-a-dev-myapp-pod`, `cluster-a-stag-myapp-pod`, `cluster-a-prod-myapp-pod`.
|
||||
Running `kustomize build` against the url gives the same output.
|
||||
|
||||
<!-- @remoteBuild @test -->
|
||||
```
|
||||
target=github.com/kubernetes-sigs/kustomize//examples/multibases?ref=v1.0.6
|
||||
test 3 == \
|
||||
$(kustomize build $target | grep cluster-a-.*-myapp-pod | wc -l); \
|
||||
echo $?
|
||||
```
|
||||
|
||||
A base can also be specified as a URL:
|
||||
|
||||
<!-- @createOverlay @test -->
|
||||
```
|
||||
DEMO_HOME=$(mktemp -d)
|
||||
|
||||
cat <<EOF >$DEMO_HOME/kustomization.yaml
|
||||
bases:
|
||||
- github.com/kubernetes-sigs/kustomize//examples/multibases?ref=v1.0.6
|
||||
namePrefix: remote-
|
||||
EOF
|
||||
```
|
||||
Running `kustomize build $DEMO_HOME` and confirm the output contains three Pods and all have `remote-` prefix.
|
||||
<!-- @remoteBases @test -->
|
||||
```
|
||||
test 3 == \
|
||||
$(kustomize build $DEMO_HOME | grep remote-.*-myapp-pod | wc -l); \
|
||||
echo $?
|
||||
```
|
||||
|
||||
## URL format
|
||||
The url should follow
|
||||
[hashicorp/go-getter URL format](https://github.com/hashicorp/go-getter#url-format).
|
||||
Here are some example urls pointing to Github repos following this convention.
|
||||
|
||||
- a repo with a root level kustomization.yaml
|
||||
|
||||
`github.com/Liujingfang1/mysql`
|
||||
- a repo with a root level kustomization.yaml on branch test
|
||||
|
||||
`github.com/Liujingfang1/mysql?ref=test`
|
||||
- a subdirectory in a repo on version v1.0.6
|
||||
|
||||
`github.com/kubernetes-sigs/kustomize//examples/multibases?ref=v1.0.6`
|
||||
- a subdirectory in a repo on branch repoUrl2
|
||||
|
||||
`github.com/Liujingfang1/kustomize//examples/helloWorld?ref=repoUrl2`
|
||||
- a subdirectory in a repo on commit `7050a45134e9848fca214ad7e7007e96e5042c03`
|
||||
|
||||
`github.com/Liujingfang1/kustomize//examples/helloWorld?ref=7050a45134e9848fca214ad7e7007e96e5042c03`
|
||||
@@ -53,6 +53,8 @@ bases:
|
||||
- wordpress
|
||||
- mysql
|
||||
namePrefix: demo-
|
||||
patches:
|
||||
- patch.yaml
|
||||
EOF
|
||||
```
|
||||
|
||||
@@ -65,7 +67,7 @@ In the new kustomization, apply a patch for wordpress deployment. The patch does
|
||||
```
|
||||
CONTENT="https://raw.githubusercontent.com\
|
||||
/kubernetes-sigs/kustomize\
|
||||
/master/examples/patch.yaml"
|
||||
/master/examples/wordpress"
|
||||
|
||||
curl -s -o "$DEMO_HOME/#1.yaml" \
|
||||
"$CONTENT/{patch}.yaml"
|
||||
|
||||
@@ -86,20 +86,6 @@ func (a *Application) MakeCustomizedResMap() (resmap.ResMap, error) {
|
||||
return a.resolveRefsToGeneratedResources(m)
|
||||
}
|
||||
|
||||
// MakeUncustomizedResMap purports to create a ResMap without customization.
|
||||
// The Resources in the returned ResMap include all resources mentioned
|
||||
// in the kustomization file and transitively reachable via its Bases,
|
||||
// and all generated secrets and configMaps.
|
||||
// Meant for use in generating a diff against customized resources.
|
||||
// TODO: See https://github.com/kubernetes-sigs/kustomize/issues/85
|
||||
func (a *Application) MakeUncustomizedResMap() (resmap.ResMap, error) {
|
||||
m, err := a.loadResMapFromBasesAndResources()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return a.resolveRefsToGeneratedResources(m)
|
||||
}
|
||||
|
||||
// resolveRefsToGeneratedResources fixes all name references.
|
||||
func (a *Application) resolveRefsToGeneratedResources(m resmap.ResMap) (resmap.ResMap, error) {
|
||||
err := transformers.NewNameHashTransformer().Transform(m)
|
||||
@@ -226,6 +212,7 @@ func (a *Application) loadCustomizedBases() (resmap.ResMap, *interror.Kustomizat
|
||||
errs.Append(errors.Wrap(err, "SemiResources"))
|
||||
continue
|
||||
}
|
||||
ldr.Cleanup()
|
||||
list = append(list, resMap)
|
||||
}
|
||||
result, err := resmap.MergeWithoutOverride(list...)
|
||||
@@ -322,6 +309,7 @@ func (a *Application) getAllVars() ([]types.Var, error) {
|
||||
errs.Append(err)
|
||||
continue
|
||||
}
|
||||
b.ldr.Cleanup()
|
||||
result = append(result, vars...)
|
||||
}
|
||||
for _, v := range a.kustomization.Vars {
|
||||
|
||||
@@ -19,6 +19,7 @@ package app
|
||||
import (
|
||||
"encoding/base64"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
@@ -53,6 +54,14 @@ secretGenerator:
|
||||
DB_USERNAME: "printf admin"
|
||||
DB_PASSWORD: "printf somepw"
|
||||
type: Opaque
|
||||
`
|
||||
kustomizationContent2 = `
|
||||
secretGenerator:
|
||||
- name: secret
|
||||
timeoutSeconds: 1
|
||||
commands:
|
||||
USER: "sleep 2"
|
||||
type: Opaque
|
||||
`
|
||||
deploymentContent = `apiVersion: apps/v1
|
||||
metadata:
|
||||
@@ -87,7 +96,6 @@ var deploy = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deploy
|
||||
var cmap = schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}
|
||||
var secret = schema.GroupVersionKind{Version: "v1", Kind: "Secret"}
|
||||
var ns = schema.GroupVersionKind{Version: "v1", Kind: "Namespace"}
|
||||
var svc = schema.GroupVersionKind{Version: "v1", Kind: "Service"}
|
||||
|
||||
func TestResources1(t *testing.T) {
|
||||
expected := resmap.ResMap{
|
||||
@@ -197,146 +205,44 @@ func TestResources1(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRawResources1(t *testing.T) {
|
||||
expected := resmap.ResMap{
|
||||
resource.NewResId(deploy, "dply1"): resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "dply1",
|
||||
},
|
||||
}),
|
||||
resource.NewResId(ns, "ns1"): resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Namespace",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "ns1",
|
||||
},
|
||||
}),
|
||||
func TestResourceNotFound(t *testing.T) {
|
||||
l := loadertest.NewFakeLoader("/testpath")
|
||||
err := l.AddFile("/testpath/"+constants.KustomizationFileName, []byte(kustomizationContent1))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
l := makeLoader1(t)
|
||||
app, err := NewApplication(l, fs.MakeFakeFS())
|
||||
fakeFs := fs.MakeFakeFS()
|
||||
fakeFs.Mkdir("/")
|
||||
app, err := NewApplication(l, fakeFs)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected construction error %v", err)
|
||||
}
|
||||
actual, err := app.MakeUncustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected RawResources error %v", err)
|
||||
_, err = app.MakeCustomizedResMap()
|
||||
if err == nil {
|
||||
t.Fatalf("Didn't get the expected error for an unknown resource")
|
||||
}
|
||||
|
||||
if err := expected.ErrorIfNotEqual(actual); err != nil {
|
||||
t.Fatalf("unexpected inequality: %v", err)
|
||||
if !strings.Contains(err.Error(), `cannot read file "/testpath/deployment.yaml"`) {
|
||||
t.Fatalf("Unpexpected error message %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
kustomizationContentBase = `
|
||||
namePrefix: foo-
|
||||
commonLabels:
|
||||
app: banana
|
||||
resources:
|
||||
- deployment.yaml
|
||||
`
|
||||
kustomizationContentOverlay = `
|
||||
commonLabels:
|
||||
env: staging
|
||||
resources:
|
||||
- service.yaml
|
||||
bases:
|
||||
- base
|
||||
`
|
||||
serviceContent = `apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: svc
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
`
|
||||
)
|
||||
|
||||
func makeLoader2(t *testing.T) loader.Loader {
|
||||
ldr := loadertest.NewFakeLoader("/testpath")
|
||||
err := ldr.AddFile("/testpath/"+constants.KustomizationFileName, []byte(kustomizationContentOverlay))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ldr.AddFile("/testpath/service.yaml", []byte(serviceContent))
|
||||
func TestSecretTimeout(t *testing.T) {
|
||||
l := loadertest.NewFakeLoader("/testpath")
|
||||
err := l.AddFile("/testpath/"+constants.KustomizationFileName, []byte(kustomizationContent2))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
err = ldr.AddDirectory("/testpath/base")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
err = ldr.AddFile("/testpath/base/"+constants.KustomizationFileName, []byte(kustomizationContentBase))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
err = ldr.AddFile("/testpath/base/deployment.yaml", []byte(deploymentContent))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to setup fake ldr.")
|
||||
}
|
||||
return ldr
|
||||
}
|
||||
|
||||
// TODO: This test covers incorrect behavior; it should not pass.
|
||||
// It asks for raw resources. The Service resource is returned in raw form,
|
||||
// but the resources in the base are modified to have the banana label,
|
||||
// the 'foo' name prefix, etc. This method exists only to support the
|
||||
// diff command comparing customized to non-customized resources;
|
||||
// perhaps it's not worth supporting the command.
|
||||
func TestRawResources2(t *testing.T) {
|
||||
expected := resmap.ResMap{
|
||||
resource.NewResIdWithPrefix(deploy, "dply1", "foo-"): resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo-dply1",
|
||||
"labels": map[string]interface{}{
|
||||
"app": "banana",
|
||||
},
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"selector": map[string]interface{}{
|
||||
"matchLabels": map[string]interface{}{
|
||||
"app": "banana",
|
||||
},
|
||||
},
|
||||
"template": map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]interface{}{
|
||||
"app": "banana",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
resource.NewResId(svc, "svc"): resource.NewResourceFromMap(
|
||||
map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Service",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "svc",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"type": "LoadBalancer",
|
||||
},
|
||||
}),
|
||||
}
|
||||
l := makeLoader2(t)
|
||||
app, err := NewApplication(l, fs.MakeFakeFS())
|
||||
fakeFs := fs.MakeFakeFS()
|
||||
fakeFs.Mkdir("/")
|
||||
app, err := NewApplication(l, fakeFs)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected construction error %v", err)
|
||||
}
|
||||
actual, err := app.MakeUncustomizedResMap()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected RawResources error %v", err)
|
||||
_, err = app.MakeCustomizedResMap()
|
||||
if err == nil {
|
||||
t.Fatalf("Didn't get the expected error for an unknown resource")
|
||||
}
|
||||
|
||||
if err := expected.ErrorIfNotEqual(actual); err != nil {
|
||||
t.Fatalf("unexpected inequality: %v", err)
|
||||
if !strings.Contains(err.Error(), "killed") {
|
||||
t.Fatalf("Unpexpected error message %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
172
pkg/commands/addmetadata.go
Normal file
172
pkg/commands/addmetadata.go
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/validate"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// KindOfAdd is the kind of metadata being added: label or annotation
|
||||
type KindOfAdd int
|
||||
|
||||
const (
|
||||
annotation KindOfAdd = iota
|
||||
label
|
||||
)
|
||||
|
||||
func (k KindOfAdd) String() string {
|
||||
kinds := [...]string{
|
||||
"annotation",
|
||||
"label",
|
||||
}
|
||||
if k < 0 || k > 1 {
|
||||
return "Unknown metadatakind"
|
||||
}
|
||||
return kinds[k]
|
||||
}
|
||||
|
||||
type addMetadataOptions struct {
|
||||
metadata map[string]string
|
||||
}
|
||||
|
||||
// newCmdAddAnnotation adds one or more commonAnnotations to the kustomization file.
|
||||
func newCmdAddAnnotation(fsys fs.FileSystem) *cobra.Command {
|
||||
var o addMetadataOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "annotation",
|
||||
Short: "Adds one or more commonAnnotations to the kustomization.yaml in current directory",
|
||||
Example: `
|
||||
add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := o.ValidateAndParse(args, annotation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.RunAddAnnotation(fsys, annotation)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// newCmdAddLabel adds one or more commonLabels to the kustomization file.
|
||||
func newCmdAddLabel(fsys fs.FileSystem) *cobra.Command {
|
||||
var o addMetadataOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "label",
|
||||
Short: "Adds one or more commonLabels to the kustomization.yaml in current directory",
|
||||
Example: `
|
||||
add label {labelKey1:labelValue1},{labelKey2:labelValue2}`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := o.ValidateAndParse(args, label)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.RunAddLabel(fsys, label)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ValidateAndParse validates addLabel and addAnnotation commands and parses them into o.metadata
|
||||
func (o *addMetadataOptions) ValidateAndParse(args []string, k KindOfAdd) error {
|
||||
o.metadata = make(map[string]string)
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("must specify %s", k)
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return fmt.Errorf("%ss must be comma-separated, with no spaces. See help text for example", k)
|
||||
}
|
||||
inputs := strings.Split(args[0], ",")
|
||||
for _, input := range inputs {
|
||||
switch k {
|
||||
case label:
|
||||
valid, err := validate.IsValidLabel(input)
|
||||
if !valid {
|
||||
return err
|
||||
}
|
||||
case annotation:
|
||||
valid, err := validate.IsValidAnnotation(input)
|
||||
if !valid {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown metadata kind %s", k)
|
||||
}
|
||||
//parse annotation keys and values into metadata
|
||||
kv := strings.Split(input, ":")
|
||||
o.metadata[kv[0]] = kv[1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunAddAnnotation runs addAnnotation command, doing the real work.
|
||||
func (o *addMetadataOptions) RunAddAnnotation(fsys fs.FileSystem, k KindOfAdd) error {
|
||||
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := mf.read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.CommonAnnotations == nil {
|
||||
m.CommonAnnotations = make(map[string]string)
|
||||
}
|
||||
|
||||
for key, value := range o.metadata {
|
||||
if k == annotation {
|
||||
if _, ok := m.CommonAnnotations[key]; ok {
|
||||
return fmt.Errorf("%s %s already in kustomization file", k, key)
|
||||
}
|
||||
m.CommonAnnotations[key] = value
|
||||
}
|
||||
}
|
||||
return mf.write(m)
|
||||
}
|
||||
|
||||
// RunAddLabel runs addLabel command, doing the real work.
|
||||
func (o *addMetadataOptions) RunAddLabel(fsys fs.FileSystem, k KindOfAdd) error {
|
||||
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := mf.read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.CommonLabels == nil {
|
||||
m.CommonLabels = make(map[string]string)
|
||||
}
|
||||
|
||||
for key, value := range o.metadata {
|
||||
if _, ok := m.CommonLabels[key]; ok {
|
||||
return fmt.Errorf("%s %s already in kustomization file", k, key)
|
||||
}
|
||||
m.CommonLabels[key] = value
|
||||
}
|
||||
return mf.write(m)
|
||||
}
|
||||
190
pkg/commands/addmetadata_test.go
Normal file
190
pkg/commands/addmetadata_test.go
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
func TestParseValidateInput(t *testing.T) {
|
||||
var testcases = []struct {
|
||||
input string
|
||||
valid bool
|
||||
name string
|
||||
expectedData map[string]string
|
||||
kind KindOfAdd
|
||||
}{
|
||||
{
|
||||
input: "otters:cute",
|
||||
valid: true,
|
||||
name: "Adds single input",
|
||||
expectedData: map[string]string{
|
||||
"otters": "cute",
|
||||
},
|
||||
kind: label,
|
||||
},
|
||||
{
|
||||
input: "owls:great,unicorns:magical",
|
||||
valid: true,
|
||||
name: "Adds two items",
|
||||
expectedData: map[string]string{
|
||||
"owls": "great",
|
||||
"unicorns": "magical",
|
||||
},
|
||||
kind: label,
|
||||
},
|
||||
{
|
||||
input: "123:45",
|
||||
valid: true,
|
||||
name: "Numeric input is allowed",
|
||||
expectedData: map[string]string{
|
||||
"123": "45",
|
||||
},
|
||||
kind: annotation,
|
||||
},
|
||||
{
|
||||
input: " ",
|
||||
valid: false,
|
||||
name: "Empty space input",
|
||||
expectedData: nil,
|
||||
kind: annotation,
|
||||
},
|
||||
}
|
||||
var o addMetadataOptions
|
||||
for _, tc := range testcases {
|
||||
args := []string{tc.input}
|
||||
err := o.ValidateAndParse(args, tc.kind)
|
||||
if err != nil && tc.valid {
|
||||
t.Errorf("for test case %s, unexpected cmd error: %v", tc.name, err)
|
||||
}
|
||||
if err == nil && !tc.valid {
|
||||
t.Errorf("unexpected error: expected invalid format error for test case %v", tc.name)
|
||||
}
|
||||
//o.metadata should be the same as expectedData
|
||||
if tc.valid {
|
||||
if !reflect.DeepEqual(o.metadata, tc.expectedData) {
|
||||
t.Errorf("unexpected error: for test case %s, unexpected data was added", tc.name)
|
||||
}
|
||||
} else {
|
||||
if len(o.metadata) != 0 {
|
||||
t.Errorf("unexpected error: for test case %s, expected no data to be added", tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunAddAnnotation(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
var o addMetadataOptions
|
||||
o.metadata = map[string]string{"owls": "cute", "otters": "adorable"}
|
||||
|
||||
err := o.RunAddAnnotation(fakeFS, annotation)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: could not write to kustomization file")
|
||||
}
|
||||
// adding the same test input should not work
|
||||
err = o.RunAddAnnotation(fakeFS, annotation)
|
||||
if err == nil {
|
||||
t.Errorf("expected already in kustomization file error")
|
||||
}
|
||||
// adding new annotations should work
|
||||
o.metadata = map[string]string{"new": "annotation"}
|
||||
err = o.RunAddAnnotation(fakeFS, annotation)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: could not write to kustomization file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAnnotationNoArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
cmd := newCmdAddAnnotation(fakeFS)
|
||||
err := cmd.Execute()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error but error is %v", err)
|
||||
}
|
||||
if err != nil && err.Error() != "must specify annotation" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
func TestAddAnnotationMultipleArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
cmd := newCmdAddAnnotation(fakeFS)
|
||||
args := []string{"this:annotation", "has:spaces"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
if err == nil {
|
||||
t.Errorf("expected an error but error is %v", err)
|
||||
}
|
||||
if err != nil && err.Error() != "annotations must be comma-separated, with no spaces. See help text for example" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunAddLabel(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
var o addMetadataOptions
|
||||
o.metadata = map[string]string{"owls": "cute", "otters": "adorable"}
|
||||
|
||||
err := o.RunAddLabel(fakeFS, label)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: could not write to kustomization file")
|
||||
}
|
||||
// adding the same test input should not work
|
||||
err = o.RunAddLabel(fakeFS, label)
|
||||
if err == nil {
|
||||
t.Errorf("expected already in kustomization file error")
|
||||
}
|
||||
// adding new labels should work
|
||||
o.metadata = map[string]string{"new": "label"}
|
||||
err = o.RunAddLabel(fakeFS, label)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: could not write to kustomization file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddLabelNoArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
|
||||
cmd := newCmdAddLabel(fakeFS)
|
||||
err := cmd.Execute()
|
||||
if err == nil {
|
||||
t.Errorf("expected an error but error is: %v", err)
|
||||
}
|
||||
if err != nil && err.Error() != "must specify label" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddLabelMultipleArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
cmd := newCmdAddLabel(fakeFS)
|
||||
args := []string{"this:input", "has:spaces"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
if err == nil {
|
||||
t.Errorf("expected an error but error is: %v", err)
|
||||
}
|
||||
if err != nil && err.Error() != "labels must be comma-separated, with no spaces. See help text for example" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ package commands
|
||||
|
||||
import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
@@ -35,15 +34,29 @@ type buildOptions struct {
|
||||
outputPath string
|
||||
}
|
||||
|
||||
var examples = `
|
||||
Use the file somedir/kustomization.yaml to generate a set of api resources:
|
||||
build somedir
|
||||
|
||||
Use a url pointing to a remote directory/kustomization.yaml to generate a set of api resources:
|
||||
build url
|
||||
The url should follow hashicorp/go-getter URL format described in
|
||||
https://github.com/hashicorp/go-getter#url-format
|
||||
|
||||
url examples:
|
||||
github.com/kubernetes-sigs/kustomize//examples/multibases?ref=v1.0.6
|
||||
github.com/Liujingfang1/mysql
|
||||
github.com/Liujingfang1/kustomize//examples/helloWorld?ref=repoUrl2
|
||||
`
|
||||
|
||||
// newCmdBuild creates a new build command.
|
||||
func newCmdBuild(out io.Writer, fs fs.FileSystem) *cobra.Command {
|
||||
var o buildOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "build [path]",
|
||||
Short: "Print current configuration per contents of " + constants.KustomizationFileName,
|
||||
Example: "Use the file somedir/" + constants.KustomizationFileName +
|
||||
" to generate a set of api resources:\nbuild somedir/",
|
||||
Use: "build [path]",
|
||||
Short: "Print current configuration per contents of " + constants.KustomizationFileName,
|
||||
Example: examples,
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := o.Validate(args)
|
||||
@@ -75,17 +88,11 @@ func (o *buildOptions) Validate(args []string) error {
|
||||
|
||||
// RunBuild runs build command.
|
||||
func (o *buildOptions) RunBuild(out io.Writer, fSys fs.FileSystem) error {
|
||||
l := loader.NewFileLoader(fSys)
|
||||
|
||||
absPath, err := filepath.Abs(o.kustomizationPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rootLoader, err := l.New(absPath)
|
||||
rootLoader, err := loader.NewLoader(o.kustomizationPath, "", fSys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rootLoader.Cleanup()
|
||||
|
||||
application, err := app.NewApplication(rootLoader, fSys)
|
||||
if err != nil {
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
// NewDefaultCommand returns the default (aka root) command for kustomize command.
|
||||
func NewDefaultCommand() *cobra.Command {
|
||||
fsys := fs.MakeRealFS()
|
||||
stdOut, stdErr := os.Stdout, os.Stderr
|
||||
stdOut := os.Stdout
|
||||
|
||||
c := &cobra.Command{
|
||||
Use: "kustomize",
|
||||
@@ -43,7 +43,6 @@ See https://github.com/kubernetes-sigs/kustomize
|
||||
c.AddCommand(
|
||||
// TODO: Make consistent API for newCmd* functions.
|
||||
newCmdBuild(stdOut, fsys),
|
||||
newCmdDiff(stdOut, stdErr, fsys),
|
||||
newCmdEdit(fsys),
|
||||
newCmdVersion(stdOut),
|
||||
)
|
||||
@@ -96,6 +95,12 @@ func newCmdAdd(fsys fs.FileSystem) *cobra.Command {
|
||||
# Adds one or more base directories to the kustomization
|
||||
kustomize edit add base <filepath>
|
||||
kustomize edit add base <filepath1>,<filepath2>,<filepath3>
|
||||
|
||||
# Adds one or more commonLabels to the kustomization
|
||||
kustomize edit add label {labelKey1:labelValue1},{labelKey2:labelValue2}
|
||||
|
||||
# Adds one or more commonAnnotations to the kustomization
|
||||
kustomize edit add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}
|
||||
`,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
}
|
||||
@@ -104,6 +109,8 @@ func newCmdAdd(fsys fs.FileSystem) *cobra.Command {
|
||||
newCmdAddPatch(fsys),
|
||||
newCmdAddConfigMap(fsys),
|
||||
newCmdAddBase(fsys),
|
||||
newCmdAddLabel(fsys),
|
||||
newCmdAddAnnotation(fsys),
|
||||
)
|
||||
return c
|
||||
}
|
||||
@@ -123,6 +130,7 @@ func newCmdSet(fsys fs.FileSystem) *cobra.Command {
|
||||
|
||||
c.AddCommand(
|
||||
newCmdSetNamePrefix(fsys),
|
||||
newCmdSetNamespace(fsys),
|
||||
newCmdSetImageTag(fsys),
|
||||
)
|
||||
return c
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/app"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/diff"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
)
|
||||
|
||||
type diffOptions struct {
|
||||
kustomizationPath string
|
||||
}
|
||||
|
||||
// newCmdDiff makes the diff command.
|
||||
func newCmdDiff(out, errOut io.Writer, fs fs.FileSystem) *cobra.Command {
|
||||
var o diffOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "diff [path]",
|
||||
Short: "diff between customized resources and uncustomized resources",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := o.Validate(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.RunDiff(out, errOut, fs)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Validate validates diff command.
|
||||
func (o *diffOptions) Validate(args []string) error {
|
||||
if len(args) > 1 {
|
||||
return errors.New("specify one path to " + constants.KustomizationFileName)
|
||||
}
|
||||
if len(args) == 0 {
|
||||
o.kustomizationPath = "./"
|
||||
return nil
|
||||
}
|
||||
o.kustomizationPath = args[0]
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunDiff gets the differences between Application.MakeCustomizedResMap() and Application.MakeUncustomizedResMap().
|
||||
func (o *diffOptions) RunDiff(out, errOut io.Writer, fSys fs.FileSystem) error {
|
||||
|
||||
l := loader.NewFileLoader(fSys)
|
||||
|
||||
absPath, err := filepath.Abs(o.kustomizationPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rootLoader, err := l.New(absPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
application, err := app.NewApplication(rootLoader, fSys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
transformedResources, err := application.MakeCustomizedResMap()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rawResources, err := application.MakeUncustomizedResMap()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return diff.RunDiff(rawResources, transformedResources, out, errOut)
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package commands
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
type DiffTestCase struct {
|
||||
Description string `yaml:"description"`
|
||||
Args []string `yaml:"args"`
|
||||
Filename string `yaml:"filename"`
|
||||
// path to the file that contains the expected output
|
||||
ExpectedDiff string `yaml:"expectedDiff"`
|
||||
ExpectedError string `yaml:"expectedError"`
|
||||
}
|
||||
|
||||
func TestDiff(t *testing.T) {
|
||||
const updateEnvVar = "UPDATE_KUSTOMIZE_EXPECTED_DATA"
|
||||
updateKustomizeExpected := os.Getenv(updateEnvVar) == "true"
|
||||
|
||||
tempDir := regexp.QuoteMeta(filepath.Clean(os.TempDir()))
|
||||
noopDir, _ := regexp.Compile(tempDir + `/noop-[0-9]*/`)
|
||||
transformedDir, _ := regexp.Compile(tempDir + `/transformed-[0-9]*/`)
|
||||
timestamp, _ := regexp.Compile(`[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9].[0-9]* [+-]{1}[0-9]{4}`)
|
||||
|
||||
fSys := fs.MakeRealFS()
|
||||
|
||||
testcases := sets.NewString()
|
||||
filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if path == "testdata" {
|
||||
return nil
|
||||
}
|
||||
name := filepath.Base(path)
|
||||
if info.IsDir() {
|
||||
if strings.HasPrefix(name, "testcase-") {
|
||||
testcases.Insert(strings.TrimPrefix(name, "testcase-"))
|
||||
}
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
})
|
||||
// sanity check that we found the right folder
|
||||
if !testcases.Has("simple") {
|
||||
t.Fatalf("Error locating testcases")
|
||||
}
|
||||
|
||||
for _, testcaseName := range testcases.List() {
|
||||
t.Run(testcaseName, func(t *testing.T) {
|
||||
runDiffTestCase(t, testcaseName, updateKustomizeExpected, fSys,
|
||||
noopDir, transformedDir, timestamp)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func runDiffTestCase(t *testing.T, testcaseName string, updateKustomizeExpected bool, fs fs.FileSystem,
|
||||
noopDir, transformedDir, timestamp *regexp.Regexp) {
|
||||
name := testcaseName
|
||||
testcase := DiffTestCase{}
|
||||
testcaseDir := filepath.Join("testdata", "testcase-"+name)
|
||||
testcaseData, err := ioutil.ReadFile(filepath.Join(testcaseDir, "test.yaml"))
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", name, err)
|
||||
}
|
||||
if err := yaml.Unmarshal(testcaseData, &testcase); err != nil {
|
||||
t.Fatalf("%s: %v", name, err)
|
||||
}
|
||||
|
||||
diffOps := &diffOptions{
|
||||
kustomizationPath: testcase.Filename,
|
||||
}
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
err = diffOps.RunDiff(buf, os.Stderr, fs)
|
||||
switch {
|
||||
case err != nil && len(testcase.ExpectedError) == 0:
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
case err != nil && len(testcase.ExpectedError) != 0:
|
||||
if !strings.Contains(err.Error(), testcase.ExpectedError) {
|
||||
t.Errorf("expected error to contain %q but got: %v", testcase.ExpectedError, err)
|
||||
}
|
||||
return
|
||||
case err == nil && len(testcase.ExpectedError) != 0:
|
||||
t.Errorf("unexpected no error")
|
||||
}
|
||||
|
||||
actualString := string(buf.Bytes())
|
||||
actualString = noopDir.ReplaceAllString(actualString, "/tmp/noop/")
|
||||
actualString = transformedDir.ReplaceAllString(actualString, "/tmp/transformed/")
|
||||
actualString = timestamp.ReplaceAllString(actualString, "YYYY-MM-DD HH:MM:SS")
|
||||
actualBytes := []byte(actualString)
|
||||
if !updateKustomizeExpected {
|
||||
expectedBytes, err := ioutil.ReadFile(testcase.ExpectedDiff)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(actualBytes, expectedBytes) {
|
||||
t.Errorf("%s\ndoesn't equal expected:\n%s\n", actualBytes, expectedBytes)
|
||||
}
|
||||
} else {
|
||||
ioutil.WriteFile(testcase.ExpectedDiff, actualBytes, 0644)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,8 +35,23 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
kustomizationFields = []string{"resources", "bases", "namePrefix", "namespace", "crds", "commonLabels", "commonAnnotations", "patches", "configMapGenerator", "secretGenerator", "vars", "imageTags"}
|
||||
recognizedFields = regexp.MustCompile("^(" + strings.Join(kustomizationFields, "|") + "):")
|
||||
// These field names are the exact kustomization fields
|
||||
kustomizationFields = []string{
|
||||
"APIVersion",
|
||||
"Kind",
|
||||
"Resources",
|
||||
"Bases",
|
||||
"NamePrefix",
|
||||
"Namespace",
|
||||
"Crds",
|
||||
"CommonLabels",
|
||||
"CommonAnnotations",
|
||||
"Patches",
|
||||
"ConfigMapGenerator",
|
||||
"SecretGenerator",
|
||||
"Vars",
|
||||
"ImageTags",
|
||||
}
|
||||
)
|
||||
|
||||
// commentedField records the comment associated with a kustomization field
|
||||
@@ -51,6 +66,10 @@ func (cf *commentedField) appendComment(comment []byte) {
|
||||
cf.comment = append(cf.comment, comment...)
|
||||
}
|
||||
|
||||
func squash(x [][]byte) []byte {
|
||||
return bytes.Join(x, []byte(``))
|
||||
}
|
||||
|
||||
type kustomizationFile struct {
|
||||
path string
|
||||
fsys fs.FileSystem
|
||||
@@ -90,16 +109,16 @@ func (mf *kustomizationFile) validate() error {
|
||||
}
|
||||
|
||||
func (mf *kustomizationFile) read() (*types.Kustomization, error) {
|
||||
bytes, err := mf.fsys.ReadFile(mf.path)
|
||||
data, err := mf.fsys.ReadFile(mf.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var kustomization types.Kustomization
|
||||
err = yaml.Unmarshal(bytes, &kustomization)
|
||||
err = yaml.Unmarshal(data, &kustomization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = mf.parseCommentedFields(bytes)
|
||||
err = mf.parseCommentedFields(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -110,11 +129,11 @@ func (mf *kustomizationFile) write(kustomization *types.Kustomization) error {
|
||||
if kustomization == nil {
|
||||
return errors.New("util: kustomization file arg is nil")
|
||||
}
|
||||
bytes, err := mf.marshal(kustomization)
|
||||
data, err := mf.marshal(kustomization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return mf.fsys.WriteFile(mf.path, bytes)
|
||||
return mf.fsys.WriteFile(mf.path, data)
|
||||
}
|
||||
|
||||
func stringInSlice(str string, list []string) bool {
|
||||
@@ -129,20 +148,20 @@ func stringInSlice(str string, list []string) bool {
|
||||
func (mf *kustomizationFile) parseCommentedFields(content []byte) error {
|
||||
buffer := bytes.NewBuffer(content)
|
||||
var comments [][]byte
|
||||
var currentfield string
|
||||
|
||||
line, err := buffer.ReadBytes('\n')
|
||||
for err == nil {
|
||||
if isCommentOrBlankLine(line) {
|
||||
comments = append(comments, line)
|
||||
} else if recognizedFields.Match(line) {
|
||||
fields := recognizedFields.FindSubmatch(line)
|
||||
currentfield = string(fields[1])
|
||||
mf.originalFields = append(mf.originalFields, &commentedField{field: currentfield, comment: bytes.Join(comments, []byte(``))})
|
||||
comments = [][]byte{}
|
||||
} else if len(comments) > 0 {
|
||||
mf.originalFields[len(mf.originalFields)-1].appendComment(bytes.Join(comments, []byte(``)))
|
||||
comments = [][]byte{}
|
||||
} else {
|
||||
matched, field := findMatchedField(line)
|
||||
if matched {
|
||||
mf.originalFields = append(mf.originalFields, &commentedField{field: field, comment: squash(comments)})
|
||||
comments = [][]byte{}
|
||||
} else if len(comments) > 0 {
|
||||
mf.originalFields[len(mf.originalFields)-1].appendComment(squash(comments))
|
||||
comments = [][]byte{}
|
||||
}
|
||||
}
|
||||
line, err = buffer.ReadBytes('\n')
|
||||
}
|
||||
@@ -154,7 +173,7 @@ func (mf *kustomizationFile) parseCommentedFields(content []byte) error {
|
||||
}
|
||||
|
||||
func (mf *kustomizationFile) marshal(kustomization *types.Kustomization) ([]byte, error) {
|
||||
output := []byte{}
|
||||
var output []byte
|
||||
for _, comment := range mf.originalFields {
|
||||
output = append(output, comment.comment...)
|
||||
content, err := marshalField(comment.field, kustomization)
|
||||
@@ -199,6 +218,17 @@ func isCommentOrBlankLine(line []byte) bool {
|
||||
return len(s) == 0 || bytes.HasPrefix(s, []byte(`#`))
|
||||
}
|
||||
|
||||
func findMatchedField(line []byte) (bool, string) {
|
||||
for _, field := range kustomizationFields {
|
||||
// (?i) is for case insensitive regexp matching
|
||||
r := regexp.MustCompile("^(" + "(?i)" + field + "):")
|
||||
if r.Match(line) {
|
||||
return true, field
|
||||
}
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// marshalField marshal a given field of a kustomization object into yaml format.
|
||||
// If the field wasn't in the original kustomization.yaml file or wasn't added,
|
||||
// an empty []byte is returned.
|
||||
|
||||
@@ -147,6 +147,8 @@ resources:
|
||||
# See which field this comment goes into
|
||||
- service.yaml
|
||||
|
||||
APIVersion: v1beta1
|
||||
kind: kustomization.yaml
|
||||
|
||||
# something you may want to keep
|
||||
vars:
|
||||
@@ -158,7 +160,7 @@ vars:
|
||||
kind: Service
|
||||
name: my-service
|
||||
|
||||
bases:
|
||||
BASES:
|
||||
- ../namespaces
|
||||
|
||||
# some descriptions for the patches
|
||||
@@ -180,6 +182,8 @@ resources:
|
||||
- pod.yaml
|
||||
- service.yaml
|
||||
|
||||
apiVersion: v1beta1
|
||||
kind: kustomization.yaml
|
||||
|
||||
# something you may want to keep
|
||||
vars:
|
||||
|
||||
@@ -69,13 +69,13 @@ and overwrite the previous newTag if the image name exists.
|
||||
// Validate validates setImageTag command.
|
||||
func (o *setImageTagOptions) Validate(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.New("No image and newTag specified.")
|
||||
return errors.New("no image and newTag specified")
|
||||
}
|
||||
o.imageTagMap = make(map[string]string)
|
||||
for _, arg := range args {
|
||||
imagetag := pattern.FindStringSubmatch(arg)
|
||||
if len(imagetag) != 3 {
|
||||
return errors.New("Invalid format of imagetag, must specify it as <image>:<newtag>")
|
||||
return errors.New("invalid format of imagetag, must specify it as <image>:<newtag>")
|
||||
}
|
||||
o.imageTagMap[imagetag[1]] = imagetag[2]
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ func TestSetImageTagsNoArgs(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Errorf("expected error: %v", err)
|
||||
}
|
||||
if err.Error() != "No image and newTag specified." {
|
||||
if err.Error() != "no image and newTag specified" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
83
pkg/commands/setnamespace.go
Normal file
83
pkg/commands/setnamespace.go
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
)
|
||||
|
||||
type setNamespaceOptions struct {
|
||||
namespace string
|
||||
}
|
||||
|
||||
// newCmdSetNamespace sets the value of the namespace field in the kustomization.
|
||||
func newCmdSetNamespace(fsys fs.FileSystem) *cobra.Command {
|
||||
var o setNamespaceOptions
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "namespace",
|
||||
Short: "Sets the value of the namespace field in the kustomization file",
|
||||
Example: `
|
||||
The command
|
||||
set namespace staging
|
||||
will add the field "namespace: staging" to the kustomization file if it doesn't exist,
|
||||
and overwrite the value with "staging" if the field does exist.
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := o.Validate(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return o.RunSetNamespace(fsys)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Validate validates setNamespace command.
|
||||
func (o *setNamespaceOptions) Validate(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.New("must specify exactly one namespace value")
|
||||
}
|
||||
ns := args[0]
|
||||
if errs := validation.IsDNS1123Label(ns); len(errs) != 0 {
|
||||
return fmt.Errorf("%q is not a valid namespace name: %s", ns, strings.Join(errs, ";"))
|
||||
}
|
||||
o.namespace = ns
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunSetNamespace runs setNamespace command (does real work).
|
||||
func (o *setNamespaceOptions) RunSetNamespace(fsys fs.FileSystem) error {
|
||||
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := mf.read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Namespace = o.namespace
|
||||
return mf.write(m)
|
||||
}
|
||||
103
pkg/commands/setnamespace_test.go
Normal file
103
pkg/commands/setnamespace_test.go
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
const (
|
||||
goodNamespaceValue = "staging"
|
||||
)
|
||||
|
||||
func TestSetNamespaceHappyPath(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
|
||||
cmd := newCmdSetNamespace(fakeFS)
|
||||
args := []string{goodNamespaceValue}
|
||||
err := cmd.RunE(cmd, args)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected cmd error: %v", err)
|
||||
}
|
||||
content, err := fakeFS.ReadFile(constants.KustomizationFileName)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected read error: %v", err)
|
||||
}
|
||||
expected := []byte(fmt.Sprintf("namespace: %s", goodNamespaceValue))
|
||||
if !strings.Contains(string(content), string(expected)) {
|
||||
t.Errorf("expected namespace in kustomization file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetNamespaceOverride(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
|
||||
cmd := newCmdSetNamespace(fakeFS)
|
||||
args := []string{goodNamespaceValue}
|
||||
err := cmd.RunE(cmd, args)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected cmd error: %v", err)
|
||||
}
|
||||
args = []string{"newnamespace"}
|
||||
err = cmd.RunE(cmd, args)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected cmd error: %v", err)
|
||||
}
|
||||
content, err := fakeFS.ReadFile(constants.KustomizationFileName)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected read error: %v", err)
|
||||
}
|
||||
expected := []byte("namespace: newnamespace")
|
||||
if !strings.Contains(string(content), string(expected)) {
|
||||
t.Errorf("expected namespace in kustomization file %s", string(content))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetNamespaceNoArgs(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
|
||||
cmd := newCmdSetNamespace(fakeFS)
|
||||
err := cmd.Execute()
|
||||
if err == nil {
|
||||
t.Errorf("expected error: %v", err)
|
||||
}
|
||||
if err.Error() != "must specify exactly one namespace value" {
|
||||
t.Errorf("incorrect error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetNamespaceInvalid(t *testing.T) {
|
||||
fakeFS := fs.MakeFakeFS()
|
||||
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
|
||||
|
||||
cmd := newCmdSetNamespace(fakeFS)
|
||||
args := []string{"/badnamespace/"}
|
||||
err := cmd.RunE(cmd, args)
|
||||
if err == nil {
|
||||
t.Errorf("expected error: %v", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "is not a valid namespace name") {
|
||||
t.Errorf("unexpected error: %v", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -212,6 +212,5 @@ func parseLiteralSource(source string) (keyName, value string, err error) {
|
||||
if len(items) != 2 {
|
||||
return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
|
||||
}
|
||||
|
||||
return items[0], items[1], nil
|
||||
return items[0], strings.Trim(items[1], "\"'"), nil
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ func makeLiteralConfigMap(name string) *corev1.ConfigMap {
|
||||
Data: map[string]string{
|
||||
"a": "x",
|
||||
"b": "y",
|
||||
"c": "Hello World",
|
||||
"d": "true",
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -127,7 +129,7 @@ func TestConstructConfigMap(t *testing.T) {
|
||||
input: types.ConfigMapArgs{
|
||||
Name: "literalConfigMap",
|
||||
DataSources: types.DataSources{
|
||||
LiteralSources: []string{"a=x", "b=y"},
|
||||
LiteralSources: []string{"a=x", "b=y", "c=\"Hello World\"", "d='true'"},
|
||||
},
|
||||
},
|
||||
expected: makeLiteralConfigMap("literalConfigMap"),
|
||||
|
||||
@@ -31,6 +31,10 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultCommandTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
// SecretFactory makes Secrets.
|
||||
type SecretFactory struct {
|
||||
fSys fs.FileSystem
|
||||
@@ -61,7 +65,12 @@ func (f *SecretFactory) MakeSecret(args *types.SecretArgs) (*corev1.Secret, erro
|
||||
var err error
|
||||
s := f.makeFreshSecret(args)
|
||||
|
||||
pairs, err := f.keyValuesFromEnvFileCommand(args.EnvCommand)
|
||||
timeout := defaultCommandTimeout
|
||||
if args.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*args.TimeoutSeconds) * time.Second
|
||||
}
|
||||
|
||||
pairs, err := f.keyValuesFromEnvFileCommand(args.EnvCommand, timeout)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf(
|
||||
"env source file: %s",
|
||||
@@ -69,7 +78,7 @@ func (f *SecretFactory) MakeSecret(args *types.SecretArgs) (*corev1.Secret, erro
|
||||
}
|
||||
all = append(all, pairs...)
|
||||
|
||||
pairs, err = f.keyValuesFromCommands(args.Commands)
|
||||
pairs, err = f.keyValuesFromCommands(args.Commands, timeout)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf(
|
||||
"commands %v", args.Commands))
|
||||
@@ -98,18 +107,18 @@ func addKvToSecret(secret *corev1.Secret, keyName, data string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *SecretFactory) keyValuesFromEnvFileCommand(cmd string) ([]kvPair, error) {
|
||||
content, err := f.createSecretKey(cmd)
|
||||
func (f *SecretFactory) keyValuesFromEnvFileCommand(cmd string, timeout time.Duration) ([]kvPair, error) {
|
||||
content, err := f.createSecretKey(cmd, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return keyValuesFromLines(content)
|
||||
}
|
||||
|
||||
func (f *SecretFactory) keyValuesFromCommands(sources map[string]string) ([]kvPair, error) {
|
||||
func (f *SecretFactory) keyValuesFromCommands(sources map[string]string, timeout time.Duration) ([]kvPair, error) {
|
||||
var kvs []kvPair
|
||||
for k, cmd := range sources {
|
||||
content, err := f.createSecretKey(cmd)
|
||||
content, err := f.createSecretKey(cmd, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -119,14 +128,14 @@ func (f *SecretFactory) keyValuesFromCommands(sources map[string]string) ([]kvPa
|
||||
}
|
||||
|
||||
// Run a command, return its output as the secret.
|
||||
func (f *SecretFactory) createSecretKey(command string) ([]byte, error) {
|
||||
func (f *SecretFactory) createSecretKey(command string, timeout time.Duration) ([]byte, error) {
|
||||
if !f.fSys.IsDir(f.wd) {
|
||||
f.wd = filepath.Dir(f.wd)
|
||||
if !f.fSys.IsDir(f.wd) {
|
||||
return nil, errors.New("not a directory: " + f.wd)
|
||||
}
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, "sh", "-c", command)
|
||||
cmd.Dir = f.wd
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package diff
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// directory represents a new temp directory and lets one create files in it.
|
||||
type directory struct {
|
||||
n string
|
||||
}
|
||||
|
||||
// newDirectory makes a directory instance holding a new temp directory on disk.
|
||||
// The directory name is the given prefix following by a random string.
|
||||
func newDirectory(prefix string) (*directory, error) {
|
||||
name, err := ioutil.TempDir("", prefix+"-")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &directory{n: name}, nil
|
||||
}
|
||||
|
||||
// newFile creates a new file in the directory.
|
||||
func (d *directory) newFile(name string) (*os.File, error) {
|
||||
return os.OpenFile(filepath.Join(d.n, name), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0700)
|
||||
}
|
||||
|
||||
// delete removes the directory recursively.
|
||||
func (d *directory) delete() error {
|
||||
return os.RemoveAll(d.n)
|
||||
}
|
||||
|
||||
// name is the name of the directory.
|
||||
func (d *directory) name() string {
|
||||
return d.n
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package diff
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/exec"
|
||||
)
|
||||
|
||||
// program wraps the system diff program.
|
||||
// If specified, the value of KUBERNETES_EXTERNAL_DIFF environment variable
|
||||
// will be used instead of simply `diff(1)`.
|
||||
type program struct {
|
||||
stdout io.Writer
|
||||
stderr io.Writer
|
||||
}
|
||||
|
||||
func newProgram(out, errOut io.Writer) *program {
|
||||
return &program{
|
||||
stdout: out,
|
||||
stderr: errOut,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *program) makeCommand(args ...string) exec.Cmd {
|
||||
diff := "diff"
|
||||
if envDiff := os.Getenv("KUBERNETES_EXTERNAL_DIFF"); envDiff != "" {
|
||||
diff = envDiff
|
||||
} else {
|
||||
args = append([]string{"-u", "-N"}, args...)
|
||||
}
|
||||
cmd := exec.New().Command(diff, args...)
|
||||
cmd.SetStdout(d.stdout)
|
||||
cmd.SetStderr(d.stderr)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// run runs the detected diff program. `from` and `to` are the directory to diff.
|
||||
func (d *program) run(from, to string) error {
|
||||
d.makeCommand(from, to).Run() // Ignore diff return code
|
||||
return nil
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package diff runs system `diff` to compare resource collections.
|
||||
package diff
|
||||
|
||||
import (
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"io"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/resmap"
|
||||
)
|
||||
|
||||
// RunDiff runs system diff program to compare two Maps.
|
||||
func RunDiff(raw, transformed resmap.ResMap, out, errOut io.Writer) (err error) {
|
||||
transformedDir, err := writeYamlToNewDir(transformed, "transformed")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
err = transformedDir.delete()
|
||||
}()
|
||||
|
||||
noopDir, err := writeYamlToNewDir(raw, "noop")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
err = noopDir.delete()
|
||||
}()
|
||||
|
||||
return newProgram(out, errOut).run(noopDir.name(), transformedDir.name())
|
||||
}
|
||||
|
||||
// writeYamlToNewDir writes each obj in ResMap to a file in a new directory.
|
||||
// The directory's name will begin with the given prefix.
|
||||
// Each file is named with GroupVersionKindName.
|
||||
func writeYamlToNewDir(in resmap.ResMap, prefix string) (*directory, error) {
|
||||
dir, err := newDirectory(prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for id, obj := range in {
|
||||
f, err := dir.newFile(id.GvknString())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = write(obj, f)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
// Write the object as YAML.
|
||||
func write(obj interface{}, w io.Writer) error {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
data, err := yaml.Marshal(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
@@ -22,6 +22,9 @@ import (
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
||||
)
|
||||
|
||||
// CleanupCalled indicates if Cleanup is called.
|
||||
var CleanupCalled = false
|
||||
|
||||
// FakeLoader encapsulates the delegate Loader and the fake file system.
|
||||
type FakeLoader struct {
|
||||
fs fs.FileSystem
|
||||
@@ -56,10 +59,20 @@ func (f FakeLoader) Root() string {
|
||||
|
||||
// New creates a new loader from a new root.
|
||||
func (f FakeLoader) New(newRoot string) (loader.Loader, error) {
|
||||
return f.delegate.New(newRoot)
|
||||
l, err := f.delegate.New(newRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return FakeLoader{fs: f.fs, delegate: l}, nil
|
||||
}
|
||||
|
||||
// Load performs load from a given location.
|
||||
func (f FakeLoader) Load(location string) ([]byte, error) {
|
||||
return f.delegate.Load(location)
|
||||
}
|
||||
|
||||
// Cleanup does nothing
|
||||
func (f FakeLoader) Cleanup() error {
|
||||
CleanupCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -53,14 +53,7 @@ func (l *fileLoader) Root() string {
|
||||
// Example: "/home/seans/project" or "/home/seans/project/"
|
||||
// NOT "/home/seans/project/file.yaml".
|
||||
func (l *fileLoader) New(newRoot string) (Loader, error) {
|
||||
if !l.IsAbsPath(l.root, newRoot) {
|
||||
return nil, fmt.Errorf("Not abs path: l.root='%s', loc='%s'\n", l.root, newRoot)
|
||||
}
|
||||
root, err := l.fullLocation(l.root, newRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newFileLoaderAtRoot(root, l.fSys), nil
|
||||
return NewLoader(newRoot, l.root, l.fSys)
|
||||
}
|
||||
|
||||
// IsAbsPath return true if the location calculated with the root
|
||||
@@ -109,3 +102,8 @@ func (l *fileLoader) Load(location string) ([]byte, error) {
|
||||
}
|
||||
return l.fSys.ReadFile(fullLocation)
|
||||
}
|
||||
|
||||
// Cleanup does nothing
|
||||
func (l *fileLoader) Cleanup() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestLoader_Root(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected in New(): %v\n", err)
|
||||
}
|
||||
if "/home/seans/project/" != loader.Root() {
|
||||
if "/home/seans/project" != loader.Root() {
|
||||
t.Fatalf("Incorrect Loader Root: %s\n", loader.Root())
|
||||
}
|
||||
|
||||
|
||||
98
pkg/loader/githubloader.go
Normal file
98
pkg/loader/githubloader.go
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package loader
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-getter"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
// githubLoader loads files from a checkout github repo
|
||||
type githubLoader struct {
|
||||
repo string
|
||||
checkoutDir string
|
||||
loader *fileLoader
|
||||
}
|
||||
|
||||
// Root returns the root location for this Loader.
|
||||
func (l *githubLoader) Root() string {
|
||||
return l.checkoutDir
|
||||
}
|
||||
|
||||
// New delegates to fileLoader.New
|
||||
func (l *githubLoader) New(newRoot string) (Loader, error) {
|
||||
return l.loader.New(newRoot)
|
||||
}
|
||||
|
||||
// Load delegates to fileLoader.Load
|
||||
func (l *githubLoader) Load(location string) ([]byte, error) {
|
||||
return l.loader.Load(location)
|
||||
}
|
||||
|
||||
// Cleanup removes the checked out repo
|
||||
func (l *githubLoader) Cleanup() error {
|
||||
return os.RemoveAll(l.checkoutDir)
|
||||
}
|
||||
|
||||
// newGithubLoader returns a new fileLoader with given github Url.
|
||||
func newGithubLoader(repoUrl string, fs fs.FileSystem) (*githubLoader, error) {
|
||||
dir, err := ioutil.TempDir("", "kustomize-")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
target := filepath.Join(dir, "repo")
|
||||
err = checkout(repoUrl, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := newFileLoaderAtRoot(target, fs)
|
||||
return &githubLoader{
|
||||
repo: repoUrl,
|
||||
checkoutDir: dir,
|
||||
loader: l,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// isRepoUrl checks if a string is a repo Url
|
||||
func isRepoUrl(s string) bool {
|
||||
if strings.HasPrefix(s, "https://") {
|
||||
return true
|
||||
}
|
||||
host := strings.SplitN(s, "/", 2)[0]
|
||||
return strings.Contains(host, ".com") || strings.Contains(host, ".org")
|
||||
}
|
||||
|
||||
// Checkout clones a github repo with specified commit/tag/branch
|
||||
func checkout(url, dir string) error {
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := &getter.Client{
|
||||
Src: url,
|
||||
Dst: dir,
|
||||
Pwd: pwd,
|
||||
Mode: getter.ClientModeDir,
|
||||
}
|
||||
return client.Get()
|
||||
}
|
||||
56
pkg/loader/githubloader_test.go
Normal file
56
pkg/loader/githubloader_test.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package loader
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsRepoURL(t *testing.T) {
|
||||
|
||||
testcases := []struct {
|
||||
input string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
input: "https://github.com/org/repo",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "github.com/org/repo",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "/github.com/org/repo",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "/abs/path/to/file",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "../relative",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
actual := isRepoUrl(tc.input)
|
||||
if actual != tc.expected {
|
||||
t.Errorf("unexpected error: unexpected result %t for input %s", actual, tc.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,13 @@ limitations under the License.
|
||||
// Package loader has a data loading interface and various implementations.
|
||||
package loader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
||||
)
|
||||
|
||||
// Loader interface exposes methods to read bytes.
|
||||
type Loader interface {
|
||||
// Root returns the root location for this Loader.
|
||||
@@ -25,4 +32,49 @@ type Loader interface {
|
||||
New(newRoot string) (Loader, error)
|
||||
// Load returns the bytes read from the location or an error.
|
||||
Load(location string) ([]byte, error)
|
||||
// Cleanup cleans the loader
|
||||
Cleanup() error
|
||||
}
|
||||
|
||||
// NewLoader returns a Loader given a target
|
||||
// The target can be a local disk directory or a github Url
|
||||
func NewLoader(target, r string, fSys fs.FileSystem) (Loader, error) {
|
||||
if !isValidLoaderPath(target, r) {
|
||||
return nil, fmt.Errorf("Not valid path: root='%s', loc='%s'\n", r, target)
|
||||
}
|
||||
|
||||
if !isLocalTarget(target, fSys) && isRepoUrl(target) {
|
||||
return newGithubLoader(target, fSys)
|
||||
}
|
||||
|
||||
l := newFileLoaderAtRoot(r, fSys)
|
||||
if isRootLoaderPath(r) {
|
||||
absPath, err := filepath.Abs(target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
target = absPath
|
||||
}
|
||||
|
||||
if !l.IsAbsPath(l.root, target) {
|
||||
return nil, fmt.Errorf("Not abs path: l.root='%s', loc='%s'\n", l.root, target)
|
||||
}
|
||||
root, err := l.fullLocation(l.root, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newFileLoaderAtRoot(root, l.fSys), nil
|
||||
}
|
||||
|
||||
func isValidLoaderPath(target, root string) bool {
|
||||
return target != "" || root != ""
|
||||
}
|
||||
|
||||
func isRootLoaderPath(root string) bool {
|
||||
return root == ""
|
||||
}
|
||||
|
||||
// isLocalTarget checks if a file exists in the filesystem
|
||||
func isLocalTarget(s string, fs fs.FileSystem) bool {
|
||||
return fs.Exists(s)
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ BAR=baz
|
||||
{
|
||||
Name: "literalConfigMap",
|
||||
DataSources: types.DataSources{
|
||||
LiteralSources: []string{"a=x", "b=y"},
|
||||
LiteralSources: []string{"a=x", "b=y", "c=\"Good Morning\"", "d=\"false\""},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -120,6 +120,8 @@ BAR=baz
|
||||
"data": map[string]interface{}{
|
||||
"a": "x",
|
||||
"b": "y",
|
||||
"c": "Good Morning",
|
||||
"d": "false",
|
||||
},
|
||||
}).SetBehavior(resource.BehaviorCreate),
|
||||
},
|
||||
|
||||
@@ -211,10 +211,14 @@ func newResourceSliceFromBytes(in []byte) ([]*resource.Resource, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MergeWithoutOverride combines multiple ResMap instances, failing on key collision.
|
||||
// MergeWithoutOverride combines multiple ResMap instances, failing on key collision
|
||||
// and skipping nil maps. In case if all of the maps are nil, an empty ResMap is returned.
|
||||
func MergeWithoutOverride(maps ...ResMap) (ResMap, error) {
|
||||
result := ResMap{}
|
||||
for _, m := range maps {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
for id, res := range m {
|
||||
if _, found := result[id]; found {
|
||||
return nil, fmt.Errorf("id '%q' already used", id)
|
||||
@@ -226,14 +230,21 @@ func MergeWithoutOverride(maps ...ResMap) (ResMap, error) {
|
||||
}
|
||||
|
||||
// MergeWithOverride combines multiple ResMap instances, allowing and sometimes
|
||||
// demanding certain collisions.
|
||||
// demanding certain collisions and skipping nil maps.
|
||||
// In case if all of the maps are nil, an empty ResMap is returned.
|
||||
// When looping over the instances to combine them, if a resource id for resource X
|
||||
// is found to be already in the combined map, then the behavior field for X
|
||||
// must be BehaviorMerge or BehaviorReplace. If X is not in the map, then it's
|
||||
// behavior cannot be merge or replace.
|
||||
func MergeWithOverride(maps ...ResMap) (ResMap, error) {
|
||||
result := maps[0]
|
||||
if result == nil {
|
||||
result = ResMap{}
|
||||
}
|
||||
for _, m := range maps[1:] {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
for id, r := range m {
|
||||
matchedId := result.FindByGVKN(id)
|
||||
if len(matchedId) == 1 {
|
||||
@@ -261,7 +272,7 @@ func MergeWithOverride(maps ...ResMap) (ResMap, error) {
|
||||
result[id] = r
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("Merge conflict, found multiple objects %v the Resmap %v can merge into", matchedId, id)
|
||||
return nil, fmt.Errorf("merge conflict, found multiple objects %v the Resmap %v can merge into", matchedId, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +202,22 @@ func TestMergeWithoutOverride(t *testing.T) {
|
||||
if !reflect.DeepEqual(merged, expected) {
|
||||
t.Fatalf("%#v doesn't equal expected %#v", merged, expected)
|
||||
}
|
||||
input3 := []ResMap{merged, nil}
|
||||
merged1, err := MergeWithoutOverride(input3...)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(merged1, expected) {
|
||||
t.Fatalf("%#v doesn't equal expected %#v", merged1, expected)
|
||||
}
|
||||
input4 := []ResMap{nil, merged}
|
||||
merged2, err := MergeWithoutOverride(input4...)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(merged2, expected) {
|
||||
t.Fatalf("%#v doesn't equal expected %#v", merged2, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeWithOverride(t *testing.T) {
|
||||
@@ -262,4 +278,20 @@ func TestMergeWithOverride(t *testing.T) {
|
||||
if !reflect.DeepEqual(merged, expected) {
|
||||
t.Fatalf("%#v doesn't equal expected %#v", merged, expected)
|
||||
}
|
||||
input3 := []ResMap{merged, nil}
|
||||
merged1, err := MergeWithOverride(input3...)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(merged1, expected) {
|
||||
t.Fatalf("%#v doesn't equal expected %#v", merged1, expected)
|
||||
}
|
||||
input4 := []ResMap{nil, merged}
|
||||
merged2, err := MergeWithOverride(input4...)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(merged2, expected) {
|
||||
t.Fatalf("%#v doesn't equal expected %#v", merged2, expected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,3 +94,27 @@ func TestNewResMapFromSecretArgs(t *testing.T) {
|
||||
t.Fatalf("%#v\ndoesn't match expected:\n%#v", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecretTimeout(t *testing.T) {
|
||||
timeout := int64(1)
|
||||
secrets := []types.SecretArgs{
|
||||
{
|
||||
Name: "slow",
|
||||
TimeoutSeconds: &timeout,
|
||||
CommandSources: types.CommandSources{
|
||||
Commands: map[string]string{
|
||||
"USER": "sleep 2",
|
||||
},
|
||||
},
|
||||
Type: "Opaque",
|
||||
},
|
||||
}
|
||||
fakeFs := fs.MakeFakeFS()
|
||||
fakeFs.Mkdir(".")
|
||||
_, err := NewResMapFromSecretArgs(
|
||||
configmapandsecret.NewSecretFactory(fakeFs, "."), secrets)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("didn't get the expected timeout error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ var defaultLabelsPathConfigs = []PathConfig{
|
||||
{
|
||||
GroupVersionKind: &schema.GroupVersionKind{Group: "policy", Kind: "PodDisruptionBudget"},
|
||||
Path: []string{"spec", "selector", "matchLabels"},
|
||||
CreateIfNotPresent: true,
|
||||
CreateIfNotPresent: false,
|
||||
},
|
||||
{
|
||||
GroupVersionKind: &schema.GroupVersionKind{Group: "networking.k8s.io", Kind: "NetworkPolicy"},
|
||||
|
||||
@@ -874,6 +874,21 @@ var defaultNameReferencePathConfigs = []ReferencePathConfig{
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referencedGVK: schema.GroupVersionKind{
|
||||
Version: "v1",
|
||||
Kind: "PersistentVolume",
|
||||
},
|
||||
pathConfigs: []PathConfig{
|
||||
{
|
||||
GroupVersionKind: &schema.GroupVersionKind{
|
||||
Kind: "PersistentVolumeClaim",
|
||||
},
|
||||
Path: []string{"spec", "volumeName"},
|
||||
CreateIfNotPresent: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// AddNameReferencePathConfigs adds extra reference path configs to the default one
|
||||
|
||||
@@ -60,7 +60,7 @@ func (pt *patchTransformer) Transform(baseResourceMap resmap.ResMap) error {
|
||||
return fmt.Errorf("failed to find an object with %#v to apply the patch", id.Gvk())
|
||||
}
|
||||
if len(matchedIds) > 1 {
|
||||
return fmt.Errorf("Found multiple objects %#v that the patch %#v can apply", matchedIds, id)
|
||||
return fmt.Errorf("found multiple objects %#v targeted by patch %#v (ambiguous)", matchedIds, id)
|
||||
}
|
||||
id = matchedIds[0]
|
||||
base := baseResourceMap[id]
|
||||
|
||||
@@ -17,8 +17,14 @@ limitations under the License.
|
||||
// Package types holds struct definitions that should find a better home.
|
||||
package types
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// Kustomization holds the information needed to generate customized k8s api resources.
|
||||
type Kustomization struct {
|
||||
metav1.TypeMeta `json:",inline" yaml:",inline"`
|
||||
|
||||
// NamePrefix will prefix the names of all resources mentioned in the kustomization
|
||||
// file including generated configmaps and secrets.
|
||||
NamePrefix string `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"`
|
||||
@@ -35,23 +41,22 @@ type Kustomization struct {
|
||||
// Annotations to add to all objects.
|
||||
CommonAnnotations map[string]string `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
|
||||
|
||||
// Each entry should be either a path to a file with a name matching the value of
|
||||
// constants.KustomizationFileName, or a path to a directory containing a file with that name.
|
||||
// Each entry should be either a path to a directory containing kustomization.yaml
|
||||
// Or a repo URL pointing to a remote directory containing kustomization.yaml
|
||||
// The repo URL should follow hashicorp/go-getter URL format
|
||||
// https://github.com/hashicorp/go-getter#url-format
|
||||
Bases []string `json:"bases,omitempty" yaml:"bases,omitempty"`
|
||||
|
||||
// Resources specifies the relative paths within the package.
|
||||
// It could be any format that kubectl -f allows, i.e. files, directories,
|
||||
// URLs and globs.
|
||||
// Resources specifies the relative paths for resource files within the package.
|
||||
// URLs and globs are not supported
|
||||
Resources []string `json:"resources,omitempty" yaml:"resources,omitempty"`
|
||||
|
||||
// Crds specifies relative paths to custom resource definition files.
|
||||
Crds []string `json:"crds,omitempty" yaml:"crds,omitempty"`
|
||||
|
||||
// An Patch entry is very similar to an Resource entry.
|
||||
// It specifies the relative paths within the package, and could be any
|
||||
// format that kubectl -f allows.
|
||||
// It should be able to be merged by Strategic Merge Patch on top of its
|
||||
// corresponding base resource.
|
||||
// It specifies the relative paths for patch files within the package.
|
||||
// URLs and globs are not supported
|
||||
Patches []string `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||
|
||||
// List of configmaps to generate from configuration sources.
|
||||
@@ -117,6 +122,9 @@ type SecretArgs struct {
|
||||
|
||||
// CommandSources for secret.
|
||||
CommandSources `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||
|
||||
// TimeoutSeconds specifies the timeout for commands.
|
||||
TimeoutSeconds *int64 `json:"timeoutSeconds,omitempty" yaml:"timeoutSeconds,omitempty"`
|
||||
}
|
||||
|
||||
// CommandSources contains some generic sources for secrets.
|
||||
|
||||
35
pkg/validate/validate.go
Normal file
35
pkg/validate/validate.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package validate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// TODO: these are rudimentary placeholder validation functions and need
|
||||
// additional work to truly match expected syntax rules.
|
||||
|
||||
// IsValidLabel checks whether a label key/value pair has correct syntax and
|
||||
// character set
|
||||
func IsValidLabel(keyval string) (bool, error) {
|
||||
ok, err := regexp.MatchString(`\A([a-zA-Z0-9_.-]+):([a-zA-Z0-9_.-]+)\z`, keyval)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid label format: %s", keyval)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// IsValidAnnotation checks whether an annotation key/value pair has correct
|
||||
// syntax and character set
|
||||
func IsValidAnnotation(keyval string) (bool, error) {
|
||||
ok, err := regexp.MatchString(`\A([a-zA-Z0-9_.-]+):([a-zA-Z0-9_.-]+)\z`, keyval)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !ok {
|
||||
return false, fmt.Errorf("invalid annotation format: %s", keyval)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
103
pkg/validate/validate_test.go
Normal file
103
pkg/validate/validate_test.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package validate
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestIsValidLabel(t *testing.T) {
|
||||
testcases := []struct {
|
||||
input, name string
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
input: "otters:cute",
|
||||
valid: true,
|
||||
name: "Valid input format",
|
||||
},
|
||||
{
|
||||
input: "dogs,cats",
|
||||
valid: false,
|
||||
name: "Does not contain colon",
|
||||
},
|
||||
{
|
||||
input: ":noKey",
|
||||
valid: false,
|
||||
name: "Missing key",
|
||||
},
|
||||
{
|
||||
input: "noValue:",
|
||||
valid: false,
|
||||
name: "Missing value",
|
||||
},
|
||||
{
|
||||
input: "exclamation!:point",
|
||||
valid: false,
|
||||
name: "Non-alphanumeric input",
|
||||
},
|
||||
{
|
||||
input: "123:45",
|
||||
valid: true,
|
||||
name: "Numeric input is allowed",
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
ok, err := IsValidLabel(tc.input)
|
||||
if tc.valid && err != nil {
|
||||
t.Errorf("unexpected error: for test case %s, expected no error but got: %s", tc.name, err.Error())
|
||||
}
|
||||
if ok && !tc.valid {
|
||||
t.Errorf("for test case %s, expected invalid label format error", tc.name)
|
||||
}
|
||||
if !ok && tc.valid {
|
||||
t.Errorf("unexpected error: for test case %s, expected test to pass", tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValidAnnotation(t *testing.T) {
|
||||
testcases := []struct {
|
||||
input, name string
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
input: "owls:adorable",
|
||||
valid: true,
|
||||
name: "Valid input format",
|
||||
},
|
||||
{
|
||||
input: "cake,cookies",
|
||||
valid: false,
|
||||
name: "Does not contain colon",
|
||||
},
|
||||
{
|
||||
input: ":noKey",
|
||||
valid: false,
|
||||
name: "Missing key",
|
||||
},
|
||||
{
|
||||
input: "noValue:",
|
||||
valid: false,
|
||||
name: "Missing value",
|
||||
},
|
||||
{
|
||||
input: "exclamation!:point",
|
||||
valid: false,
|
||||
name: "Input has a bang!",
|
||||
},
|
||||
{
|
||||
input: "987:65",
|
||||
valid: true,
|
||||
name: "Numeric input is valid",
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
ok, err := IsValidAnnotation(tc.input)
|
||||
if tc.valid && err != nil {
|
||||
t.Errorf("unexpected error: for test case %s, expected no error but got: %s", tc.name, err.Error())
|
||||
}
|
||||
if ok && !tc.valid {
|
||||
t.Errorf("for test case %s, expected invalid annotation format error", tc.name)
|
||||
}
|
||||
if !ok && tc.valid {
|
||||
t.Errorf("unexpected error: for test case %s, expected test to pass", tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
14
vendor/github.com/aws/aws-sdk-go/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
14
vendor/github.com/aws/aws-sdk-go/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal 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 an runnable example, please include it.
|
||||
|
||||
3
vendor/github.com/aws/aws-sdk-go/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
3
vendor/github.com/aws/aws-sdk-go/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal 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.
|
||||
11
vendor/github.com/aws/aws-sdk-go/.gitignore
generated
vendored
Normal file
11
vendor/github.com/aws/aws-sdk-go/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
dist
|
||||
/doc
|
||||
/doc-staging
|
||||
.yardoc
|
||||
Gemfile.lock
|
||||
awstesting/integration/smoke/**/importmarker__.go
|
||||
awstesting/integration/smoke/_test/
|
||||
/vendor/bin/
|
||||
/vendor/pkg/
|
||||
/vendor/src/
|
||||
/private/model/cli/gen-api/gen-api
|
||||
14
vendor/github.com/aws/aws-sdk-go/.godoc_config
generated
vendored
Normal file
14
vendor/github.com/aws/aws-sdk-go/.godoc_config
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"PkgHandler": {
|
||||
"Pattern": "/sdk-for-go/api/",
|
||||
"StripPrefix": "/sdk-for-go/api",
|
||||
"Include": ["/src/github.com/aws/aws-sdk-go/aws", "/src/github.com/aws/aws-sdk-go/service"],
|
||||
"Exclude": ["/src/cmd", "/src/github.com/aws/aws-sdk-go/awstesting", "/src/github.com/aws/aws-sdk-go/awsmigrate", "/src/github.com/aws/aws-sdk-go/private"],
|
||||
"IgnoredSuffixes": ["iface"]
|
||||
},
|
||||
"Github": {
|
||||
"Tag": "master",
|
||||
"Repo": "/aws/aws-sdk-go",
|
||||
"UseGithub": true
|
||||
}
|
||||
}
|
||||
48
vendor/github.com/aws/aws-sdk-go/.travis.yml
generated
vendored
Normal file
48
vendor/github.com/aws/aws-sdk-go/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
language: go
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
- go: 1.6.x
|
||||
os: linux
|
||||
include:
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.5.x
|
||||
# Use Go 1.5's vendoring experiment for 1.5 tests.
|
||||
env: GO15VENDOREXPERIMENT=1
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.6.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.7.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.8.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.9.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.10.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: tip
|
||||
- os: osx
|
||||
go: 1.7.x
|
||||
- os: osx
|
||||
go: 1.8.x
|
||||
- os: osx
|
||||
go: 1.9.x
|
||||
- os: osx
|
||||
go: 1.10.x
|
||||
- os: osx
|
||||
go: tip
|
||||
|
||||
script:
|
||||
- make ci-test
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
3993
vendor/github.com/aws/aws-sdk-go/CHANGELOG.md
generated
vendored
Normal file
3993
vendor/github.com/aws/aws-sdk-go/CHANGELOG.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md
generated
vendored
Normal file
5
vendor/github.com/aws/aws-sdk-go/CHANGELOG_PENDING.md
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
### SDK Features
|
||||
|
||||
### SDK Enhancements
|
||||
|
||||
### SDK Bugs
|
||||
4
vendor/github.com/aws/aws-sdk-go/CODE_OF_CONDUCT.md
generated
vendored
Normal file
4
vendor/github.com/aws/aws-sdk-go/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
## Code of Conduct
|
||||
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||
127
vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md
generated
vendored
Normal file
127
vendor/github.com/aws/aws-sdk-go/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
Contributing to the AWS SDK for Go
|
||||
|
||||
We work hard to provide a high-quality and useful SDK, and we greatly value
|
||||
feedback and contributions from our community. Whether it's a bug report,
|
||||
new feature, correction, or additional documentation, we welcome your issues
|
||||
and pull requests. Please read through this document before submitting any
|
||||
issues or pull requests to ensure we have all the necessary information to
|
||||
effectively respond to your bug report or contribution.
|
||||
|
||||
|
||||
## Filing Bug Reports
|
||||
|
||||
You can file bug reports against the SDK on the [GitHub issues][issues] page.
|
||||
|
||||
If you are filing a report for a bug or regression in the SDK, it's extremely
|
||||
helpful to provide as much information as possible when opening the original
|
||||
issue. This helps us reproduce and investigate the possible bug without having
|
||||
to wait for this extra information to be provided. Please read the following
|
||||
guidelines prior to filing a bug report.
|
||||
|
||||
1. Search through existing [issues][] to ensure that your specific issue has
|
||||
not yet been reported. If it is a common issue, it is likely there is
|
||||
already a bug report for your problem.
|
||||
|
||||
2. Ensure that you have tested the latest version of the SDK. Although you
|
||||
may have an issue against an older version of the SDK, we cannot provide
|
||||
bug fixes for old versions. It's also possible that the bug may have been
|
||||
fixed in the latest release.
|
||||
|
||||
3. Provide as much information about your environment, SDK version, and
|
||||
relevant dependencies as possible. For example, let us know what version
|
||||
of Go you are using, which and version of the operating system, and the
|
||||
the environment your code is running in. e.g Container.
|
||||
|
||||
4. Provide a minimal test case that reproduces your issue or any error
|
||||
information you related to your problem. We can provide feedback much
|
||||
more quickly if we know what operations you are calling in the SDK. If
|
||||
you cannot provide a full test case, provide as much code as you can
|
||||
to help us diagnose the problem. Any relevant information should be provided
|
||||
as well, like whether this is a persistent issue, or if it only occurs
|
||||
some of the time.
|
||||
|
||||
|
||||
## Submitting Pull Requests
|
||||
|
||||
We are always happy to receive code and documentation contributions to the SDK.
|
||||
Please be aware of the following notes prior to opening a pull request:
|
||||
|
||||
1. The SDK is released under the [Apache license][license]. Any code you submit
|
||||
will be released under that license. For substantial contributions, we may
|
||||
ask you to sign a [Contributor License Agreement (CLA)][cla].
|
||||
|
||||
2. If you would like to implement support for a significant feature that is not
|
||||
yet available in the SDK, please talk to us beforehand to avoid any
|
||||
duplication of effort.
|
||||
|
||||
3. Wherever possible, pull requests should contain tests as appropriate.
|
||||
Bugfixes should contain tests that exercise the corrected behavior (i.e., the
|
||||
test should fail without the bugfix and pass with it), and new features
|
||||
should be accompanied by tests exercising the feature.
|
||||
|
||||
4. Pull requests that contain failing tests will not be merged until the test
|
||||
failures are addressed. Pull requests that cause a significant drop in the
|
||||
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
|
||||
SDK's testing dependencies, and run vet, link and unit tests for the SDK.
|
||||
|
||||
```
|
||||
make unit
|
||||
```
|
||||
|
||||
Standard go testing functionality is supported as well. To test SDK code that
|
||||
is tagged with `codegen` you'll need to set the build tag in the go test
|
||||
command. The `make unit` command will do this automatically.
|
||||
|
||||
```
|
||||
go test -tags codegen ./private/...
|
||||
```
|
||||
|
||||
See the `Makefile` for additional testing tags that can be used in testing.
|
||||
|
||||
To test on multiple platform the SDK includes several DockerFiles under the
|
||||
`awstesting/sandbox` folder, and associated make recipes to execute
|
||||
unit testing within environments configured for specific Go versions.
|
||||
|
||||
```
|
||||
make sandbox-test-go18
|
||||
```
|
||||
|
||||
To run all sandbox environments use the following make recipe
|
||||
|
||||
```
|
||||
# Optionally update the Go tip that will be used during the batch testing
|
||||
make update-aws-golang-tip
|
||||
|
||||
# Run all SDK tests for supported Go versions in sandboxes
|
||||
make sandbox-test
|
||||
```
|
||||
|
||||
In addition the sandbox environment include make recipes for interactive modes
|
||||
so you can run command within the Docker container and context of the SDK.
|
||||
|
||||
```
|
||||
make sandbox-go18
|
||||
```
|
||||
|
||||
### Changelog
|
||||
|
||||
You can see all release changes in the `CHANGELOG.md` file at the root of the
|
||||
repository. The release notes added to this file will contain service client
|
||||
updates, and major SDK changes.
|
||||
|
||||
[issues]: https://github.com/aws/aws-sdk-go/issues
|
||||
[pr]: https://github.com/aws/aws-sdk-go/pulls
|
||||
[license]: http://aws.amazon.com/apache2.0/
|
||||
[cla]: http://en.wikipedia.org/wiki/Contributor_License_Agreement
|
||||
[releasenotes]: https://github.com/aws/aws-sdk-go/releases
|
||||
|
||||
20
vendor/github.com/aws/aws-sdk-go/Gopkg.lock
generated
vendored
Normal file
20
vendor/github.com/aws/aws-sdk-go/Gopkg.lock
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ini/ini"
|
||||
packages = ["."]
|
||||
revision = "300e940a926eb277d3901b20bdfcc54928ad3642"
|
||||
version = "v1.25.4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
packages = ["."]
|
||||
revision = "0b12d6b5"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "51a86a867df617990082dec6b868e4efe2fdb2ed0e02a3daa93cd30f962b5085"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
48
vendor/github.com/aws/aws-sdk-go/Gopkg.toml
generated
vendored
Normal file
48
vendor/github.com/aws/aws-sdk-go/Gopkg.toml
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
ignored = [
|
||||
# Testing/Example/Codegen dependencies
|
||||
"github.com/stretchr/testify",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/stretchr/testify/require",
|
||||
"github.com/go-sql-driver/mysql",
|
||||
"github.com/gucumber/gucumber",
|
||||
"github.com/pkg/errors",
|
||||
"golang.org/x/net",
|
||||
"golang.org/x/net/html",
|
||||
"golang.org/x/net/http2",
|
||||
"golang.org/x/text",
|
||||
"golang.org/x/text/html",
|
||||
"golang.org/x/tools",
|
||||
"golang.org/x/tools/go/loader",
|
||||
]
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-ini/ini"
|
||||
version = "1.25.4"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
revision = "0b12d6b5"
|
||||
#version = "0.2.2"
|
||||
202
vendor/github.com/aws/aws-sdk-go/LICENSE.txt
generated
vendored
Normal file
202
vendor/github.com/aws/aws-sdk-go/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
216
vendor/github.com/aws/aws-sdk-go/Makefile
generated
vendored
Normal file
216
vendor/github.com/aws/aws-sdk-go/Makefile
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
LINTIGNOREDOT='awstesting/integration.+should not use dot imports'
|
||||
LINTIGNOREDOC='service/[^/]+/(api|service|waiters)\.go:.+(comment on exported|should have comment or be unexported)'
|
||||
LINTIGNORECONST='service/[^/]+/(api|service|waiters)\.go:.+(type|struct field|const|func) ([^ ]+) should be ([^ ]+)'
|
||||
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 '
|
||||
LINTIGNOREENDPOINTS='aws/endpoints/defaults.go:.+(method|const) .+ should be '
|
||||
LINTIGNOREDEPS='vendor/.+\.go'
|
||||
LINTIGNOREPKGCOMMENT='service/[^/]+/doc_custom.go:.+package comment should be of the form'
|
||||
UNIT_TEST_TAGS="example codegen awsinclude"
|
||||
|
||||
SDK_WITH_VENDOR_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/src")
|
||||
SDK_ONLY_PKGS=$(shell go list ./... | grep -v "/vendor/")
|
||||
SDK_UNIT_TEST_ONLY_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/")
|
||||
SDK_GO_1_4=$(shell go version | grep "go1.4")
|
||||
SDK_GO_1_5=$(shell go version | grep "go1.5")
|
||||
SDK_GO_1_6=$(shell go version | grep "go1.6")
|
||||
SDK_GO_VERSION=$(shell go version | awk '''{print $$3}''' | tr -d '''\n''')
|
||||
|
||||
all: get-deps generate unit
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " api_info to print a list of services and versions"
|
||||
@echo " docs to build SDK documentation"
|
||||
@echo " build to go build the SDK"
|
||||
@echo " unit to run unit tests"
|
||||
@echo " integration to run integration tests"
|
||||
@echo " performance to run performance tests"
|
||||
@echo " verify to verify tests"
|
||||
@echo " lint to lint the SDK"
|
||||
@echo " vet to vet the SDK"
|
||||
@echo " generate to go generate and make services"
|
||||
@echo " gen-test to generate protocol tests"
|
||||
@echo " gen-services to generate services"
|
||||
@echo " get-deps to go get the SDK dependencies"
|
||||
@echo " get-deps-tests to get the SDK's test dependencies"
|
||||
@echo " get-deps-verify to get the SDK's verification dependencies"
|
||||
|
||||
generate: cleanup-models gen-test gen-endpoints gen-services
|
||||
|
||||
gen-test: gen-protocol-test gen-codegen-test
|
||||
|
||||
gen-codegen-test:
|
||||
go generate ./private/model/api/codegentest/service
|
||||
|
||||
gen-services:
|
||||
go generate ./service
|
||||
|
||||
gen-protocol-test:
|
||||
go generate ./private/protocol/...
|
||||
|
||||
gen-endpoints:
|
||||
go generate ./models/endpoints/
|
||||
|
||||
cleanup-models:
|
||||
@echo "Cleaning up stale model versions"
|
||||
@./cleanup_models.sh
|
||||
|
||||
build:
|
||||
@echo "go build SDK and vendor packages"
|
||||
@go build ${SDK_ONLY_PKGS}
|
||||
|
||||
unit: get-deps-tests build verify
|
||||
@echo "go test SDK and vendor packages"
|
||||
@go test -tags ${UNIT_TEST_TAGS} $(SDK_UNIT_TEST_ONLY_PKGS)
|
||||
|
||||
unit-with-race-cover: get-deps-tests build verify
|
||||
@echo "go test SDK and vendor packages"
|
||||
@go test -tags ${UNIT_TEST_TAGS} -race -cpu=1,2,4 $(SDK_UNIT_TEST_ONLY_PKGS)
|
||||
|
||||
ci-test: ci-test-generate unit-with-race-cover ci-test-generate-validate
|
||||
|
||||
ci-test-generate: get-deps
|
||||
@echo "CI test generated code"
|
||||
@if [ \( -z "${SDK_GO_1_6}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then make generate; else echo "skipping generate"; fi
|
||||
|
||||
ci-test-generate-validate:
|
||||
@echo "CI test validate no generated code changes"
|
||||
@git add . -A
|
||||
@gitstatus=`if [ \( -z "${SDK_GO_1_6}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then git diff --cached --ignore-space-change; else echo "skipping validation"; fi`; \
|
||||
echo "$$gitstatus"; \
|
||||
if [ "$$gitstatus" != "" ] && [ "$$gitstatus" != "skipping validation" ]; then echo "$$gitstatus"; exit 1; fi
|
||||
|
||||
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
|
||||
|
||||
performance: get-deps-tests
|
||||
AWS_TESTING_LOG_RESULTS=${log-detailed} AWS_TESTING_REGION=$(region) AWS_TESTING_DB_TABLE=$(table) gucumber -go-tags "integration" ./awstesting/performance
|
||||
|
||||
sandbox-tests: sandbox-test-go15 sandbox-test-go15-novendorexp sandbox-test-go16 sandbox-test-go17 sandbox-test-go18 sandbox-test-go19 sandbox-test-gotip
|
||||
|
||||
sandbox-build-go15:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5 -t "aws-sdk-go-1.5" .
|
||||
sandbox-go15: sandbox-build-go15
|
||||
docker run -i -t aws-sdk-go-1.5 bash
|
||||
sandbox-test-go15: sandbox-build-go15
|
||||
docker run -t aws-sdk-go-1.5
|
||||
|
||||
sandbox-build-go15-novendorexp:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5-novendorexp -t "aws-sdk-go-1.5-novendorexp" .
|
||||
sandbox-go15-novendorexp: sandbox-build-go15-novendorexp
|
||||
docker run -i -t aws-sdk-go-1.5-novendorexp bash
|
||||
sandbox-test-go15-novendorexp: sandbox-build-go15-novendorexp
|
||||
docker run -t aws-sdk-go-1.5-novendorexp
|
||||
|
||||
sandbox-build-go16:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.6 -t "aws-sdk-go-1.6" .
|
||||
sandbox-go16: sandbox-build-go16
|
||||
docker run -i -t aws-sdk-go-1.6 bash
|
||||
sandbox-test-go16: sandbox-build-go16
|
||||
docker run -t aws-sdk-go-1.6
|
||||
|
||||
sandbox-build-go17:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.7 -t "aws-sdk-go-1.7" .
|
||||
sandbox-go17: sandbox-build-go17
|
||||
docker run -i -t aws-sdk-go-1.7 bash
|
||||
sandbox-test-go17: sandbox-build-go17
|
||||
docker run -t aws-sdk-go-1.7
|
||||
|
||||
sandbox-build-go18:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.8" .
|
||||
sandbox-go18: sandbox-build-go18
|
||||
docker run -i -t aws-sdk-go-1.8 bash
|
||||
sandbox-test-go18: sandbox-build-go18
|
||||
docker run -t aws-sdk-go-1.8
|
||||
|
||||
sandbox-build-go19:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.9" .
|
||||
sandbox-go19: sandbox-build-go19
|
||||
docker run -i -t aws-sdk-go-1.9 bash
|
||||
sandbox-test-go19: sandbox-build-go19
|
||||
docker run -t aws-sdk-go-1.9
|
||||
|
||||
sandbox-build-go110:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.10" .
|
||||
sandbox-go110: sandbox-build-go110
|
||||
docker run -i -t aws-sdk-go-1.10 bash
|
||||
sandbox-test-go110: sandbox-build-go110
|
||||
docker run -t aws-sdk-go-1.10
|
||||
|
||||
sandbox-build-gotip:
|
||||
@echo "Run make update-aws-golang-tip, if this test fails because missing aws-golang:tip container"
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.gotip -t "aws-sdk-go-tip" .
|
||||
sandbox-gotip: sandbox-build-gotip
|
||||
docker run -i -t aws-sdk-go-tip bash
|
||||
sandbox-test-gotip: sandbox-build-gotip
|
||||
docker run -t aws-sdk-go-tip
|
||||
|
||||
update-aws-golang-tip:
|
||||
docker build --no-cache=true -f ./awstesting/sandbox/Dockerfile.golang-tip -t "aws-golang:tip" .
|
||||
|
||||
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} -e ${LINTIGNOREPKGCOMMENT} -e ${LINTIGNOREENDPOINTS}`; \
|
||||
echo "$$lint"; \
|
||||
if [ "$$lint" != "" ] && [ "$$lint" != "skipping golint" ]; then exit 1; fi
|
||||
|
||||
SDK_BASE_FOLDERS=$(shell ls -d */ | grep -v vendor | grep -v awsmigrate)
|
||||
ifneq (,$(findstring go1.4, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=echo skipping go vet, ${SDK_GO_VERSION}
|
||||
else ifneq (,$(findstring go1.6, ${SDK_GO_VERSION}))
|
||||
GO_VET_CMD=go tool vet --all -shadow -example=false
|
||||
else
|
||||
GO_VET_CMD=go tool vet --all -shadow
|
||||
endif
|
||||
|
||||
vet:
|
||||
${GO_VET_CMD} ${SDK_BASE_FOLDERS}
|
||||
|
||||
get-deps: get-deps-tests get-deps-verify
|
||||
@echo "go get SDK dependencies"
|
||||
@go get -v $(SDK_ONLY_PKGS)
|
||||
|
||||
get-deps-tests:
|
||||
@echo "go get SDK testing dependencies"
|
||||
go get github.com/gucumber/gucumber/cmd/gucumber
|
||||
go get github.com/stretchr/testify
|
||||
go get github.com/smartystreets/goconvey
|
||||
go get golang.org/x/net/html
|
||||
go get golang.org/x/net/http2
|
||||
|
||||
get-deps-verify:
|
||||
@echo "go get SDK verification utilities"
|
||||
@if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then go get github.com/golang/lint/golint; else echo "skipped getting golint"; fi
|
||||
|
||||
bench:
|
||||
@echo "go bench SDK packages"
|
||||
@go test -run NONE -bench . -benchmem -tags 'bench' $(SDK_ONLY_PKGS)
|
||||
|
||||
bench-protocol:
|
||||
@echo "go bench SDK protocol marshallers"
|
||||
@go test -run NONE -bench . -benchmem -tags 'bench' ./private/protocol/...
|
||||
|
||||
docs:
|
||||
@echo "generate SDK docs"
|
||||
@# This env variable, DOCS, is for internal use
|
||||
@if [ -z ${AWS_DOC_GEN_TOOL} ]; then\
|
||||
rm -rf doc && bundle install && bundle exec yard;\
|
||||
else\
|
||||
$(AWS_DOC_GEN_TOOL) `pwd`;\
|
||||
fi
|
||||
|
||||
api_info:
|
||||
@go run private/model/cli/api-info/api-info.go
|
||||
3
vendor/github.com/aws/aws-sdk-go/NOTICE.txt
generated
vendored
Normal file
3
vendor/github.com/aws/aws-sdk-go/NOTICE.txt
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
AWS SDK for Go
|
||||
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Copyright 2014-2015 Stripe, Inc.
|
||||
451
vendor/github.com/aws/aws-sdk-go/README.md
generated
vendored
Normal file
451
vendor/github.com/aws/aws-sdk-go/README.md
generated
vendored
Normal file
@@ -0,0 +1,451 @@
|
||||
[](http://docs.aws.amazon.com/sdk-for-go/api) [](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://travis-ci.org/aws/aws-sdk-go) [](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
|
||||
|
||||
# AWS SDK for Go
|
||||
|
||||
aws-sdk-go is the official AWS SDK for the Go programming language.
|
||||
|
||||
Checkout our [release notes](https://github.com/aws/aws-sdk-go/releases) for information about the latest bug fixes, updates, and features added to the SDK.
|
||||
|
||||
We [announced](https://aws.amazon.com/blogs/developer/aws-sdk-for-go-2-0-developer-preview/) the Developer Preview for the [v2 AWS SDK for Go](https://github.com/aws/aws-sdk-go-v2). The v2 SDK is available at https://github.com/aws/aws-sdk-go-v2, and `go get github.com/aws/aws-sdk-go-v2` via `go get`. Check out the v2 SDK's [changes and updates](https://github.com/aws/aws-sdk-go-v2/blob/master/CHANGELOG.md), and let us know what you think. We want your feedback.
|
||||
|
||||
## Installing
|
||||
|
||||
If you are using Go 1.5 with the `GO15VENDOREXPERIMENT=1` vendoring flag, or 1.6 and higher you can use the following command to retrieve the SDK. The SDK's non-testing dependencies will be included and are vendored in the `vendor` folder.
|
||||
|
||||
go get -u github.com/aws/aws-sdk-go
|
||||
|
||||
Otherwise if your Go environment does not have vendoring support enabled, or you do not want to include the vendored SDK's dependencies you can use the following command to retrieve the SDK and its non-testing dependencies using `go get`.
|
||||
|
||||
go get -u github.com/aws/aws-sdk-go/aws/...
|
||||
go get -u github.com/aws/aws-sdk-go/service/...
|
||||
|
||||
If you're looking to retrieve just the SDK without any dependencies use the following command.
|
||||
|
||||
go get -d github.com/aws/aws-sdk-go/
|
||||
|
||||
These two processes will still include the `vendor` folder and it should be deleted if its not going to be used by your environment.
|
||||
|
||||
rm -rf $GOPATH/src/github.com/aws/aws-sdk-go/vendor
|
||||
|
||||
## 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).
|
||||
* If you think you may have found a bug, please open an [issue](https://github.com/aws/aws-sdk-go/issues/new).
|
||||
|
||||
## 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 you’re 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.
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
[`Getting Started Guide`](https://aws.amazon.com/sdk-for-go/) - This document is a general introduction how to configure and make requests with the SDK. If this is your first time using the SDK, this documentation and the API documentation will help you get started. This document focuses on the syntax and behavior of the SDK. The [Service Developer Guide](https://aws.amazon.com/documentation/) will help you get started using specific AWS services.
|
||||
|
||||
[`SDK API Reference Documentation`](https://docs.aws.amazon.com/sdk-for-go/api/) - Use this document to look up all API operation input and output parameters for AWS services supported by the SDK. The API reference also includes documentation of the SDK, and examples how to using the SDK, service client API operations, and API operation require parameters.
|
||||
|
||||
[`Service Developer Guide`](https://aws.amazon.com/documentation/) - Use this documentation to learn how to interface with an AWS service. These are great guides both, if you're getting started with a service, or looking for more information on a service. You should not need this document for coding, though in some cases, services may supply helpful samples that you might want to look out for.
|
||||
|
||||
[`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.
|
||||
|
||||
## 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][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
|
||||
// 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][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]: https://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.Int64Value(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 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
|
||||
|
||||
This SDK is distributed under the
|
||||
[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0),
|
||||
see LICENSE.txt and NOTICE.txt for more information.
|
||||
86
vendor/github.com/aws/aws-sdk-go/aws/arn/arn.go
generated
vendored
Normal file
86
vendor/github.com/aws/aws-sdk-go/aws/arn/arn.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
// Package arn provides a parser for interacting with Amazon Resource Names.
|
||||
package arn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
arnDelimiter = ":"
|
||||
arnSections = 6
|
||||
arnPrefix = "arn:"
|
||||
|
||||
// zero-indexed
|
||||
sectionPartition = 1
|
||||
sectionService = 2
|
||||
sectionRegion = 3
|
||||
sectionAccountID = 4
|
||||
sectionResource = 5
|
||||
|
||||
// errors
|
||||
invalidPrefix = "arn: invalid prefix"
|
||||
invalidSections = "arn: not enough sections"
|
||||
)
|
||||
|
||||
// ARN captures the individual fields of an Amazon Resource Name.
|
||||
// See http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html for more information.
|
||||
type ARN struct {
|
||||
// The partition that the resource is in. For standard AWS regions, the partition is "aws". If you have resources in
|
||||
// other partitions, the partition is "aws-partitionname". For example, the partition for resources in the China
|
||||
// (Beijing) region is "aws-cn".
|
||||
Partition string
|
||||
|
||||
// The service namespace that identifies the AWS product (for example, Amazon S3, IAM, or Amazon RDS). For a list of
|
||||
// namespaces, see
|
||||
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces.
|
||||
Service string
|
||||
|
||||
// The region the resource resides in. Note that the ARNs for some resources do not require a region, so this
|
||||
// component might be omitted.
|
||||
Region string
|
||||
|
||||
// The ID of the AWS account that owns the resource, without the hyphens. For example, 123456789012. Note that the
|
||||
// ARNs for some resources don't require an account number, so this component might be omitted.
|
||||
AccountID string
|
||||
|
||||
// The content of this part of the ARN varies by service. It often includes an indicator of the type of resource —
|
||||
// for example, an IAM user or Amazon RDS database - followed by a slash (/) or a colon (:), followed by the
|
||||
// resource name itself. Some services allows paths for resource names, as described in
|
||||
// http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arns-paths.
|
||||
Resource string
|
||||
}
|
||||
|
||||
// Parse parses an ARN into its constituent parts.
|
||||
//
|
||||
// Some example ARNs:
|
||||
// arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment
|
||||
// arn:aws:iam::123456789012:user/David
|
||||
// arn:aws:rds:eu-west-1:123456789012:db:mysql-db
|
||||
// arn:aws:s3:::my_corporate_bucket/exampleobject.png
|
||||
func Parse(arn string) (ARN, error) {
|
||||
if !strings.HasPrefix(arn, arnPrefix) {
|
||||
return ARN{}, errors.New(invalidPrefix)
|
||||
}
|
||||
sections := strings.SplitN(arn, arnDelimiter, arnSections)
|
||||
if len(sections) != arnSections {
|
||||
return ARN{}, errors.New(invalidSections)
|
||||
}
|
||||
return ARN{
|
||||
Partition: sections[sectionPartition],
|
||||
Service: sections[sectionService],
|
||||
Region: sections[sectionRegion],
|
||||
AccountID: sections[sectionAccountID],
|
||||
Resource: sections[sectionResource],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// String returns the canonical representation of the ARN
|
||||
func (arn ARN) String() string {
|
||||
return arnPrefix +
|
||||
arn.Partition + arnDelimiter +
|
||||
arn.Service + arnDelimiter +
|
||||
arn.Region + arnDelimiter +
|
||||
arn.AccountID + arnDelimiter +
|
||||
arn.Resource
|
||||
}
|
||||
90
vendor/github.com/aws/aws-sdk-go/aws/arn/arn_test.go
generated
vendored
Normal file
90
vendor/github.com/aws/aws-sdk-go/aws/arn/arn_test.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// +build go1.7
|
||||
|
||||
package arn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseARN(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
arn ARN
|
||||
err error
|
||||
}{
|
||||
{
|
||||
input: "invalid",
|
||||
err: errors.New(invalidPrefix),
|
||||
},
|
||||
{
|
||||
input: "arn:nope",
|
||||
err: errors.New(invalidSections),
|
||||
},
|
||||
{
|
||||
input: "arn:aws:ecr:us-west-2:123456789012:repository/foo/bar",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "ecr",
|
||||
Region: "us-west-2",
|
||||
AccountID: "123456789012",
|
||||
Resource: "repository/foo/bar",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "elasticbeanstalk",
|
||||
Region: "us-east-1",
|
||||
AccountID: "123456789012",
|
||||
Resource: "environment/My App/MyEnvironment",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "arn:aws:iam::123456789012:user/David",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "iam",
|
||||
Region: "",
|
||||
AccountID: "123456789012",
|
||||
Resource: "user/David",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "arn:aws:rds:eu-west-1:123456789012:db:mysql-db",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "rds",
|
||||
Region: "eu-west-1",
|
||||
AccountID: "123456789012",
|
||||
Resource: "db:mysql-db",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: "arn:aws:s3:::my_corporate_bucket/exampleobject.png",
|
||||
arn: ARN{
|
||||
Partition: "aws",
|
||||
Service: "s3",
|
||||
Region: "",
|
||||
AccountID: "",
|
||||
Resource: "my_corporate_bucket/exampleobject.png",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.input, func(t *testing.T) {
|
||||
spec, err := Parse(tc.input)
|
||||
if tc.arn != spec {
|
||||
t.Errorf("Expected %q to parse as %v, but got %v", tc.input, tc.arn, spec)
|
||||
}
|
||||
if err == nil && tc.err != nil {
|
||||
t.Errorf("Expected err to be %v, but got nil", tc.err)
|
||||
} else if err != nil && tc.err == nil {
|
||||
t.Errorf("Expected err to be nil, but got %v", err)
|
||||
} else if err != nil && tc.err != nil && err.Error() != tc.err.Error() {
|
||||
t.Errorf("Expected err to be %v, but got %v", tc.err, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
145
vendor/github.com/aws/aws-sdk-go/aws/awserr/error.go
generated
vendored
Normal file
145
vendor/github.com/aws/aws-sdk-go/aws/awserr/error.go
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
// Package awserr represents API error interface accessors for the SDK.
|
||||
package awserr
|
||||
|
||||
// An Error wraps lower level errors with code, message and an original error.
|
||||
// The underlying concrete error type may also satisfy other interfaces which
|
||||
// can be to used to obtain more specific information about the error.
|
||||
//
|
||||
// Calling Error() or String() will always include the full information about
|
||||
// an error based on its underlying type.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// output, err := s3manage.Upload(svc, input, opts)
|
||||
// if err != nil {
|
||||
// if awsErr, ok := err.(awserr.Error); ok {
|
||||
// // Get error details
|
||||
// log.Println("Error:", awsErr.Code(), awsErr.Message())
|
||||
//
|
||||
// // Prints out full error message, including original error if there was one.
|
||||
// log.Println("Error:", awsErr.Error())
|
||||
//
|
||||
// // Get original error
|
||||
// if origErr := awsErr.OrigErr(); origErr != nil {
|
||||
// // operate on original error.
|
||||
// }
|
||||
// } else {
|
||||
// fmt.Println(err.Error())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
type Error interface {
|
||||
// Satisfy the generic error interface.
|
||||
error
|
||||
|
||||
// Returns the short phrase depicting the classification of the error.
|
||||
Code() string
|
||||
|
||||
// Returns the error details message.
|
||||
Message() string
|
||||
|
||||
// Returns the original error if one was set. Nil is returned if not set.
|
||||
OrigErr() error
|
||||
}
|
||||
|
||||
// BatchError is a batch of errors which also wraps lower level errors with
|
||||
// code, message, and original errors. Calling Error() will include all errors
|
||||
// that occurred in the batch.
|
||||
//
|
||||
// Deprecated: Replaced with BatchedErrors. Only defined for backwards
|
||||
// compatibility.
|
||||
type BatchError interface {
|
||||
// Satisfy the generic error interface.
|
||||
error
|
||||
|
||||
// Returns the short phrase depicting the classification of the error.
|
||||
Code() string
|
||||
|
||||
// Returns the error details message.
|
||||
Message() string
|
||||
|
||||
// Returns the original error if one was set. Nil is returned if not set.
|
||||
OrigErrs() []error
|
||||
}
|
||||
|
||||
// BatchedErrors is a batch of errors which also wraps lower level errors with
|
||||
// code, message, and original errors. Calling Error() will include all errors
|
||||
// that occurred in the batch.
|
||||
//
|
||||
// Replaces BatchError
|
||||
type BatchedErrors interface {
|
||||
// Satisfy the base Error interface.
|
||||
Error
|
||||
|
||||
// Returns the original error if one was set. Nil is returned if not set.
|
||||
OrigErrs() []error
|
||||
}
|
||||
|
||||
// New returns an Error object described by the code, message, and origErr.
|
||||
//
|
||||
// If origErr satisfies the Error interface it will not be wrapped within a new
|
||||
// Error object and will instead be returned.
|
||||
func New(code, message string, origErr error) Error {
|
||||
var errs []error
|
||||
if origErr != nil {
|
||||
errs = append(errs, origErr)
|
||||
}
|
||||
return newBaseError(code, message, errs)
|
||||
}
|
||||
|
||||
// NewBatchError returns an BatchedErrors with a collection of errors as an
|
||||
// array of errors.
|
||||
func NewBatchError(code, message string, errs []error) BatchedErrors {
|
||||
return newBaseError(code, message, errs)
|
||||
}
|
||||
|
||||
// A RequestFailure is an interface to extract request failure information from
|
||||
// an Error such as the request ID of the failed request returned by a service.
|
||||
// RequestFailures may not always have a requestID value if the request failed
|
||||
// prior to reaching the service such as a connection error.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// output, err := s3manage.Upload(svc, input, opts)
|
||||
// if err != nil {
|
||||
// if reqerr, ok := err.(RequestFailure); ok {
|
||||
// log.Println("Request failed", reqerr.Code(), reqerr.Message(), reqerr.RequestID())
|
||||
// } else {
|
||||
// log.Println("Error:", err.Error())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Combined with awserr.Error:
|
||||
//
|
||||
// output, err := s3manage.Upload(svc, input, opts)
|
||||
// if err != nil {
|
||||
// if awsErr, ok := err.(awserr.Error); ok {
|
||||
// // Generic AWS Error with Code, Message, and original error (if any)
|
||||
// fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
|
||||
//
|
||||
// if reqErr, ok := err.(awserr.RequestFailure); ok {
|
||||
// // A service error occurred
|
||||
// fmt.Println(reqErr.StatusCode(), reqErr.RequestID())
|
||||
// }
|
||||
// } else {
|
||||
// fmt.Println(err.Error())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
type RequestFailure interface {
|
||||
Error
|
||||
|
||||
// The status code of the HTTP response.
|
||||
StatusCode() int
|
||||
|
||||
// The request ID returned by the service for a request failure. This will
|
||||
// be empty if no request ID is available such as the request failed due
|
||||
// to a connection error.
|
||||
RequestID() string
|
||||
}
|
||||
|
||||
// NewRequestFailure returns a new request error wrapper for the given Error
|
||||
// provided.
|
||||
func NewRequestFailure(err Error, statusCode int, reqID string) RequestFailure {
|
||||
return newRequestError(err, statusCode, reqID)
|
||||
}
|
||||
194
vendor/github.com/aws/aws-sdk-go/aws/awserr/types.go
generated
vendored
Normal file
194
vendor/github.com/aws/aws-sdk-go/aws/awserr/types.go
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
package awserr
|
||||
|
||||
import "fmt"
|
||||
|
||||
// SprintError returns a string of the formatted error code.
|
||||
//
|
||||
// Both extra and origErr are optional. If they are included their lines
|
||||
// will be added, but if they are not included their lines will be ignored.
|
||||
func SprintError(code, message, extra string, origErr error) string {
|
||||
msg := fmt.Sprintf("%s: %s", code, message)
|
||||
if extra != "" {
|
||||
msg = fmt.Sprintf("%s\n\t%s", msg, extra)
|
||||
}
|
||||
if origErr != nil {
|
||||
msg = fmt.Sprintf("%s\ncaused by: %s", msg, origErr.Error())
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
// A baseError wraps the code and message which defines an error. It also
|
||||
// can be used to wrap an original error object.
|
||||
//
|
||||
// Should be used as the root for errors satisfying the awserr.Error. Also
|
||||
// for any error which does not fit into a specific error wrapper type.
|
||||
type baseError struct {
|
||||
// Classification of error
|
||||
code string
|
||||
|
||||
// Detailed information about error
|
||||
message string
|
||||
|
||||
// Optional original error this error is based off of. Allows building
|
||||
// chained errors.
|
||||
errs []error
|
||||
}
|
||||
|
||||
// newBaseError returns an error object for the code, message, and errors.
|
||||
//
|
||||
// code is a short no whitespace phrase depicting the classification of
|
||||
// the error that is being created.
|
||||
//
|
||||
// message is the free flow string containing detailed information about the
|
||||
// error.
|
||||
//
|
||||
// origErrs is the error objects which will be nested under the new errors to
|
||||
// be returned.
|
||||
func newBaseError(code, message string, origErrs []error) *baseError {
|
||||
b := &baseError{
|
||||
code: code,
|
||||
message: message,
|
||||
errs: origErrs,
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
//
|
||||
// See ErrorWithExtra for formatting.
|
||||
//
|
||||
// Satisfies the error interface.
|
||||
func (b baseError) Error() string {
|
||||
size := len(b.errs)
|
||||
if size > 0 {
|
||||
return SprintError(b.code, b.message, "", errorList(b.errs))
|
||||
}
|
||||
|
||||
return SprintError(b.code, b.message, "", nil)
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
// Alias for Error to satisfy the stringer interface.
|
||||
func (b baseError) String() string {
|
||||
return b.Error()
|
||||
}
|
||||
|
||||
// Code returns the short phrase depicting the classification of the error.
|
||||
func (b baseError) Code() string {
|
||||
return b.code
|
||||
}
|
||||
|
||||
// Message returns the error details message.
|
||||
func (b baseError) Message() string {
|
||||
return b.message
|
||||
}
|
||||
|
||||
// OrigErr returns the original error if one was set. Nil is returned if no
|
||||
// error was set. This only returns the first element in the list. If the full
|
||||
// list is needed, use BatchedErrors.
|
||||
func (b baseError) OrigErr() error {
|
||||
switch len(b.errs) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return b.errs[0]
|
||||
default:
|
||||
if err, ok := b.errs[0].(Error); ok {
|
||||
return NewBatchError(err.Code(), err.Message(), b.errs[1:])
|
||||
}
|
||||
return NewBatchError("BatchedErrors",
|
||||
"multiple errors occurred", b.errs)
|
||||
}
|
||||
}
|
||||
|
||||
// OrigErrs returns the original errors if one was set. An empty slice is
|
||||
// returned if no error was set.
|
||||
func (b baseError) OrigErrs() []error {
|
||||
return b.errs
|
||||
}
|
||||
|
||||
// So that the Error interface type can be included as an anonymous field
|
||||
// in the requestError struct and not conflict with the error.Error() method.
|
||||
type awsError Error
|
||||
|
||||
// A requestError wraps a request or service error.
|
||||
//
|
||||
// Composed of baseError for code, message, and original error.
|
||||
type requestError struct {
|
||||
awsError
|
||||
statusCode int
|
||||
requestID string
|
||||
}
|
||||
|
||||
// newRequestError returns a wrapped error with additional information for
|
||||
// request status code, and service requestID.
|
||||
//
|
||||
// Should be used to wrap all request which involve service requests. Even if
|
||||
// the request failed without a service response, but had an HTTP status code
|
||||
// that may be meaningful.
|
||||
//
|
||||
// Also wraps original errors via the baseError.
|
||||
func newRequestError(err Error, statusCode int, requestID string) *requestError {
|
||||
return &requestError{
|
||||
awsError: err,
|
||||
statusCode: statusCode,
|
||||
requestID: requestID,
|
||||
}
|
||||
}
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
// Satisfies the error interface.
|
||||
func (r requestError) Error() string {
|
||||
extra := fmt.Sprintf("status code: %d, request id: %s",
|
||||
r.statusCode, r.requestID)
|
||||
return SprintError(r.Code(), r.Message(), extra, r.OrigErr())
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
// Alias for Error to satisfy the stringer interface.
|
||||
func (r requestError) String() string {
|
||||
return r.Error()
|
||||
}
|
||||
|
||||
// StatusCode returns the wrapped status code for the error
|
||||
func (r requestError) StatusCode() int {
|
||||
return r.statusCode
|
||||
}
|
||||
|
||||
// RequestID returns the wrapped requestID
|
||||
func (r requestError) RequestID() string {
|
||||
return r.requestID
|
||||
}
|
||||
|
||||
// OrigErrs returns the original errors if one was set. An empty slice is
|
||||
// returned if no error was set.
|
||||
func (r requestError) OrigErrs() []error {
|
||||
if b, ok := r.awsError.(BatchedErrors); ok {
|
||||
return b.OrigErrs()
|
||||
}
|
||||
return []error{r.OrigErr()}
|
||||
}
|
||||
|
||||
// An error list that satisfies the golang interface
|
||||
type errorList []error
|
||||
|
||||
// Error returns the string representation of the error.
|
||||
//
|
||||
// Satisfies the error interface.
|
||||
func (e errorList) Error() string {
|
||||
msg := ""
|
||||
// How do we want to handle the array size being zero
|
||||
if size := len(e); size > 0 {
|
||||
for i := 0; i < size; i++ {
|
||||
msg += fmt.Sprintf("%s", e[i].Error())
|
||||
// We check the next index to see if it is within the slice.
|
||||
// If it is, then we append a newline. We do this, because unit tests
|
||||
// could be broken with the additional '\n'
|
||||
if i+1 < size {
|
||||
msg += "\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
return msg
|
||||
}
|
||||
108
vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go
generated
vendored
Normal file
108
vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
package awsutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Copy deeply copies a src structure to dst. Useful for copying request and
|
||||
// response structures.
|
||||
//
|
||||
// Can copy between structs of different type, but will only copy fields which
|
||||
// are assignable, and exist in both structs. Fields which are not assignable,
|
||||
// or do not exist in both structs are ignored.
|
||||
func Copy(dst, src interface{}) {
|
||||
dstval := reflect.ValueOf(dst)
|
||||
if !dstval.IsValid() {
|
||||
panic("Copy dst cannot be nil")
|
||||
}
|
||||
|
||||
rcopy(dstval, reflect.ValueOf(src), true)
|
||||
}
|
||||
|
||||
// CopyOf returns a copy of src while also allocating the memory for dst.
|
||||
// src must be a pointer type or this operation will fail.
|
||||
func CopyOf(src interface{}) (dst interface{}) {
|
||||
dsti := reflect.New(reflect.TypeOf(src).Elem())
|
||||
dst = dsti.Interface()
|
||||
rcopy(dsti, reflect.ValueOf(src), true)
|
||||
return
|
||||
}
|
||||
|
||||
// rcopy performs a recursive copy of values from the source to destination.
|
||||
//
|
||||
// root is used to skip certain aspects of the copy which are not valid
|
||||
// for the root node of a object.
|
||||
func rcopy(dst, src reflect.Value, root bool) {
|
||||
if !src.IsValid() {
|
||||
return
|
||||
}
|
||||
|
||||
switch src.Kind() {
|
||||
case reflect.Ptr:
|
||||
if _, ok := src.Interface().(io.Reader); ok {
|
||||
if dst.Kind() == reflect.Ptr && dst.Elem().CanSet() {
|
||||
dst.Elem().Set(src)
|
||||
} else if dst.CanSet() {
|
||||
dst.Set(src)
|
||||
}
|
||||
} else {
|
||||
e := src.Type().Elem()
|
||||
if dst.CanSet() && !src.IsNil() {
|
||||
if _, ok := src.Interface().(*time.Time); !ok {
|
||||
dst.Set(reflect.New(e))
|
||||
} else {
|
||||
tempValue := reflect.New(e)
|
||||
tempValue.Elem().Set(src.Elem())
|
||||
// Sets time.Time's unexported values
|
||||
dst.Set(tempValue)
|
||||
}
|
||||
}
|
||||
if src.Elem().IsValid() {
|
||||
// Keep the current root state since the depth hasn't changed
|
||||
rcopy(dst.Elem(), src.Elem(), root)
|
||||
}
|
||||
}
|
||||
case reflect.Struct:
|
||||
t := dst.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
name := t.Field(i).Name
|
||||
srcVal := src.FieldByName(name)
|
||||
dstVal := dst.FieldByName(name)
|
||||
if srcVal.IsValid() && dstVal.CanSet() {
|
||||
rcopy(dstVal, srcVal, false)
|
||||
}
|
||||
}
|
||||
case reflect.Slice:
|
||||
if src.IsNil() {
|
||||
break
|
||||
}
|
||||
|
||||
s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
|
||||
dst.Set(s)
|
||||
for i := 0; i < src.Len(); i++ {
|
||||
rcopy(dst.Index(i), src.Index(i), false)
|
||||
}
|
||||
case reflect.Map:
|
||||
if src.IsNil() {
|
||||
break
|
||||
}
|
||||
|
||||
s := reflect.MakeMap(src.Type())
|
||||
dst.Set(s)
|
||||
for _, k := range src.MapKeys() {
|
||||
v := src.MapIndex(k)
|
||||
v2 := reflect.New(v.Type()).Elem()
|
||||
rcopy(v2, v, false)
|
||||
dst.SetMapIndex(k, v2)
|
||||
}
|
||||
default:
|
||||
// Assign the value if possible. If its not assignable, the value would
|
||||
// need to be converted and the impact of that may be unexpected, or is
|
||||
// not compatible with the dst type.
|
||||
if src.Type().AssignableTo(dst.Type()) {
|
||||
dst.Set(src)
|
||||
}
|
||||
}
|
||||
}
|
||||
353
vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go
generated
vendored
Normal file
353
vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy_test.go
generated
vendored
Normal file
@@ -0,0 +1,353 @@
|
||||
package awsutil_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
)
|
||||
|
||||
func ExampleCopy() {
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
f1 := &Foo{A: 1, B: []*string{&str1, &str2}}
|
||||
|
||||
// Do the copy
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Print the result
|
||||
fmt.Println(awsutil.Prettify(f2))
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// A: 1,
|
||||
// B: ["hello","bye bye"]
|
||||
// }
|
||||
}
|
||||
|
||||
func TestCopy1(t *testing.T) {
|
||||
type Bar struct {
|
||||
a *int
|
||||
B *int
|
||||
c int
|
||||
D int
|
||||
}
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
D *time.Time
|
||||
E *Bar
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
int1 := 1
|
||||
int2 := 2
|
||||
intPtr1 := 1
|
||||
intPtr2 := 2
|
||||
now := time.Now()
|
||||
f1 := &Foo{
|
||||
A: 1,
|
||||
B: []*string{&str1, &str2},
|
||||
C: map[string]*int{
|
||||
"A": &int1,
|
||||
"B": &int2,
|
||||
},
|
||||
D: &now,
|
||||
E: &Bar{
|
||||
&intPtr1,
|
||||
&intPtr2,
|
||||
2,
|
||||
3,
|
||||
},
|
||||
}
|
||||
|
||||
// Do the copy
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values are equal
|
||||
if v1, v2 := f2.A, f1.A; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.B, f1.B; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.C, f1.C; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.D, f1.D; !v1.Equal(*v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.E.B, f1.E.B; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.E.D, f1.E.D; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
|
||||
// But pointers are not!
|
||||
str3 := "nothello"
|
||||
int3 := 57
|
||||
f2.A = 100
|
||||
*f2.B[0] = str3
|
||||
*f2.C["B"] = int3
|
||||
*f2.D = time.Now()
|
||||
f2.E.a = &int3
|
||||
*f2.E.B = int3
|
||||
f2.E.c = 5
|
||||
f2.E.D = 5
|
||||
if v1, v2 := f2.A, f1.A; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.B, f1.B; reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.C, f1.C; reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.D, f1.D; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.E.a, f1.E.a; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.E.B, f1.E.B; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.E.c, f1.E.c; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.E.D, f1.E.D; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyNestedWithUnexported(t *testing.T) {
|
||||
type Bar struct {
|
||||
a int
|
||||
B int
|
||||
}
|
||||
type Foo struct {
|
||||
A string
|
||||
B Bar
|
||||
}
|
||||
|
||||
f1 := &Foo{A: "string", B: Bar{a: 1, B: 2}}
|
||||
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values match
|
||||
if v1, v2 := f2.A, f1.A; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.B, f1.B; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.B.a, f1.B.a; v1 == v2 {
|
||||
t.Errorf("expected values to be not equivalent, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := f2.B.B, f2.B.B; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyIgnoreNilMembers(t *testing.T) {
|
||||
type Foo struct {
|
||||
A *string
|
||||
B []string
|
||||
C map[string]string
|
||||
}
|
||||
|
||||
f := &Foo{}
|
||||
if v1 := f.A; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f.B; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f.C; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
|
||||
var f2 Foo
|
||||
awsutil.Copy(&f2, f)
|
||||
if v1 := f2.A; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f2.B; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f2.C; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
|
||||
fcopy := awsutil.CopyOf(f)
|
||||
f3 := fcopy.(*Foo)
|
||||
if v1 := f3.A; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f3.B; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1 := f3.C; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyPrimitive(t *testing.T) {
|
||||
str := "hello"
|
||||
var s string
|
||||
awsutil.Copy(&s, &str)
|
||||
if v1, v2 := "hello", s; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyNil(t *testing.T) {
|
||||
var s string
|
||||
awsutil.Copy(&s, nil)
|
||||
if v1, v2 := "", s; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyReader(t *testing.T) {
|
||||
var buf io.Reader = bytes.NewReader([]byte("hello world"))
|
||||
var r io.Reader
|
||||
awsutil.Copy(&r, buf)
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, but received %v", err)
|
||||
}
|
||||
if v1, v2 := []byte("hello world"), b; !bytes.Equal(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
|
||||
// empty bytes because this is not a deep copy
|
||||
b, err = ioutil.ReadAll(buf)
|
||||
if err != nil {
|
||||
t.Errorf("expected no error, but received %v", err)
|
||||
}
|
||||
if v1, v2 := []byte(""), b; !bytes.Equal(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyDifferentStructs(t *testing.T) {
|
||||
type SrcFoo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
SrcUnique string
|
||||
SameNameDiffType int
|
||||
unexportedPtr *int
|
||||
ExportedPtr *int
|
||||
}
|
||||
type DstFoo struct {
|
||||
A int
|
||||
B []*string
|
||||
C map[string]*int
|
||||
DstUnique int
|
||||
SameNameDiffType string
|
||||
unexportedPtr *int
|
||||
ExportedPtr *int
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
int1 := 1
|
||||
int2 := 2
|
||||
f1 := &SrcFoo{
|
||||
A: 1,
|
||||
B: []*string{&str1, &str2},
|
||||
C: map[string]*int{
|
||||
"A": &int1,
|
||||
"B": &int2,
|
||||
},
|
||||
SrcUnique: "unique",
|
||||
SameNameDiffType: 1,
|
||||
unexportedPtr: &int1,
|
||||
ExportedPtr: &int2,
|
||||
}
|
||||
|
||||
// Do the copy
|
||||
var f2 DstFoo
|
||||
awsutil.Copy(&f2, f1)
|
||||
|
||||
// Values are equal
|
||||
if v1, v2 := f2.A, f1.A; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.B, f1.B; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := f2.C, f1.C; !reflect.DeepEqual(v1, v2) {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := "unique", f1.SrcUnique; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := 1, f1.SameNameDiffType; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := 0, f2.DstUnique; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := "", f2.SameNameDiffType; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := int1, *f1.unexportedPtr; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1 := f2.unexportedPtr; v1 != nil {
|
||||
t.Errorf("expected nil, but received %v", v1)
|
||||
}
|
||||
if v1, v2 := int2, *f1.ExportedPtr; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
if v1, v2 := int2, *f2.ExportedPtr; v1 != v2 {
|
||||
t.Errorf("expected values to be equivalent but received %v and %v", v1, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleCopyOf() {
|
||||
type Foo struct {
|
||||
A int
|
||||
B []*string
|
||||
}
|
||||
|
||||
// Create the initial value
|
||||
str1 := "hello"
|
||||
str2 := "bye bye"
|
||||
f1 := &Foo{A: 1, B: []*string{&str1, &str2}}
|
||||
|
||||
// Do the copy
|
||||
v := awsutil.CopyOf(f1)
|
||||
var f2 *Foo = v.(*Foo)
|
||||
|
||||
// Print the result
|
||||
fmt.Println(awsutil.Prettify(f2))
|
||||
|
||||
// Output:
|
||||
// {
|
||||
// A: 1,
|
||||
// B: ["hello","bye bye"]
|
||||
// }
|
||||
}
|
||||
27
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go
generated
vendored
Normal file
27
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package awsutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// DeepEqual returns if the two values are deeply equal like reflect.DeepEqual.
|
||||
// In addition to this, this method will also dereference the input values if
|
||||
// possible so the DeepEqual performed will not fail if one parameter is a
|
||||
// pointer and the other is not.
|
||||
//
|
||||
// DeepEqual will not perform indirection of nested values of the input parameters.
|
||||
func DeepEqual(a, b interface{}) bool {
|
||||
ra := reflect.Indirect(reflect.ValueOf(a))
|
||||
rb := reflect.Indirect(reflect.ValueOf(b))
|
||||
|
||||
if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid {
|
||||
// If the elements are both nil, and of the same type the are equal
|
||||
// If they are of different types they are not equal
|
||||
return reflect.TypeOf(a) == reflect.TypeOf(b)
|
||||
} else if raValid != rbValid {
|
||||
// Both values must be valid to be equal
|
||||
return false
|
||||
}
|
||||
|
||||
return reflect.DeepEqual(ra.Interface(), rb.Interface())
|
||||
}
|
||||
30
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal_test.go
generated
vendored
Normal file
30
vendor/github.com/aws/aws-sdk-go/aws/awsutil/equal_test.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package awsutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
)
|
||||
|
||||
func TestDeepEqual(t *testing.T) {
|
||||
cases := []struct {
|
||||
a, b interface{}
|
||||
equal bool
|
||||
}{
|
||||
{"a", "a", true},
|
||||
{"a", "b", false},
|
||||
{"a", aws.String(""), false},
|
||||
{"a", nil, false},
|
||||
{"a", aws.String("a"), true},
|
||||
{(*bool)(nil), (*bool)(nil), true},
|
||||
{(*bool)(nil), (*string)(nil), false},
|
||||
{nil, nil, true},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
if awsutil.DeepEqual(c.a, c.b) != c.equal {
|
||||
t.Errorf("%d, a:%v b:%v, %t", i, c.a, c.b, c.equal)
|
||||
}
|
||||
}
|
||||
}
|
||||
222
vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go
generated
vendored
Normal file
222
vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
package awsutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jmespath/go-jmespath"
|
||||
)
|
||||
|
||||
var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`)
|
||||
|
||||
// rValuesAtPath returns a slice of values found in value v. The values
|
||||
// in v are explored recursively so all nested values are collected.
|
||||
func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTerm bool) []reflect.Value {
|
||||
pathparts := strings.Split(path, "||")
|
||||
if len(pathparts) > 1 {
|
||||
for _, pathpart := range pathparts {
|
||||
vals := rValuesAtPath(v, pathpart, createPath, caseSensitive, nilTerm)
|
||||
if len(vals) > 0 {
|
||||
return vals
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
values := []reflect.Value{reflect.Indirect(reflect.ValueOf(v))}
|
||||
components := strings.Split(path, ".")
|
||||
for len(values) > 0 && len(components) > 0 {
|
||||
var index *int64
|
||||
var indexStar bool
|
||||
c := strings.TrimSpace(components[0])
|
||||
if c == "" { // no actual component, illegal syntax
|
||||
return nil
|
||||
} else if caseSensitive && c != "*" && strings.ToLower(c[0:1]) == c[0:1] {
|
||||
// TODO normalize case for user
|
||||
return nil // don't support unexported fields
|
||||
}
|
||||
|
||||
// parse this component
|
||||
if m := indexRe.FindStringSubmatch(c); m != nil {
|
||||
c = m[1]
|
||||
if m[2] == "" {
|
||||
index = nil
|
||||
indexStar = true
|
||||
} else {
|
||||
i, _ := strconv.ParseInt(m[2], 10, 32)
|
||||
index = &i
|
||||
indexStar = false
|
||||
}
|
||||
}
|
||||
|
||||
nextvals := []reflect.Value{}
|
||||
for _, value := range values {
|
||||
// pull component name out of struct member
|
||||
if value.Kind() != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
|
||||
if c == "*" { // pull all members
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
if f := reflect.Indirect(value.Field(i)); f.IsValid() {
|
||||
nextvals = append(nextvals, f)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
value = value.FieldByNameFunc(func(name string) bool {
|
||||
if c == name {
|
||||
return true
|
||||
} else if !caseSensitive && strings.ToLower(name) == strings.ToLower(c) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
if nilTerm && value.Kind() == reflect.Ptr && len(components[1:]) == 0 {
|
||||
if !value.IsNil() {
|
||||
value.Set(reflect.Zero(value.Type()))
|
||||
}
|
||||
return []reflect.Value{value}
|
||||
}
|
||||
|
||||
if createPath && value.Kind() == reflect.Ptr && value.IsNil() {
|
||||
// TODO if the value is the terminus it should not be created
|
||||
// if the value to be set to its position is nil.
|
||||
value.Set(reflect.New(value.Type().Elem()))
|
||||
value = value.Elem()
|
||||
} else {
|
||||
value = reflect.Indirect(value)
|
||||
}
|
||||
|
||||
if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
|
||||
if !createPath && value.IsNil() {
|
||||
value = reflect.ValueOf(nil)
|
||||
}
|
||||
}
|
||||
|
||||
if value.IsValid() {
|
||||
nextvals = append(nextvals, value)
|
||||
}
|
||||
}
|
||||
values = nextvals
|
||||
|
||||
if indexStar || index != nil {
|
||||
nextvals = []reflect.Value{}
|
||||
for _, valItem := range values {
|
||||
value := reflect.Indirect(valItem)
|
||||
if value.Kind() != reflect.Slice {
|
||||
continue
|
||||
}
|
||||
|
||||
if indexStar { // grab all indices
|
||||
for i := 0; i < value.Len(); i++ {
|
||||
idx := reflect.Indirect(value.Index(i))
|
||||
if idx.IsValid() {
|
||||
nextvals = append(nextvals, idx)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// pull out index
|
||||
i := int(*index)
|
||||
if i >= value.Len() { // check out of bounds
|
||||
if createPath {
|
||||
// TODO resize slice
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else if i < 0 { // support negative indexing
|
||||
i = value.Len() + i
|
||||
}
|
||||
value = reflect.Indirect(value.Index(i))
|
||||
|
||||
if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
|
||||
if !createPath && value.IsNil() {
|
||||
value = reflect.ValueOf(nil)
|
||||
}
|
||||
}
|
||||
|
||||
if value.IsValid() {
|
||||
nextvals = append(nextvals, value)
|
||||
}
|
||||
}
|
||||
values = nextvals
|
||||
}
|
||||
|
||||
components = components[1:]
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// ValuesAtPath returns a list of values at the case insensitive lexical
|
||||
// path inside of a structure.
|
||||
func ValuesAtPath(i interface{}, path string) ([]interface{}, error) {
|
||||
result, err := jmespath.Search(path, i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(result)
|
||||
if !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) {
|
||||
return nil, nil
|
||||
}
|
||||
if s, ok := result.([]interface{}); ok {
|
||||
return s, err
|
||||
}
|
||||
if v.Kind() == reflect.Map && v.Len() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if v.Kind() == reflect.Slice {
|
||||
out := make([]interface{}, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
out[i] = v.Index(i).Interface()
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
return []interface{}{result}, nil
|
||||
}
|
||||
|
||||
// SetValueAtPath sets a value at the case insensitive lexical path inside
|
||||
// of a structure.
|
||||
func SetValueAtPath(i interface{}, path string, v interface{}) {
|
||||
if rvals := rValuesAtPath(i, path, true, false, v == nil); rvals != nil {
|
||||
for _, rval := range rvals {
|
||||
if rval.Kind() == reflect.Ptr && rval.IsNil() {
|
||||
continue
|
||||
}
|
||||
setValue(rval, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setValue(dstVal reflect.Value, src interface{}) {
|
||||
if dstVal.Kind() == reflect.Ptr {
|
||||
dstVal = reflect.Indirect(dstVal)
|
||||
}
|
||||
srcVal := reflect.ValueOf(src)
|
||||
|
||||
if !srcVal.IsValid() { // src is literal nil
|
||||
if dstVal.CanAddr() {
|
||||
// Convert to pointer so that pointer's value can be nil'ed
|
||||
// dstVal = dstVal.Addr()
|
||||
}
|
||||
dstVal.Set(reflect.Zero(dstVal.Type()))
|
||||
|
||||
} else if srcVal.Kind() == reflect.Ptr {
|
||||
if srcVal.IsNil() {
|
||||
srcVal = reflect.Zero(dstVal.Type())
|
||||
} else {
|
||||
srcVal = reflect.ValueOf(src).Elem()
|
||||
}
|
||||
dstVal.Set(srcVal)
|
||||
} else {
|
||||
dstVal.Set(srcVal)
|
||||
}
|
||||
|
||||
}
|
||||
182
vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go
generated
vendored
Normal file
182
vendor/github.com/aws/aws-sdk-go/aws/awsutil/path_value_test.go
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
package awsutil_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awsutil"
|
||||
)
|
||||
|
||||
type Struct struct {
|
||||
A []Struct
|
||||
z []Struct
|
||||
B *Struct
|
||||
D *Struct
|
||||
C string
|
||||
E map[string]string
|
||||
}
|
||||
|
||||
var data = Struct{
|
||||
A: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}},
|
||||
z: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}},
|
||||
B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}},
|
||||
C: "initial",
|
||||
}
|
||||
var data2 = Struct{A: []Struct{
|
||||
{A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}},
|
||||
{A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}},
|
||||
}}
|
||||
|
||||
func TestValueAtPathSuccess(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
expect []interface{}
|
||||
data interface{}
|
||||
path string
|
||||
}{
|
||||
{[]interface{}{"initial"}, data, "C"},
|
||||
{[]interface{}{"value1"}, data, "A[0].C"},
|
||||
{[]interface{}{"value2"}, data, "A[1].C"},
|
||||
{[]interface{}{"value3"}, data, "A[2].C"},
|
||||
{[]interface{}{"value3"}, data, "a[2].c"},
|
||||
{[]interface{}{"value3"}, data, "A[-1].C"},
|
||||
{[]interface{}{"value1", "value2", "value3"}, data, "A[].C"},
|
||||
{[]interface{}{"terminal"}, data, "B . B . C"},
|
||||
{[]interface{}{"initial"}, data, "A.D.X || C"},
|
||||
{[]interface{}{"initial"}, data, "A[0].B || C"},
|
||||
{[]interface{}{
|
||||
Struct{A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}},
|
||||
Struct{A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}},
|
||||
}, data2, "A"},
|
||||
}
|
||||
for i, c := range testCases {
|
||||
v, err := awsutil.ValuesAtPath(c.data, c.path)
|
||||
if err != nil {
|
||||
t.Errorf("case %v, expected no error, %v", i, c.path)
|
||||
}
|
||||
if e, a := c.expect, v; !awsutil.DeepEqual(e, a) {
|
||||
t.Errorf("case %v, %v", i, c.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueAtPathFailure(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
expect []interface{}
|
||||
errContains string
|
||||
data interface{}
|
||||
path string
|
||||
}{
|
||||
{nil, "", data, "C.x"},
|
||||
{nil, "SyntaxError: Invalid token: tDot", data, ".x"},
|
||||
{nil, "", data, "X.Y.Z"},
|
||||
{nil, "", data, "A[100].C"},
|
||||
{nil, "", data, "A[3].C"},
|
||||
{nil, "", data, "B.B.C.Z"},
|
||||
{nil, "", data, "z[-1].C"},
|
||||
{nil, "", nil, "A.B.C"},
|
||||
{[]interface{}{}, "", Struct{}, "A"},
|
||||
{nil, "", data, "A[0].B.C"},
|
||||
{nil, "", data, "D"},
|
||||
}
|
||||
|
||||
for i, c := range testCases {
|
||||
v, err := awsutil.ValuesAtPath(c.data, c.path)
|
||||
if c.errContains != "" {
|
||||
if !strings.Contains(err.Error(), c.errContains) {
|
||||
t.Errorf("case %v, expected error, %v", i, c.path)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("case %v, expected no error, %v", i, c.path)
|
||||
}
|
||||
}
|
||||
if e, a := c.expect, v; !awsutil.DeepEqual(e, a) {
|
||||
t.Errorf("case %v, %v", i, c.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetValueAtPathSuccess(t *testing.T) {
|
||||
var s Struct
|
||||
awsutil.SetValueAtPath(&s, "C", "test1")
|
||||
awsutil.SetValueAtPath(&s, "B.B.C", "test2")
|
||||
awsutil.SetValueAtPath(&s, "B.D.C", "test3")
|
||||
if e, a := "test1", s.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
if e, a := "test2", s.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
if e, a := "test3", s.B.D.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
awsutil.SetValueAtPath(&s, "B.*.C", "test0")
|
||||
if e, a := "test0", s.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
if e, a := "test0", s.B.D.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
var s2 Struct
|
||||
awsutil.SetValueAtPath(&s2, "b.b.c", "test0")
|
||||
if e, a := "test0", s2.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
awsutil.SetValueAtPath(&s2, "A", []Struct{{}})
|
||||
if e, a := []Struct{{}}, s2.A; !awsutil.DeepEqual(e, a) {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
str := "foo"
|
||||
|
||||
s3 := Struct{}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", str)
|
||||
if e, a := "foo", s3.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s3 = Struct{B: &Struct{B: &Struct{C: str}}}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", nil)
|
||||
if e, a := "", s3.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s3 = Struct{}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", nil)
|
||||
if e, a := "", s3.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s3 = Struct{}
|
||||
awsutil.SetValueAtPath(&s3, "b.b.c", &str)
|
||||
if e, a := "foo", s3.B.B.C; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
var s4 struct{ Name *string }
|
||||
awsutil.SetValueAtPath(&s4, "Name", str)
|
||||
if e, a := str, *s4.Name; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s4 = struct{ Name *string }{}
|
||||
awsutil.SetValueAtPath(&s4, "Name", nil)
|
||||
if e, a := (*string)(nil), s4.Name; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s4 = struct{ Name *string }{Name: &str}
|
||||
awsutil.SetValueAtPath(&s4, "Name", nil)
|
||||
if e, a := (*string)(nil), s4.Name; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
|
||||
s4 = struct{ Name *string }{}
|
||||
awsutil.SetValueAtPath(&s4, "Name", &str)
|
||||
if e, a := str, *s4.Name; e != a {
|
||||
t.Errorf("expected %v, but received %v", e, a)
|
||||
}
|
||||
}
|
||||
113
vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go
generated
vendored
Normal file
113
vendor/github.com/aws/aws-sdk-go/aws/awsutil/prettify.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
package awsutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Prettify returns the string representation of a value.
|
||||
func Prettify(i interface{}) string {
|
||||
var buf bytes.Buffer
|
||||
prettify(reflect.ValueOf(i), 0, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// prettify will recursively walk value v to build a textual
|
||||
// representation of the value.
|
||||
func prettify(v reflect.Value, indent int, buf *bytes.Buffer) {
|
||||
for v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
strtype := v.Type().String()
|
||||
if strtype == "time.Time" {
|
||||
fmt.Fprintf(buf, "%s", v.Interface())
|
||||
break
|
||||
} else if strings.HasPrefix(strtype, "io.") {
|
||||
buf.WriteString("<buffer>")
|
||||
break
|
||||
}
|
||||
|
||||
buf.WriteString("{\n")
|
||||
|
||||
names := []string{}
|
||||
for i := 0; i < v.Type().NumField(); i++ {
|
||||
name := v.Type().Field(i).Name
|
||||
f := v.Field(i)
|
||||
if name[0:1] == strings.ToLower(name[0:1]) {
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() {
|
||||
continue // ignore unset fields
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
for i, n := range names {
|
||||
val := v.FieldByName(n)
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString(n + ": ")
|
||||
prettify(val, indent+2, buf)
|
||||
|
||||
if i < len(names)-1 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||
case reflect.Slice:
|
||||
strtype := v.Type().String()
|
||||
if strtype == "[]uint8" {
|
||||
fmt.Fprintf(buf, "<binary> len %d", v.Len())
|
||||
break
|
||||
}
|
||||
|
||||
nl, id, id2 := "", "", ""
|
||||
if v.Len() > 3 {
|
||||
nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
|
||||
}
|
||||
buf.WriteString("[" + nl)
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
buf.WriteString(id2)
|
||||
prettify(v.Index(i), indent+2, buf)
|
||||
|
||||
if i < v.Len()-1 {
|
||||
buf.WriteString("," + nl)
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(nl + id + "]")
|
||||
case reflect.Map:
|
||||
buf.WriteString("{\n")
|
||||
|
||||
for i, k := range v.MapKeys() {
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString(k.String() + ": ")
|
||||
prettify(v.MapIndex(k), indent+2, buf)
|
||||
|
||||
if i < v.Len()-1 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||
default:
|
||||
if !v.IsValid() {
|
||||
fmt.Fprint(buf, "<invalid value>")
|
||||
return
|
||||
}
|
||||
format := "%v"
|
||||
switch v.Interface().(type) {
|
||||
case string:
|
||||
format = "%q"
|
||||
case io.ReadSeeker, io.Reader:
|
||||
format = "buffer(%p)"
|
||||
}
|
||||
fmt.Fprintf(buf, format, v.Interface())
|
||||
}
|
||||
}
|
||||
89
vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go
generated
vendored
Normal file
89
vendor/github.com/aws/aws-sdk-go/aws/awsutil/string_value.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package awsutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// StringValue returns the string representation of a value.
|
||||
func StringValue(i interface{}) string {
|
||||
var buf bytes.Buffer
|
||||
stringValue(reflect.ValueOf(i), 0, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) {
|
||||
for v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
buf.WriteString("{\n")
|
||||
|
||||
names := []string{}
|
||||
for i := 0; i < v.Type().NumField(); i++ {
|
||||
name := v.Type().Field(i).Name
|
||||
f := v.Field(i)
|
||||
if name[0:1] == strings.ToLower(name[0:1]) {
|
||||
continue // ignore unexported fields
|
||||
}
|
||||
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() {
|
||||
continue // ignore unset fields
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
for i, n := range names {
|
||||
val := v.FieldByName(n)
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString(n + ": ")
|
||||
stringValue(val, indent+2, buf)
|
||||
|
||||
if i < len(names)-1 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||
case reflect.Slice:
|
||||
nl, id, id2 := "", "", ""
|
||||
if v.Len() > 3 {
|
||||
nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
|
||||
}
|
||||
buf.WriteString("[" + nl)
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
buf.WriteString(id2)
|
||||
stringValue(v.Index(i), indent+2, buf)
|
||||
|
||||
if i < v.Len()-1 {
|
||||
buf.WriteString("," + nl)
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(nl + id + "]")
|
||||
case reflect.Map:
|
||||
buf.WriteString("{\n")
|
||||
|
||||
for i, k := range v.MapKeys() {
|
||||
buf.WriteString(strings.Repeat(" ", indent+2))
|
||||
buf.WriteString(k.String() + ": ")
|
||||
stringValue(v.MapIndex(k), indent+2, buf)
|
||||
|
||||
if i < v.Len()-1 {
|
||||
buf.WriteString(",\n")
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
|
||||
default:
|
||||
format := "%v"
|
||||
switch v.Interface().(type) {
|
||||
case string:
|
||||
format = "%q"
|
||||
}
|
||||
fmt.Fprintf(buf, format, v.Interface())
|
||||
}
|
||||
}
|
||||
96
vendor/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
Normal file
96
vendor/github.com/aws/aws-sdk-go/aws/client/client.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// A Config provides configuration to a service client instance.
|
||||
type Config struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
Endpoint string
|
||||
SigningRegion string
|
||||
SigningName string
|
||||
|
||||
// States that the signing name did not come from a modeled source but
|
||||
// was derived based on other data. Used by service client constructors
|
||||
// to determine if the signin name can be overriden based on metadata the
|
||||
// service has.
|
||||
SigningNameDerived bool
|
||||
}
|
||||
|
||||
// ConfigProvider provides a generic way for a service client to receive
|
||||
// the ClientConfig without circular dependencies.
|
||||
type ConfigProvider interface {
|
||||
ClientConfig(serviceName string, cfgs ...*aws.Config) Config
|
||||
}
|
||||
|
||||
// ConfigNoResolveEndpointProvider same as ConfigProvider except it will not
|
||||
// resolve the endpoint automatically. The service client's endpoint must be
|
||||
// provided via the aws.Config.Endpoint field.
|
||||
type ConfigNoResolveEndpointProvider interface {
|
||||
ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) Config
|
||||
}
|
||||
|
||||
// A Client implements the base client request and response handling
|
||||
// used by all service clients.
|
||||
type Client struct {
|
||||
request.Retryer
|
||||
metadata.ClientInfo
|
||||
|
||||
Config aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// New will return a pointer to a new initialized service client.
|
||||
func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, options ...func(*Client)) *Client {
|
||||
svc := &Client{
|
||||
Config: cfg,
|
||||
ClientInfo: info,
|
||||
Handlers: handlers.Copy(),
|
||||
}
|
||||
|
||||
switch retryer, ok := cfg.Retryer.(request.Retryer); {
|
||||
case ok:
|
||||
svc.Retryer = retryer
|
||||
case cfg.Retryer != nil && cfg.Logger != nil:
|
||||
s := fmt.Sprintf("WARNING: %T does not implement request.Retryer; using DefaultRetryer instead", cfg.Retryer)
|
||||
cfg.Logger.Log(s)
|
||||
fallthrough
|
||||
default:
|
||||
maxRetries := aws.IntValue(cfg.MaxRetries)
|
||||
if cfg.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries {
|
||||
maxRetries = 3
|
||||
}
|
||||
svc.Retryer = DefaultRetryer{NumMaxRetries: maxRetries}
|
||||
}
|
||||
|
||||
svc.AddDebugHandlers()
|
||||
|
||||
for _, option := range options {
|
||||
option(svc)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
// NewRequest returns a new Request pointer for the service API
|
||||
// operation and parameters.
|
||||
func (c *Client) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
|
||||
return request.New(c.Config, c.ClientInfo, c.Handlers, c.Retryer, operation, params, data)
|
||||
}
|
||||
|
||||
// AddDebugHandlers injects debug logging handlers into the service to log request
|
||||
// debug information.
|
||||
func (c *Client) AddDebugHandlers() {
|
||||
if !c.Config.LogLevel.AtLeast(aws.LogDebug) {
|
||||
return
|
||||
}
|
||||
|
||||
c.Handlers.Send.PushFrontNamed(LogHTTPRequestHandler)
|
||||
c.Handlers.Send.PushBackNamed(LogHTTPResponseHandler)
|
||||
}
|
||||
78
vendor/github.com/aws/aws-sdk-go/aws/client/client_test.go
generated
vendored
Normal file
78
vendor/github.com/aws/aws-sdk-go/aws/client/client_test.go
generated
vendored
Normal 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")
|
||||
}
|
||||
|
||||
}
|
||||
116
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go
generated
vendored
Normal file
116
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/sdkrand"
|
||||
)
|
||||
|
||||
// DefaultRetryer implements basic retry logic using exponential backoff for
|
||||
// most services. If you want to implement custom retry logic, implement the
|
||||
// request.Retryer interface or create a structure type that composes this
|
||||
// struct and override the specific methods. For example, to override only
|
||||
// the MaxRetries method:
|
||||
//
|
||||
// type retryer struct {
|
||||
// client.DefaultRetryer
|
||||
// }
|
||||
//
|
||||
// // This implementation always has 100 max retries
|
||||
// func (d retryer) MaxRetries() int { return 100 }
|
||||
type DefaultRetryer struct {
|
||||
NumMaxRetries int
|
||||
}
|
||||
|
||||
// MaxRetries returns the number of maximum returns the service will use to make
|
||||
// an individual API request.
|
||||
func (d DefaultRetryer) MaxRetries() int {
|
||||
return d.NumMaxRetries
|
||||
}
|
||||
|
||||
// RetryRules returns the delay duration before retrying this request again
|
||||
func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
|
||||
// Set the upper limit of delay in retrying at ~five minutes
|
||||
minTime := 30
|
||||
throttle := d.shouldThrottle(r)
|
||||
if throttle {
|
||||
if delay, ok := getRetryDelay(r); ok {
|
||||
return delay
|
||||
}
|
||||
|
||||
minTime = 500
|
||||
}
|
||||
|
||||
retryCount := r.RetryCount
|
||||
if throttle && retryCount > 8 {
|
||||
retryCount = 8
|
||||
} else if retryCount > 13 {
|
||||
retryCount = 13
|
||||
}
|
||||
|
||||
delay := (1 << uint(retryCount)) * (sdkrand.SeededRand.Intn(minTime) + minTime)
|
||||
return time.Duration(delay) * time.Millisecond
|
||||
}
|
||||
|
||||
// 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 && r.HTTPResponse.StatusCode != 501 {
|
||||
return true
|
||||
}
|
||||
return r.IsErrorRetryable() || d.shouldThrottle(r)
|
||||
}
|
||||
|
||||
// ShouldThrottle returns true if the request should be throttled.
|
||||
func (d DefaultRetryer) shouldThrottle(r *request.Request) bool {
|
||||
switch r.HTTPResponse.StatusCode {
|
||||
case 429:
|
||||
case 502:
|
||||
case 503:
|
||||
case 504:
|
||||
default:
|
||||
return r.IsErrorThrottle()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// This will look in the Retry-After header, RFC 7231, for how long
|
||||
// it will wait before attempting another request
|
||||
func getRetryDelay(r *request.Request) (time.Duration, bool) {
|
||||
if !canUseRetryAfterHeader(r) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
delayStr := r.HTTPResponse.Header.Get("Retry-After")
|
||||
if len(delayStr) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
delay, err := strconv.Atoi(delayStr)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return time.Duration(delay) * time.Second, true
|
||||
}
|
||||
|
||||
// Will look at the status code to see if the retry header pertains to
|
||||
// the status code.
|
||||
func canUseRetryAfterHeader(r *request.Request) bool {
|
||||
switch r.HTTPResponse.StatusCode {
|
||||
case 429:
|
||||
case 503:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
189
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer_test.go
generated
vendored
Normal file
189
vendor/github.com/aws/aws-sdk-go/aws/client/default_retryer_test.go
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
func TestRetryThrottleStatusCodes(t *testing.T) {
|
||||
cases := []struct {
|
||||
expectThrottle bool
|
||||
expectRetry bool
|
||||
r request.Request
|
||||
}{
|
||||
{
|
||||
false,
|
||||
false,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 200},
|
||||
},
|
||||
},
|
||||
{
|
||||
true,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 429},
|
||||
},
|
||||
},
|
||||
{
|
||||
true,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 502},
|
||||
},
|
||||
},
|
||||
{
|
||||
true,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503},
|
||||
},
|
||||
},
|
||||
{
|
||||
true,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 504},
|
||||
},
|
||||
},
|
||||
{
|
||||
false,
|
||||
true,
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 500},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
d := DefaultRetryer{NumMaxRetries: 10}
|
||||
for i, c := range cases {
|
||||
throttle := d.shouldThrottle(&c.r)
|
||||
retry := d.ShouldRetry(&c.r)
|
||||
|
||||
if e, a := c.expectThrottle, throttle; e != a {
|
||||
t.Errorf("%d: expected %v, but received %v", i, e, a)
|
||||
}
|
||||
|
||||
if e, a := c.expectRetry, retry; e != a {
|
||||
t.Errorf("%d: expected %v, but received %v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanUseRetryAfter(t *testing.T) {
|
||||
cases := []struct {
|
||||
r request.Request
|
||||
e bool
|
||||
}{
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 200},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 500},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 429},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
a := canUseRetryAfterHeader(&c.r)
|
||||
if c.e != a {
|
||||
t.Errorf("%d: expected %v, but received %v", i, c.e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRetryDelay(t *testing.T) {
|
||||
cases := []struct {
|
||||
r request.Request
|
||||
e time.Duration
|
||||
equal bool
|
||||
ok bool
|
||||
}{
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 429, Header: http.Header{"Retry-After": []string{"3600"}}},
|
||||
},
|
||||
3600 * time.Second,
|
||||
true,
|
||||
true,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{"120"}}},
|
||||
},
|
||||
120 * time.Second,
|
||||
true,
|
||||
true,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{"120"}}},
|
||||
},
|
||||
1 * time.Second,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
request.Request{
|
||||
HTTPResponse: &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{""}}},
|
||||
},
|
||||
0 * time.Second,
|
||||
true,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
a, ok := getRetryDelay(&c.r)
|
||||
if c.ok != ok {
|
||||
t.Errorf("%d: expected %v, but received %v", i, c.ok, ok)
|
||||
}
|
||||
|
||||
if (c.e != a) == c.equal {
|
||||
t.Errorf("%d: expected %v, but received %v", i, c.e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetryDelay(t *testing.T) {
|
||||
r := request.Request{}
|
||||
for i := 0; i < 100; i++ {
|
||||
rTemp := r
|
||||
rTemp.HTTPResponse = &http.Response{StatusCode: 500, Header: http.Header{"Retry-After": []string{""}}}
|
||||
rTemp.RetryCount = i
|
||||
a, _ := getRetryDelay(&rTemp)
|
||||
if a > 5*time.Minute {
|
||||
t.Errorf("retry delay should never be greater than five minutes, received %d", a)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
rTemp := r
|
||||
rTemp.RetryCount = i
|
||||
rTemp.HTTPResponse = &http.Response{StatusCode: 503, Header: http.Header{"Retry-After": []string{""}}}
|
||||
a, _ := getRetryDelay(&rTemp)
|
||||
if a > 5*time.Minute {
|
||||
t.Errorf("retry delay should never be greater than five minutes, received %d", a)
|
||||
}
|
||||
}
|
||||
}
|
||||
184
vendor/github.com/aws/aws-sdk-go/aws/client/logger.go
generated
vendored
Normal file
184
vendor/github.com/aws/aws-sdk-go/aws/client/logger.go
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
const logReqMsg = `DEBUG: Request %s/%s Details:
|
||||
---[ REQUEST POST-SIGN ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
const logReqErrMsg = `DEBUG ERROR: Request %s/%s:
|
||||
---[ REQUEST DUMP ERROR ]-----------------------------
|
||||
%s
|
||||
------------------------------------------------------`
|
||||
|
||||
type logWriter struct {
|
||||
// Logger is what we will use to log the payload of a response.
|
||||
Logger aws.Logger
|
||||
// buf stores the contents of what has been read
|
||||
buf *bytes.Buffer
|
||||
}
|
||||
|
||||
func (logger *logWriter) Write(b []byte) (int, error) {
|
||||
return logger.buf.Write(b)
|
||||
}
|
||||
|
||||
type teeReaderCloser struct {
|
||||
// io.Reader will be a tee reader that is used during logging.
|
||||
// This structure will read from a body and write the contents to a logger.
|
||||
io.Reader
|
||||
// Source is used just to close when we are done reading.
|
||||
Source io.ReadCloser
|
||||
}
|
||||
|
||||
func (reader *teeReaderCloser) Close() error {
|
||||
return reader.Source.Close()
|
||||
}
|
||||
|
||||
// LogHTTPRequestHandler is a SDK request handler to log the HTTP request sent
|
||||
// to a service. Will include the HTTP request body if the LogLevel of the
|
||||
// request matches LogDebugWithHTTPBody.
|
||||
var LogHTTPRequestHandler = request.NamedHandler{
|
||||
Name: "awssdk.client.LogRequest",
|
||||
Fn: logRequest,
|
||||
}
|
||||
|
||||
func logRequest(r *request.Request) {
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
bodySeekable := aws.IsReaderSeekable(r.Body)
|
||||
|
||||
b, err := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
if logBody {
|
||||
if !bodySeekable {
|
||||
r.SetReaderBody(aws.ReadSeekCloser(r.HTTPRequest.Body))
|
||||
}
|
||||
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
|
||||
// Body as a NoOpCloser and will not be reset after read by the HTTP
|
||||
// client reader.
|
||||
r.ResetBody()
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, string(b)))
|
||||
}
|
||||
|
||||
// LogHTTPRequestHeaderHandler is a SDK request handler to log the HTTP request sent
|
||||
// to a service. Will only log the HTTP request's headers. The request payload
|
||||
// will not be read.
|
||||
var LogHTTPRequestHeaderHandler = request.NamedHandler{
|
||||
Name: "awssdk.client.LogRequestHeader",
|
||||
Fn: logRequestHeader,
|
||||
}
|
||||
|
||||
func logRequestHeader(r *request.Request) {
|
||||
b, err := httputil.DumpRequestOut(r.HTTPRequest, false)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logReqMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, string(b)))
|
||||
}
|
||||
|
||||
const logRespMsg = `DEBUG: Response %s/%s Details:
|
||||
---[ RESPONSE ]--------------------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
const logRespErrMsg = `DEBUG ERROR: Response %s/%s:
|
||||
---[ RESPONSE DUMP ERROR ]-----------------------------
|
||||
%s
|
||||
-----------------------------------------------------`
|
||||
|
||||
// LogHTTPResponseHandler is a SDK request handler to log the HTTP response
|
||||
// received from a service. Will include the HTTP response body if the LogLevel
|
||||
// of the request matches LogDebugWithHTTPBody.
|
||||
var LogHTTPResponseHandler = request.NamedHandler{
|
||||
Name: "awssdk.client.LogResponse",
|
||||
Fn: logResponse,
|
||||
}
|
||||
|
||||
func logResponse(r *request.Request) {
|
||||
lw := &logWriter{r.Config.Logger, bytes.NewBuffer(nil)}
|
||||
|
||||
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||
if logBody {
|
||||
r.HTTPResponse.Body = &teeReaderCloser{
|
||||
Reader: io.TeeReader(r.HTTPResponse.Body, lw),
|
||||
Source: r.HTTPResponse.Body,
|
||||
}
|
||||
}
|
||||
|
||||
handlerFn := func(req *request.Request) {
|
||||
b, err := httputil.DumpResponse(req.HTTPResponse, false)
|
||||
if err != nil {
|
||||
lw.Logger.Log(fmt.Sprintf(logRespErrMsg,
|
||||
req.ClientInfo.ServiceName, req.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
lw.Logger.Log(fmt.Sprintf(logRespMsg,
|
||||
req.ClientInfo.ServiceName, req.Operation.Name, string(b)))
|
||||
|
||||
if logBody {
|
||||
b, err := ioutil.ReadAll(lw.buf)
|
||||
if err != nil {
|
||||
lw.Logger.Log(fmt.Sprintf(logRespErrMsg,
|
||||
req.ClientInfo.ServiceName, req.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
lw.Logger.Log(string(b))
|
||||
}
|
||||
}
|
||||
|
||||
const handlerName = "awsdk.client.LogResponse.ResponseBody"
|
||||
|
||||
r.Handlers.Unmarshal.SetBackNamed(request.NamedHandler{
|
||||
Name: handlerName, Fn: handlerFn,
|
||||
})
|
||||
r.Handlers.UnmarshalError.SetBackNamed(request.NamedHandler{
|
||||
Name: handlerName, Fn: handlerFn,
|
||||
})
|
||||
}
|
||||
|
||||
// LogHTTPResponseHeaderHandler is a SDK request handler to log the HTTP
|
||||
// response received from a service. Will only log the HTTP response's headers.
|
||||
// The response payload will not be read.
|
||||
var LogHTTPResponseHeaderHandler = request.NamedHandler{
|
||||
Name: "awssdk.client.LogResponseHeader",
|
||||
Fn: logResponseHeader,
|
||||
}
|
||||
|
||||
func logResponseHeader(r *request.Request) {
|
||||
if r.Config.Logger == nil {
|
||||
return
|
||||
}
|
||||
|
||||
b, err := httputil.DumpResponse(r.HTTPResponse, false)
|
||||
if err != nil {
|
||||
r.Config.Logger.Log(fmt.Sprintf(logRespErrMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||
return
|
||||
}
|
||||
|
||||
r.Config.Logger.Log(fmt.Sprintf(logRespMsg,
|
||||
r.ClientInfo.ServiceName, r.Operation.Name, string(b)))
|
||||
}
|
||||
222
vendor/github.com/aws/aws-sdk-go/aws/client/logger_test.go
generated
vendored
Normal file
222
vendor/github.com/aws/aws-sdk-go/aws/client/logger_test.go
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"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"
|
||||
)
|
||||
|
||||
type mockCloser struct {
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (closer *mockCloser) Read(b []byte) (int, error) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
func (closer *mockCloser) Close() error {
|
||||
closer.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestTeeReaderCloser(t *testing.T) {
|
||||
expected := "FOO"
|
||||
buf := bytes.NewBuffer([]byte(expected))
|
||||
lw := bytes.NewBuffer(nil)
|
||||
c := &mockCloser{}
|
||||
closer := teeReaderCloser{
|
||||
io.TeeReader(buf, lw),
|
||||
c,
|
||||
}
|
||||
|
||||
b := make([]byte, len(expected))
|
||||
_, err := closer.Read(b)
|
||||
closer.Close()
|
||||
|
||||
if expected != lw.String() {
|
||||
t.Errorf("Expected %q, but received %q", expected, lw.String())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Expected 'nil', but received %v", err)
|
||||
}
|
||||
|
||||
if !c.closed {
|
||||
t.Error("Expected 'true', but received 'false'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogWriter(t *testing.T) {
|
||||
expected := "FOO"
|
||||
lw := &logWriter{nil, bytes.NewBuffer(nil)}
|
||||
lw.Write([]byte(expected))
|
||||
|
||||
if expected != lw.buf.String() {
|
||||
t.Errorf("Expected %q, but received %q", expected, lw.buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogRequest(t *testing.T) {
|
||||
cases := []struct {
|
||||
Body io.ReadSeeker
|
||||
ExpectBody []byte
|
||||
LogLevel aws.LogLevelType
|
||||
}{
|
||||
{
|
||||
Body: aws.ReadSeekCloser(bytes.NewBuffer([]byte("body content"))),
|
||||
ExpectBody: []byte("body content"),
|
||||
},
|
||||
{
|
||||
Body: aws.ReadSeekCloser(bytes.NewBuffer([]byte("body content"))),
|
||||
LogLevel: aws.LogDebugWithHTTPBody,
|
||||
ExpectBody: []byte("body content"),
|
||||
},
|
||||
{
|
||||
Body: bytes.NewReader([]byte("body content")),
|
||||
ExpectBody: []byte("body content"),
|
||||
},
|
||||
{
|
||||
Body: bytes.NewReader([]byte("body content")),
|
||||
LogLevel: aws.LogDebugWithHTTPBody,
|
||||
ExpectBody: []byte("body content"),
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
logW := bytes.NewBuffer(nil)
|
||||
req := request.New(
|
||||
aws.Config{
|
||||
Credentials: credentials.AnonymousCredentials,
|
||||
Logger: &bufLogger{w: logW},
|
||||
LogLevel: aws.LogLevel(c.LogLevel),
|
||||
},
|
||||
metadata.ClientInfo{
|
||||
Endpoint: "https://mock-service.mock-region.amazonaws.com",
|
||||
},
|
||||
testHandlers(),
|
||||
nil,
|
||||
&request.Operation{
|
||||
Name: "APIName",
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
},
|
||||
struct{}{}, nil,
|
||||
)
|
||||
req.SetReaderBody(c.Body)
|
||||
req.Build()
|
||||
|
||||
logRequest(req)
|
||||
|
||||
b, err := ioutil.ReadAll(req.HTTPRequest.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%d, expect to read SDK request Body", i)
|
||||
}
|
||||
|
||||
if e, a := c.ExpectBody, b; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("%d, expect %v body, got %v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogResponse(t *testing.T) {
|
||||
cases := []struct {
|
||||
Body *bytes.Buffer
|
||||
ExpectBody []byte
|
||||
ReadBody bool
|
||||
LogLevel aws.LogLevelType
|
||||
}{
|
||||
{
|
||||
Body: bytes.NewBuffer([]byte("body content")),
|
||||
ExpectBody: []byte("body content"),
|
||||
},
|
||||
{
|
||||
Body: bytes.NewBuffer([]byte("body content")),
|
||||
LogLevel: aws.LogDebug,
|
||||
ExpectBody: []byte("body content"),
|
||||
},
|
||||
{
|
||||
Body: bytes.NewBuffer([]byte("body content")),
|
||||
LogLevel: aws.LogDebugWithHTTPBody,
|
||||
ReadBody: true,
|
||||
ExpectBody: []byte("body content"),
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
var logW bytes.Buffer
|
||||
req := request.New(
|
||||
aws.Config{
|
||||
Credentials: credentials.AnonymousCredentials,
|
||||
Logger: &bufLogger{w: &logW},
|
||||
LogLevel: aws.LogLevel(c.LogLevel),
|
||||
},
|
||||
metadata.ClientInfo{
|
||||
Endpoint: "https://mock-service.mock-region.amazonaws.com",
|
||||
},
|
||||
testHandlers(),
|
||||
nil,
|
||||
&request.Operation{
|
||||
Name: "APIName",
|
||||
HTTPMethod: "POST",
|
||||
HTTPPath: "/",
|
||||
},
|
||||
struct{}{}, nil,
|
||||
)
|
||||
req.HTTPResponse = &http.Response{
|
||||
StatusCode: 200,
|
||||
Status: "OK",
|
||||
Header: http.Header{
|
||||
"ABC": []string{"123"},
|
||||
},
|
||||
Body: ioutil.NopCloser(c.Body),
|
||||
}
|
||||
|
||||
logResponse(req)
|
||||
req.Handlers.Unmarshal.Run(req)
|
||||
|
||||
if c.ReadBody {
|
||||
if e, a := len(c.ExpectBody), c.Body.Len(); e != a {
|
||||
t.Errorf("%d, expect orginal body not to of been read", i)
|
||||
}
|
||||
}
|
||||
|
||||
if logW.Len() == 0 {
|
||||
t.Errorf("%d, expect HTTP Response headers to be logged", i)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(req.HTTPResponse.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%d, expect to read SDK request Body", i)
|
||||
}
|
||||
|
||||
if e, a := c.ExpectBody, b; !bytes.Equal(e, a) {
|
||||
t.Errorf("%d, expect %v body, got %v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type bufLogger struct {
|
||||
w *bytes.Buffer
|
||||
}
|
||||
|
||||
func (l *bufLogger) Log(args ...interface{}) {
|
||||
fmt.Fprintln(l.w, args...)
|
||||
}
|
||||
|
||||
func testHandlers() request.Handlers {
|
||||
var handlers request.Handlers
|
||||
|
||||
handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler)
|
||||
|
||||
return handlers
|
||||
}
|
||||
13
vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
13
vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package metadata
|
||||
|
||||
// ClientInfo wraps immutable data from the client.Client structure.
|
||||
type ClientInfo struct {
|
||||
ServiceName string
|
||||
ServiceID string
|
||||
APIVersion string
|
||||
Endpoint string
|
||||
SigningName string
|
||||
SigningRegion string
|
||||
JSONVersion string
|
||||
TargetPrefix string
|
||||
}
|
||||
492
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
Normal file
492
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
Normal file
@@ -0,0 +1,492 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||
)
|
||||
|
||||
// UseServiceDefaultRetries instructs the config to use the service's own
|
||||
// default number of retries. This will be the default action if
|
||||
// Config.MaxRetries is nil also.
|
||||
const UseServiceDefaultRetries = -1
|
||||
|
||||
// RequestRetryer is an alias for a type that implements the request.Retryer
|
||||
// interface.
|
||||
type RequestRetryer interface{}
|
||||
|
||||
// A Config provides service configuration for service clients. By default,
|
||||
// all clients will use the defaults.DefaultConfig tructure.
|
||||
//
|
||||
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess := session.Must(session.NewSession(&aws.Config{
|
||||
// MaxRetries: aws.Int(3),
|
||||
// }))
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
// Region: aws.String("us-west-2"),
|
||||
// })
|
||||
type Config struct {
|
||||
// Enables verbose error printing of all credential chain errors.
|
||||
// Should be used when wanting to see all errors while attempting to
|
||||
// retrieve credentials.
|
||||
CredentialsChainVerboseErrors *bool
|
||||
|
||||
// The credentials object to use when signing requests. Defaults to a
|
||||
// chain of credential providers to search for credentials in environment
|
||||
// variables, shared credential file, and EC2 Instance Roles.
|
||||
Credentials *credentials.Credentials
|
||||
|
||||
// An optional endpoint URL (hostname only or fully qualified URI)
|
||||
// that overrides the default generated endpoint for a client. Set this
|
||||
// to `""` to use the default generated endpoint.
|
||||
//
|
||||
// @note You must still provide a `Region` value when specifying an
|
||||
// endpoint for a client.
|
||||
Endpoint *string
|
||||
|
||||
// The resolver to use for looking up endpoints for AWS service clients
|
||||
// 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"
|
||||
// document.
|
||||
//
|
||||
// @see http://docs.aws.amazon.com/general/latest/gr/rande.html
|
||||
// AWS Regions and Endpoints
|
||||
Region *string
|
||||
|
||||
// Set this to `true` to disable SSL when sending requests. Defaults
|
||||
// to `false`.
|
||||
DisableSSL *bool
|
||||
|
||||
// The HTTP client to use when sending requests. Defaults to
|
||||
// `http.DefaultClient`.
|
||||
HTTPClient *http.Client
|
||||
|
||||
// An integer value representing the logging level. The default log level
|
||||
// is zero (LogOff), which represents no logging. To enable logging set
|
||||
// to a LogLevel Value.
|
||||
LogLevel *LogLevelType
|
||||
|
||||
// The logger writer interface to write logging messages to. Defaults to
|
||||
// standard out.
|
||||
Logger Logger
|
||||
|
||||
// The maximum number of times that a request will be retried for failures.
|
||||
// Defaults to -1, which defers the max retry setting to the service
|
||||
// specific configuration.
|
||||
MaxRetries *int
|
||||
|
||||
// Retryer guides how HTTP requests should be retried in case of
|
||||
// recoverable failures.
|
||||
//
|
||||
// When nil or the value does not implement the request.Retryer interface,
|
||||
// the client.DefaultRetryer will be used.
|
||||
//
|
||||
// When both Retryer and MaxRetries are non-nil, the former is used and
|
||||
// the latter ignored.
|
||||
//
|
||||
// To set the Retryer field in a type-safe manner and with chaining, use
|
||||
// the request.WithRetryer helper function:
|
||||
//
|
||||
// cfg := request.WithRetryer(aws.NewConfig(), myRetryer)
|
||||
//
|
||||
Retryer RequestRetryer
|
||||
|
||||
// Disables semantic parameter validation, which validates input for
|
||||
// missing required fields and/or other semantic request input errors.
|
||||
DisableParamValidation *bool
|
||||
|
||||
// Disables the computation of request and response checksums, e.g.,
|
||||
// CRC32 checksums in Amazon DynamoDB.
|
||||
DisableComputeChecksums *bool
|
||||
|
||||
// Set this to `true` to force the request to use path-style addressing,
|
||||
// i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client
|
||||
// will use virtual hosted bucket addressing when possible
|
||||
// (`http://BUCKET.s3.amazonaws.com/KEY`).
|
||||
//
|
||||
// @note This configuration option is specific to the Amazon S3 service.
|
||||
// @see http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html
|
||||
// Amazon S3: Virtual Hosting of Buckets
|
||||
S3ForcePathStyle *bool
|
||||
|
||||
// Set this to `true` to disable the SDK adding the `Expect: 100-Continue`
|
||||
// header to PUT requests over 2MB of content. 100-Continue instructs the
|
||||
// HTTP client not to send the body until the service responds with a
|
||||
// `continue` status. This is useful to prevent sending the request body
|
||||
// until after the request is authenticated, and validated.
|
||||
//
|
||||
// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html
|
||||
//
|
||||
// 100-Continue is only enabled for Go 1.6 and above. See `http.Transport`'s
|
||||
// `ExpectContinueTimeout` for information on adjusting the continue wait
|
||||
// timeout. https://golang.org/pkg/net/http/#Transport
|
||||
//
|
||||
// You should use this flag to disble 100-Continue if you experience issues
|
||||
// with proxies or third party S3 compatible services.
|
||||
S3Disable100Continue *bool
|
||||
|
||||
// Set this to `true` to enable S3 Accelerate feature. For all operations
|
||||
// compatible with S3 Accelerate will use the accelerate endpoint for
|
||||
// requests. Requests not compatible will fall back to normal S3 requests.
|
||||
//
|
||||
// The bucket must be enable for accelerate to be used with S3 client with
|
||||
// accelerate enabled. If the bucket is not enabled for accelerate an error
|
||||
// will be returned. The bucket name must be DNS compatible to also work
|
||||
// with accelerate.
|
||||
S3UseAccelerate *bool
|
||||
|
||||
// S3DisableContentMD5Validation config option is temporarily disabled,
|
||||
// For S3 GetObject API calls, #1837.
|
||||
//
|
||||
// Set this to `true` to disable the S3 service client from automatically
|
||||
// adding the ContentMD5 to S3 Object Put and Upload API calls. This option
|
||||
// will also disable the SDK from performing object ContentMD5 validation
|
||||
// on GetObject API calls.
|
||||
S3DisableContentMD5Validation *bool
|
||||
|
||||
// Set this to `true` to disable the EC2Metadata client from overriding the
|
||||
// default http.Client's Timeout. This is helpful if you do not want the
|
||||
// EC2Metadata client to create a new http.Client. This options is only
|
||||
// meaningful if you're not already using a custom HTTP client with the
|
||||
// SDK. Enabled by default.
|
||||
//
|
||||
// Must be set and provided to the session.NewSession() in order to disable
|
||||
// the EC2Metadata overriding the timeout for default credentials chain.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.Must(session.NewSession(aws.NewConfig()
|
||||
// .WithEC2MetadataDiableTimeoutOverride(true)))
|
||||
//
|
||||
// svc := s3.New(sess)
|
||||
//
|
||||
EC2MetadataDisableTimeoutOverride *bool
|
||||
|
||||
// Instructs the endpoint to be generated for a service client to
|
||||
// be the dual stack endpoint. The dual stack endpoint will support
|
||||
// both IPv4 and IPv6 addressing.
|
||||
//
|
||||
// Setting this for a service which does not support dual stack will fail
|
||||
// to make requets. It is not recommended to set this value on the session
|
||||
// as it will apply to all service clients created with the session. Even
|
||||
// services which don't support dual stack endpoints.
|
||||
//
|
||||
// If the Endpoint config value is also provided the UseDualStack flag
|
||||
// will be ignored.
|
||||
//
|
||||
// Only supported with.
|
||||
//
|
||||
// sess := session.Must(session.NewSession())
|
||||
//
|
||||
// svc := s3.New(sess, &aws.Config{
|
||||
// UseDualStack: aws.Bool(true),
|
||||
// })
|
||||
UseDualStack *bool
|
||||
|
||||
// SleepDelay is an override for the func the SDK will call when sleeping
|
||||
// during the lifecycle of a request. Specifically this will be used for
|
||||
// request delays. This value should only be used for testing. To adjust
|
||||
// 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.
|
||||
// Will default to false. This would only be used for empty directory names in s3 requests.
|
||||
//
|
||||
// Example:
|
||||
// sess := session.Must(session.NewSession(&aws.Config{
|
||||
// DisableRestProtocolURICleaning: aws.Bool(true),
|
||||
// }))
|
||||
//
|
||||
// svc := s3.New(sess)
|
||||
// out, err := svc.GetObject(&s3.GetObjectInput {
|
||||
// Bucket: aws.String("bucketname"),
|
||||
// Key: aws.String("//foo//bar//moo"),
|
||||
// })
|
||||
DisableRestProtocolURICleaning *bool
|
||||
}
|
||||
|
||||
// NewConfig returns a new Config pointer that can be chained with builder
|
||||
// methods to set multiple configuration values inline without using pointers.
|
||||
//
|
||||
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||
// // service clients.
|
||||
// sess := session.Must(session.NewSession(aws.NewConfig().
|
||||
// WithMaxRetries(3),
|
||||
// ))
|
||||
//
|
||||
// // Create S3 service client with a specific Region.
|
||||
// svc := s3.New(sess, aws.NewConfig().
|
||||
// WithRegion("us-west-2"),
|
||||
// )
|
||||
func NewConfig() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
|
||||
// WithCredentialsChainVerboseErrors sets a config verbose errors boolean and returning
|
||||
// a Config pointer.
|
||||
func (c *Config) WithCredentialsChainVerboseErrors(verboseErrs bool) *Config {
|
||||
c.CredentialsChainVerboseErrors = &verboseErrs
|
||||
return c
|
||||
}
|
||||
|
||||
// WithCredentials sets a config Credentials value returning a Config pointer
|
||||
// for chaining.
|
||||
func (c *Config) WithCredentials(creds *credentials.Credentials) *Config {
|
||||
c.Credentials = creds
|
||||
return c
|
||||
}
|
||||
|
||||
// WithEndpoint sets a config Endpoint value returning a Config pointer for
|
||||
// chaining.
|
||||
func (c *Config) WithEndpoint(endpoint string) *Config {
|
||||
c.Endpoint = &endpoint
|
||||
return c
|
||||
}
|
||||
|
||||
// WithEndpointResolver sets a config EndpointResolver value returning a
|
||||
// Config pointer for chaining.
|
||||
func (c *Config) WithEndpointResolver(resolver endpoints.Resolver) *Config {
|
||||
c.EndpointResolver = resolver
|
||||
return c
|
||||
}
|
||||
|
||||
// WithRegion sets a config Region value returning a Config pointer for
|
||||
// chaining.
|
||||
func (c *Config) WithRegion(region string) *Config {
|
||||
c.Region = ®ion
|
||||
return c
|
||||
}
|
||||
|
||||
// WithDisableSSL sets a config DisableSSL value returning a Config pointer
|
||||
// for chaining.
|
||||
func (c *Config) WithDisableSSL(disable bool) *Config {
|
||||
c.DisableSSL = &disable
|
||||
return c
|
||||
}
|
||||
|
||||
// WithHTTPClient sets a config HTTPClient value returning a Config pointer
|
||||
// for chaining.
|
||||
func (c *Config) WithHTTPClient(client *http.Client) *Config {
|
||||
c.HTTPClient = client
|
||||
return c
|
||||
}
|
||||
|
||||
// WithMaxRetries sets a config MaxRetries value returning a Config pointer
|
||||
// for chaining.
|
||||
func (c *Config) WithMaxRetries(max int) *Config {
|
||||
c.MaxRetries = &max
|
||||
return c
|
||||
}
|
||||
|
||||
// WithDisableParamValidation sets a config DisableParamValidation value
|
||||
// returning a Config pointer for chaining.
|
||||
func (c *Config) WithDisableParamValidation(disable bool) *Config {
|
||||
c.DisableParamValidation = &disable
|
||||
return c
|
||||
}
|
||||
|
||||
// WithDisableComputeChecksums sets a config DisableComputeChecksums value
|
||||
// returning a Config pointer for chaining.
|
||||
func (c *Config) WithDisableComputeChecksums(disable bool) *Config {
|
||||
c.DisableComputeChecksums = &disable
|
||||
return c
|
||||
}
|
||||
|
||||
// WithLogLevel sets a config LogLevel value returning a Config pointer for
|
||||
// chaining.
|
||||
func (c *Config) WithLogLevel(level LogLevelType) *Config {
|
||||
c.LogLevel = &level
|
||||
return c
|
||||
}
|
||||
|
||||
// WithLogger sets a config Logger value returning a Config pointer for
|
||||
// chaining.
|
||||
func (c *Config) WithLogger(logger Logger) *Config {
|
||||
c.Logger = logger
|
||||
return c
|
||||
}
|
||||
|
||||
// WithS3ForcePathStyle sets a config S3ForcePathStyle value returning a Config
|
||||
// pointer for chaining.
|
||||
func (c *Config) WithS3ForcePathStyle(force bool) *Config {
|
||||
c.S3ForcePathStyle = &force
|
||||
return c
|
||||
}
|
||||
|
||||
// WithS3Disable100Continue sets a config S3Disable100Continue value returning
|
||||
// a Config pointer for chaining.
|
||||
func (c *Config) WithS3Disable100Continue(disable bool) *Config {
|
||||
c.S3Disable100Continue = &disable
|
||||
return c
|
||||
}
|
||||
|
||||
// WithS3UseAccelerate sets a config S3UseAccelerate value returning a Config
|
||||
// pointer for chaining.
|
||||
func (c *Config) WithS3UseAccelerate(enable bool) *Config {
|
||||
c.S3UseAccelerate = &enable
|
||||
return c
|
||||
|
||||
}
|
||||
|
||||
// WithS3DisableContentMD5Validation sets a config
|
||||
// S3DisableContentMD5Validation value returning a Config pointer for chaining.
|
||||
func (c *Config) WithS3DisableContentMD5Validation(enable bool) *Config {
|
||||
c.S3DisableContentMD5Validation = &enable
|
||||
return c
|
||||
|
||||
}
|
||||
|
||||
// WithUseDualStack sets a config UseDualStack value returning a Config
|
||||
// pointer for chaining.
|
||||
func (c *Config) WithUseDualStack(enable bool) *Config {
|
||||
c.UseDualStack = &enable
|
||||
return c
|
||||
}
|
||||
|
||||
// WithEC2MetadataDisableTimeoutOverride sets a config EC2MetadataDisableTimeoutOverride value
|
||||
// returning a Config pointer for chaining.
|
||||
func (c *Config) WithEC2MetadataDisableTimeoutOverride(enable bool) *Config {
|
||||
c.EC2MetadataDisableTimeoutOverride = &enable
|
||||
return c
|
||||
}
|
||||
|
||||
// WithSleepDelay overrides the function used to sleep while waiting for the
|
||||
// next retry. Defaults to time.Sleep.
|
||||
func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config {
|
||||
c.SleepDelay = fn
|
||||
return c
|
||||
}
|
||||
|
||||
// MergeIn merges the passed in configs into the existing config object.
|
||||
func (c *Config) MergeIn(cfgs ...*Config) {
|
||||
for _, other := range cfgs {
|
||||
mergeInConfig(c, other)
|
||||
}
|
||||
}
|
||||
|
||||
func mergeInConfig(dst *Config, other *Config) {
|
||||
if other == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if other.CredentialsChainVerboseErrors != nil {
|
||||
dst.CredentialsChainVerboseErrors = other.CredentialsChainVerboseErrors
|
||||
}
|
||||
|
||||
if other.Credentials != nil {
|
||||
dst.Credentials = other.Credentials
|
||||
}
|
||||
|
||||
if other.Endpoint != nil {
|
||||
dst.Endpoint = other.Endpoint
|
||||
}
|
||||
|
||||
if other.EndpointResolver != nil {
|
||||
dst.EndpointResolver = other.EndpointResolver
|
||||
}
|
||||
|
||||
if other.Region != nil {
|
||||
dst.Region = other.Region
|
||||
}
|
||||
|
||||
if other.DisableSSL != nil {
|
||||
dst.DisableSSL = other.DisableSSL
|
||||
}
|
||||
|
||||
if other.HTTPClient != nil {
|
||||
dst.HTTPClient = other.HTTPClient
|
||||
}
|
||||
|
||||
if other.LogLevel != nil {
|
||||
dst.LogLevel = other.LogLevel
|
||||
}
|
||||
|
||||
if other.Logger != nil {
|
||||
dst.Logger = other.Logger
|
||||
}
|
||||
|
||||
if other.MaxRetries != nil {
|
||||
dst.MaxRetries = other.MaxRetries
|
||||
}
|
||||
|
||||
if other.Retryer != nil {
|
||||
dst.Retryer = other.Retryer
|
||||
}
|
||||
|
||||
if other.DisableParamValidation != nil {
|
||||
dst.DisableParamValidation = other.DisableParamValidation
|
||||
}
|
||||
|
||||
if other.DisableComputeChecksums != nil {
|
||||
dst.DisableComputeChecksums = other.DisableComputeChecksums
|
||||
}
|
||||
|
||||
if other.S3ForcePathStyle != nil {
|
||||
dst.S3ForcePathStyle = other.S3ForcePathStyle
|
||||
}
|
||||
|
||||
if other.S3Disable100Continue != nil {
|
||||
dst.S3Disable100Continue = other.S3Disable100Continue
|
||||
}
|
||||
|
||||
if other.S3UseAccelerate != nil {
|
||||
dst.S3UseAccelerate = other.S3UseAccelerate
|
||||
}
|
||||
|
||||
if other.S3DisableContentMD5Validation != nil {
|
||||
dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation
|
||||
}
|
||||
|
||||
if other.UseDualStack != nil {
|
||||
dst.UseDualStack = other.UseDualStack
|
||||
}
|
||||
|
||||
if other.EC2MetadataDisableTimeoutOverride != nil {
|
||||
dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride
|
||||
}
|
||||
|
||||
if other.SleepDelay != nil {
|
||||
dst.SleepDelay = other.SleepDelay
|
||||
}
|
||||
|
||||
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
|
||||
// configurations are provided they will be merged into the new config returned.
|
||||
func (c *Config) Copy(cfgs ...*Config) *Config {
|
||||
dst := &Config{}
|
||||
dst.MergeIn(c)
|
||||
|
||||
for _, cfg := range cfgs {
|
||||
dst.MergeIn(cfg)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
86
vendor/github.com/aws/aws-sdk-go/aws/config_test.go
generated
vendored
Normal file
86
vendor/github.com/aws/aws-sdk-go/aws/config_test.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
)
|
||||
|
||||
var testCredentials = credentials.NewStaticCredentials("AKID", "SECRET", "SESSION")
|
||||
|
||||
var copyTestConfig = Config{
|
||||
Credentials: testCredentials,
|
||||
Endpoint: String("CopyTestEndpoint"),
|
||||
Region: String("COPY_TEST_AWS_REGION"),
|
||||
DisableSSL: Bool(true),
|
||||
HTTPClient: http.DefaultClient,
|
||||
LogLevel: LogLevel(LogDebug),
|
||||
Logger: NewDefaultLogger(),
|
||||
MaxRetries: Int(3),
|
||||
DisableParamValidation: Bool(true),
|
||||
DisableComputeChecksums: Bool(true),
|
||||
S3ForcePathStyle: Bool(true),
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
want := copyTestConfig
|
||||
got := copyTestConfig.Copy()
|
||||
if !reflect.DeepEqual(*got, want) {
|
||||
t.Errorf("Copy() = %+v", got)
|
||||
t.Errorf(" want %+v", want)
|
||||
}
|
||||
|
||||
got.Region = String("other")
|
||||
if got.Region == want.Region {
|
||||
t.Errorf("Expect setting copy values not not reflect in source")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyReturnsNewInstance(t *testing.T) {
|
||||
want := copyTestConfig
|
||||
got := copyTestConfig.Copy()
|
||||
if got == &want {
|
||||
t.Errorf("Copy() = %p; want different instance as source %p", got, &want)
|
||||
}
|
||||
}
|
||||
|
||||
var mergeTestZeroValueConfig = Config{}
|
||||
|
||||
var mergeTestConfig = Config{
|
||||
Credentials: testCredentials,
|
||||
Endpoint: String("MergeTestEndpoint"),
|
||||
Region: String("MERGE_TEST_AWS_REGION"),
|
||||
DisableSSL: Bool(true),
|
||||
HTTPClient: http.DefaultClient,
|
||||
LogLevel: LogLevel(LogDebug),
|
||||
Logger: NewDefaultLogger(),
|
||||
MaxRetries: Int(10),
|
||||
DisableParamValidation: Bool(true),
|
||||
DisableComputeChecksums: Bool(true),
|
||||
S3ForcePathStyle: Bool(true),
|
||||
}
|
||||
|
||||
var mergeTests = []struct {
|
||||
cfg *Config
|
||||
in *Config
|
||||
want *Config
|
||||
}{
|
||||
{&Config{}, nil, &Config{}},
|
||||
{&Config{}, &mergeTestZeroValueConfig, &Config{}},
|
||||
{&Config{}, &mergeTestConfig, &mergeTestConfig},
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
for i, tt := range mergeTests {
|
||||
got := tt.cfg.Copy()
|
||||
got.MergeIn(tt.in)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Config %d %+v", i, tt.cfg)
|
||||
t.Errorf(" Merge(%+v)", tt.in)
|
||||
t.Errorf(" got %+v", got)
|
||||
t.Errorf(" want %+v", tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
71
vendor/github.com/aws/aws-sdk-go/aws/context.go
generated
vendored
Normal file
71
vendor/github.com/aws/aws-sdk-go/aws/context.go
generated
vendored
Normal 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
41
vendor/github.com/aws/aws-sdk-go/aws/context_1_6.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// +build !go1.7
|
||||
|
||||
package aws
|
||||
|
||||
import "time"
|
||||
|
||||
// An emptyCtx is a copy of the Go 1.7 context.emptyCtx type. This is copied to
|
||||
// provide a 1.6 and 1.5 safe version of context that is compatible with Go
|
||||
// 1.7's Context.
|
||||
//
|
||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||
// struct{}, since vars of this type must have distinct addresses.
|
||||
type emptyCtx int
|
||||
|
||||
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func (*emptyCtx) Done() <-chan struct{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*emptyCtx) Err() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*emptyCtx) Value(key interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *emptyCtx) String() string {
|
||||
switch e {
|
||||
case backgroundCtx:
|
||||
return "aws.BackgroundContext"
|
||||
}
|
||||
return "unknown empty Context"
|
||||
}
|
||||
|
||||
var (
|
||||
backgroundCtx = new(emptyCtx)
|
||||
)
|
||||
9
vendor/github.com/aws/aws-sdk-go/aws/context_1_7.go
generated
vendored
Normal file
9
vendor/github.com/aws/aws-sdk-go/aws/context_1_7.go
generated
vendored
Normal 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
37
vendor/github.com/aws/aws-sdk-go/aws/context_test.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
387
vendor/github.com/aws/aws-sdk-go/aws/convert_types.go
generated
vendored
Normal file
387
vendor/github.com/aws/aws-sdk-go/aws/convert_types.go
generated
vendored
Normal file
@@ -0,0 +1,387 @@
|
||||
package aws
|
||||
|
||||
import "time"
|
||||
|
||||
// String returns a pointer to the string value passed in.
|
||||
func String(v string) *string {
|
||||
return &v
|
||||
}
|
||||
|
||||
// StringValue returns the value of the string pointer passed in or
|
||||
// "" if the pointer is nil.
|
||||
func StringValue(v *string) string {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// StringSlice converts a slice of string values into a slice of
|
||||
// string pointers
|
||||
func StringSlice(src []string) []*string {
|
||||
dst := make([]*string, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// StringValueSlice converts a slice of string pointers into a slice of
|
||||
// string values
|
||||
func StringValueSlice(src []*string) []string {
|
||||
dst := make([]string, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// StringMap converts a string map of string values into a string
|
||||
// map of string pointers
|
||||
func StringMap(src map[string]string) map[string]*string {
|
||||
dst := make(map[string]*string)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// StringValueMap converts a string map of string pointers into a string
|
||||
// map of string values
|
||||
func StringValueMap(src map[string]*string) map[string]string {
|
||||
dst := make(map[string]string)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Bool returns a pointer to the bool value passed in.
|
||||
func Bool(v bool) *bool {
|
||||
return &v
|
||||
}
|
||||
|
||||
// BoolValue returns the value of the bool pointer passed in or
|
||||
// false if the pointer is nil.
|
||||
func BoolValue(v *bool) bool {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// BoolSlice converts a slice of bool values into a slice of
|
||||
// bool pointers
|
||||
func BoolSlice(src []bool) []*bool {
|
||||
dst := make([]*bool, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// BoolValueSlice converts a slice of bool pointers into a slice of
|
||||
// bool values
|
||||
func BoolValueSlice(src []*bool) []bool {
|
||||
dst := make([]bool, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// BoolMap converts a string map of bool values into a string
|
||||
// map of bool pointers
|
||||
func BoolMap(src map[string]bool) map[string]*bool {
|
||||
dst := make(map[string]*bool)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// BoolValueMap converts a string map of bool pointers into a string
|
||||
// map of bool values
|
||||
func BoolValueMap(src map[string]*bool) map[string]bool {
|
||||
dst := make(map[string]bool)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int returns a pointer to the int value passed in.
|
||||
func Int(v int) *int {
|
||||
return &v
|
||||
}
|
||||
|
||||
// IntValue returns the value of the int pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func IntValue(v *int) int {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IntSlice converts a slice of int values into a slice of
|
||||
// int pointers
|
||||
func IntSlice(src []int) []*int {
|
||||
dst := make([]*int, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// IntValueSlice converts a slice of int pointers into a slice of
|
||||
// int values
|
||||
func IntValueSlice(src []*int) []int {
|
||||
dst := make([]int, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// IntMap converts a string map of int values into a string
|
||||
// map of int pointers
|
||||
func IntMap(src map[string]int) map[string]*int {
|
||||
dst := make(map[string]*int)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// IntValueMap converts a string map of int pointers into a string
|
||||
// map of int values
|
||||
func IntValueMap(src map[string]*int) map[string]int {
|
||||
dst := make(map[string]int)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int64 returns a pointer to the int64 value passed in.
|
||||
func Int64(v int64) *int64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Int64Value returns the value of the int64 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Int64Value(v *int64) int64 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Int64Slice converts a slice of int64 values into a slice of
|
||||
// int64 pointers
|
||||
func Int64Slice(src []int64) []*int64 {
|
||||
dst := make([]*int64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int64ValueSlice converts a slice of int64 pointers into a slice of
|
||||
// int64 values
|
||||
func Int64ValueSlice(src []*int64) []int64 {
|
||||
dst := make([]int64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int64Map converts a string map of int64 values into a string
|
||||
// map of int64 pointers
|
||||
func Int64Map(src map[string]int64) map[string]*int64 {
|
||||
dst := make(map[string]*int64)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Int64ValueMap converts a string map of int64 pointers into a string
|
||||
// map of int64 values
|
||||
func Int64ValueMap(src map[string]*int64) map[string]int64 {
|
||||
dst := make(map[string]int64)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float64 returns a pointer to the float64 value passed in.
|
||||
func Float64(v float64) *float64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
// Float64Value returns the value of the float64 pointer passed in or
|
||||
// 0 if the pointer is nil.
|
||||
func Float64Value(v *float64) float64 {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Float64Slice converts a slice of float64 values into a slice of
|
||||
// float64 pointers
|
||||
func Float64Slice(src []float64) []*float64 {
|
||||
dst := make([]*float64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float64ValueSlice converts a slice of float64 pointers into a slice of
|
||||
// float64 values
|
||||
func Float64ValueSlice(src []*float64) []float64 {
|
||||
dst := make([]float64, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float64Map converts a string map of float64 values into a string
|
||||
// map of float64 pointers
|
||||
func Float64Map(src map[string]float64) map[string]*float64 {
|
||||
dst := make(map[string]*float64)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Float64ValueMap converts a string map of float64 pointers into a string
|
||||
// map of float64 values
|
||||
func Float64ValueMap(src map[string]*float64) map[string]float64 {
|
||||
dst := make(map[string]float64)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Time returns a pointer to the time.Time value passed in.
|
||||
func Time(v time.Time) *time.Time {
|
||||
return &v
|
||||
}
|
||||
|
||||
// TimeValue returns the value of the time.Time pointer passed in or
|
||||
// time.Time{} if the pointer is nil.
|
||||
func TimeValue(v *time.Time) time.Time {
|
||||
if v != nil {
|
||||
return *v
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// SecondsTimeValue converts an int64 pointer to a time.Time value
|
||||
// representing seconds since Epoch or time.Time{} if the pointer is nil.
|
||||
func SecondsTimeValue(v *int64) time.Time {
|
||||
if v != nil {
|
||||
return time.Unix((*v / 1000), 0)
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// MillisecondsTimeValue converts an int64 pointer to a time.Time value
|
||||
// representing milliseconds sinch Epoch or time.Time{} if the pointer is nil.
|
||||
func MillisecondsTimeValue(v *int64) time.Time {
|
||||
if v != nil {
|
||||
return time.Unix(0, (*v * 1000000))
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// TimeUnixMilli returns a Unix timestamp in milliseconds from "January 1, 1970 UTC".
|
||||
// The result is undefined if the Unix time cannot be represented by an int64.
|
||||
// Which includes calling TimeUnixMilli on a zero Time is undefined.
|
||||
//
|
||||
// This utility is useful for service API's such as CloudWatch Logs which require
|
||||
// their unix time values to be in milliseconds.
|
||||
//
|
||||
// See Go stdlib https://golang.org/pkg/time/#Time.UnixNano for more information.
|
||||
func TimeUnixMilli(t time.Time) int64 {
|
||||
return t.UnixNano() / int64(time.Millisecond/time.Nanosecond)
|
||||
}
|
||||
|
||||
// TimeSlice converts a slice of time.Time values into a slice of
|
||||
// time.Time pointers
|
||||
func TimeSlice(src []time.Time) []*time.Time {
|
||||
dst := make([]*time.Time, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
dst[i] = &(src[i])
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// TimeValueSlice converts a slice of time.Time pointers into a slice of
|
||||
// time.Time values
|
||||
func TimeValueSlice(src []*time.Time) []time.Time {
|
||||
dst := make([]time.Time, len(src))
|
||||
for i := 0; i < len(src); i++ {
|
||||
if src[i] != nil {
|
||||
dst[i] = *(src[i])
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// TimeMap converts a string map of time.Time values into a string
|
||||
// map of time.Time pointers
|
||||
func TimeMap(src map[string]time.Time) map[string]*time.Time {
|
||||
dst := make(map[string]*time.Time)
|
||||
for k, val := range src {
|
||||
v := val
|
||||
dst[k] = &v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// TimeValueMap converts a string map of time.Time pointers into a string
|
||||
// map of time.Time values
|
||||
func TimeValueMap(src map[string]*time.Time) map[string]time.Time {
|
||||
dst := make(map[string]time.Time)
|
||||
for k, val := range src {
|
||||
if val != nil {
|
||||
dst[k] = *val
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
641
vendor/github.com/aws/aws-sdk-go/aws/convert_types_test.go
generated
vendored
Normal file
641
vendor/github.com/aws/aws-sdk-go/aws/convert_types_test.go
generated
vendored
Normal file
@@ -0,0 +1,641 @@
|
||||
package aws
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var testCasesStringSlice = [][]string{
|
||||
{"a", "b", "c", "d", "e"},
|
||||
{"a", "b", "", "", "e"},
|
||||
}
|
||||
|
||||
func TestStringSlice(t *testing.T) {
|
||||
for idx, in := range testCasesStringSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := StringSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := StringValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesStringValueSlice = [][]*string{
|
||||
{String("a"), String("b"), nil, String("c")},
|
||||
}
|
||||
|
||||
func TestStringValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesStringValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := StringValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] != "" {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := StringSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) != "" {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *in[i], *out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesStringMap = []map[string]string{
|
||||
{"a": "1", "b": "2", "c": "3"},
|
||||
}
|
||||
|
||||
func TestStringMap(t *testing.T) {
|
||||
for idx, in := range testCasesStringMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := StringMap(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := StringValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesBoolSlice = [][]bool{
|
||||
{true, true, false, false},
|
||||
}
|
||||
|
||||
func TestBoolSlice(t *testing.T) {
|
||||
for idx, in := range testCasesBoolSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := BoolSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := BoolValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesBoolValueSlice = [][]*bool{}
|
||||
|
||||
func TestBoolValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesBoolValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := BoolValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := BoolSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesBoolMap = []map[string]bool{
|
||||
{"a": true, "b": false, "c": true},
|
||||
}
|
||||
|
||||
func TestBoolMap(t *testing.T) {
|
||||
for idx, in := range testCasesBoolMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := BoolMap(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := BoolValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesIntSlice = [][]int{
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
func TestIntSlice(t *testing.T) {
|
||||
for idx, in := range testCasesIntSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := IntSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := IntValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesIntValueSlice = [][]*int{}
|
||||
|
||||
func TestIntValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesIntValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := IntValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := IntSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesIntMap = []map[string]int{
|
||||
{"a": 3, "b": 2, "c": 1},
|
||||
}
|
||||
|
||||
func TestIntMap(t *testing.T) {
|
||||
for idx, in := range testCasesIntMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := IntMap(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := IntValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInt64Slice = [][]int64{
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
func TestInt64Slice(t *testing.T) {
|
||||
for idx, in := range testCasesInt64Slice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Int64Slice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Int64ValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInt64ValueSlice = [][]*int64{}
|
||||
|
||||
func TestInt64ValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesInt64ValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Int64ValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Int64Slice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesInt64Map = []map[string]int64{
|
||||
{"a": 3, "b": 2, "c": 1},
|
||||
}
|
||||
|
||||
func TestInt64Map(t *testing.T) {
|
||||
for idx, in := range testCasesInt64Map {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Int64Map(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Int64ValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesFloat64Slice = [][]float64{
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
func TestFloat64Slice(t *testing.T) {
|
||||
for idx, in := range testCasesFloat64Slice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Float64Slice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Float64ValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesFloat64ValueSlice = [][]*float64{}
|
||||
|
||||
func TestFloat64ValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesFloat64ValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Float64ValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if out[i] != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Float64Slice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if *(out2[i]) != 0 {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesFloat64Map = []map[string]float64{
|
||||
{"a": 3, "b": 2, "c": 1},
|
||||
}
|
||||
|
||||
func TestFloat64Map(t *testing.T) {
|
||||
for idx, in := range testCasesFloat64Map {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := Float64Map(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := Float64ValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesTimeSlice = [][]time.Time{
|
||||
{time.Now(), time.Now().AddDate(100, 0, 0)},
|
||||
}
|
||||
|
||||
func TestTimeSlice(t *testing.T) {
|
||||
for idx, in := range testCasesTimeSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := TimeSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := TimeValueSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesTimeValueSlice = [][]*time.Time{}
|
||||
|
||||
func TestTimeValueSlice(t *testing.T) {
|
||||
for idx, in := range testCasesTimeValueSlice {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := TimeValueSlice(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if in[i] == nil {
|
||||
if !out[i].IsZero() {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := *(in[i]), out[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out2 := TimeSlice(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out2 {
|
||||
if in[i] == nil {
|
||||
if !(*(out2[i])).IsZero() {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
} else {
|
||||
if e, a := in[i], out2[i]; e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testCasesTimeMap = []map[string]time.Time{
|
||||
{"a": time.Now().AddDate(-100, 0, 0), "b": time.Now()},
|
||||
}
|
||||
|
||||
func TestTimeMap(t *testing.T) {
|
||||
for idx, in := range testCasesTimeMap {
|
||||
if in == nil {
|
||||
continue
|
||||
}
|
||||
out := TimeMap(in)
|
||||
if e, a := len(out), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
for i := range out {
|
||||
if e, a := in[i], *(out[i]); e != a {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
|
||||
out2 := TimeValueMap(out)
|
||||
if e, a := len(out2), len(in); e != a {
|
||||
t.Errorf("Unexpected len at idx %d", idx)
|
||||
}
|
||||
if e, a := in, out2; !reflect.DeepEqual(e, a) {
|
||||
t.Errorf("Unexpected value at idx %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TimeValueTestCase struct {
|
||||
in int64
|
||||
outSecs time.Time
|
||||
outMillis time.Time
|
||||
}
|
||||
|
||||
var testCasesTimeValue = []TimeValueTestCase{
|
||||
{
|
||||
in: int64(1501558289000),
|
||||
outSecs: time.Unix(1501558289, 0),
|
||||
outMillis: time.Unix(1501558289, 0),
|
||||
},
|
||||
{
|
||||
in: int64(1501558289001),
|
||||
outSecs: time.Unix(1501558289, 0),
|
||||
outMillis: time.Unix(1501558289, 1*1000000),
|
||||
},
|
||||
}
|
||||
|
||||
func TestSecondsTimeValue(t *testing.T) {
|
||||
for idx, testCase := range testCasesTimeValue {
|
||||
out := SecondsTimeValue(&testCase.in)
|
||||
if e, a := testCase.outSecs, out; e != a {
|
||||
t.Errorf("Unexpected value for time value at %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMillisecondsTimeValue(t *testing.T) {
|
||||
for idx, testCase := range testCasesTimeValue {
|
||||
out := MillisecondsTimeValue(&testCase.in)
|
||||
if e, a := testCase.outMillis, out; e != a {
|
||||
t.Errorf("Unexpected value for time value at %d", idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
228
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
Normal file
228
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers.go
generated
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
package corehandlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// Interface for matching types which also have a Len method.
|
||||
type lener interface {
|
||||
Len() int
|
||||
}
|
||||
|
||||
// BuildContentLengthHandler builds the content length of a request based on the body,
|
||||
// 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 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) {
|
||||
var length int64
|
||||
|
||||
if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" {
|
||||
length, _ = strconv.ParseInt(slength, 10, 64)
|
||||
} else {
|
||||
if r.Body != nil {
|
||||
var err error
|
||||
length, err = aws.SeekerLen(r.Body)
|
||||
if err != nil {
|
||||
r.Error = awserr.New(request.ErrCodeSerialization, "failed to get request body's length", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if length > 0 {
|
||||
r.HTTPRequest.ContentLength = length
|
||||
r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length))
|
||||
} else {
|
||||
r.HTTPRequest.ContentLength = 0
|
||||
r.HTTPRequest.Header.Del("Content-Length")
|
||||
}
|
||||
}}
|
||||
|
||||
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 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) {
|
||||
// Unsigned requests are not signed
|
||||
if r.Config.Credentials == credentials.AnonymousCredentials {
|
||||
return
|
||||
}
|
||||
|
||||
signedTime := r.Time
|
||||
if !r.LastSignedAt.IsZero() {
|
||||
signedTime = r.LastSignedAt
|
||||
}
|
||||
|
||||
// 10 minutes to allow for some clock skew/delays in transmission.
|
||||
// Would be improved with aws/aws-sdk-go#423
|
||||
if signedTime.Add(10 * time.Minute).After(time.Now()) {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("request expired, resigning")
|
||||
r.Sign()
|
||||
},
|
||||
}
|
||||
|
||||
// SendHandler is a request handler to send service request using HTTP client.
|
||||
var SendHandler = request.NamedHandler{
|
||||
Name: "core.SendHandler",
|
||||
Fn: func(r *request.Request) {
|
||||
sender := sendFollowRedirects
|
||||
if r.DisableFollowRedirects {
|
||||
sender = sendWithoutFollowRedirects
|
||||
}
|
||||
|
||||
if request.NoBody == r.HTTPRequest.Body {
|
||||
// Strip off the request body if the NoBody reader was used as a
|
||||
// place holder for a request body. This prevents the SDK from
|
||||
// making requests with a request body when it would be invalid
|
||||
// to do so.
|
||||
//
|
||||
// Use a shallow copy of the http.Request to ensure the race condition
|
||||
// of transport on Body will not trigger
|
||||
reqOrig, reqCopy := r.HTTPRequest, *r.HTTPRequest
|
||||
reqCopy.Body = nil
|
||||
r.HTTPRequest = &reqCopy
|
||||
defer func() {
|
||||
r.HTTPRequest = reqOrig
|
||||
}()
|
||||
}
|
||||
|
||||
var err error
|
||||
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 {
|
||||
r.HTTPResponse.Body.Close()
|
||||
}
|
||||
// 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
|
||||
// comeback in a similar method.
|
||||
if e, ok := err.(*url.Error); ok && e.Err != nil {
|
||||
if s := reStatusCode.FindStringSubmatch(e.Err.Error()); s != nil {
|
||||
code, _ := strconv.ParseInt(s[1], 10, 64)
|
||||
r.HTTPResponse = &http.Response{
|
||||
StatusCode: int(code),
|
||||
Status: http.StatusText(int(code)),
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
if r.HTTPResponse == nil {
|
||||
// Add a dummy request response object to ensure the HTTPResponse
|
||||
// value is consistent.
|
||||
r.HTTPResponse = &http.Response{
|
||||
StatusCode: int(0),
|
||||
Status: http.StatusText(int(0)),
|
||||
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
|
||||
}
|
||||
}
|
||||
// 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) {
|
||||
if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 {
|
||||
// this may be replaced by an UnmarshalError handler
|
||||
r.Error = awserr.New("UnknownError", "unknown error", nil)
|
||||
}
|
||||
}}
|
||||
|
||||
// AfterRetryHandler performs final checks to determine if the request should
|
||||
// be retried and how long to delay.
|
||||
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 || aws.BoolValue(r.Config.EnforceShouldRetryCheck) {
|
||||
r.Retryable = aws.Bool(r.ShouldRetry(r))
|
||||
}
|
||||
|
||||
if r.WillRetry() {
|
||||
r.RetryDelay = r.RetryRules(r)
|
||||
|
||||
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
|
||||
// get credentials will trigger a credentials refresh.
|
||||
if r.IsErrorExpired() {
|
||||
r.Config.Credentials.Expire()
|
||||
}
|
||||
|
||||
r.RetryCount++
|
||||
r.Error = nil
|
||||
}
|
||||
}}
|
||||
|
||||
// ValidateEndpointHandler is a request handler to validate a request had the
|
||||
// appropriate Region and Endpoint set. Will set r.Error if the endpoint or
|
||||
// region is not valid.
|
||||
var ValidateEndpointHandler = request.NamedHandler{Name: "core.ValidateEndpointHandler", Fn: func(r *request.Request) {
|
||||
if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" {
|
||||
r.Error = aws.ErrMissingRegion
|
||||
} else if r.ClientInfo.Endpoint == "" {
|
||||
r.Error = aws.ErrMissingEndpoint
|
||||
}
|
||||
}}
|
||||
64
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_1_8_test.go
generated
vendored
Normal file
64
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_1_8_test.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
// +build go1.8
|
||||
|
||||
package corehandlers_test
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
func TestSendHandler_HEADNoBody(t *testing.T) {
|
||||
TLSBundleCertFile, TLSBundleKeyFile, TLSBundleCAFile, err := awstesting.CreateTLSBundleFiles()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer awstesting.CleanupTLSBundleFiles(TLSBundleCertFile, TLSBundleKeyFile, TLSBundleCAFile)
|
||||
|
||||
endpoint, err := awstesting.CreateTLSServer(TLSBundleCertFile, TLSBundleKeyFile, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("expect no error, got %v", err)
|
||||
}
|
||||
|
||||
transport := http.DefaultTransport.(*http.Transport)
|
||||
// test server's certificate is self-signed certificate
|
||||
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
http2.ConfigureTransport(transport)
|
||||
|
||||
sess, err := session.NewSessionWithOptions(session.Options{
|
||||
Config: aws.Config{
|
||||
HTTPClient: &http.Client{},
|
||||
Endpoint: aws.String(endpoint),
|
||||
Region: aws.String("mock-region"),
|
||||
Credentials: credentials.AnonymousCredentials,
|
||||
S3ForcePathStyle: aws.Bool(true),
|
||||
},
|
||||
})
|
||||
|
||||
svc := s3.New(sess)
|
||||
|
||||
req, _ := svc.HeadObjectRequest(&s3.HeadObjectInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Key: aws.String("keyname"),
|
||||
})
|
||||
|
||||
if e, a := request.NoBody, req.HTTPRequest.Body; e != a {
|
||||
t.Fatalf("expect %T request body, got %T", e, a)
|
||||
}
|
||||
|
||||
err = req.Send()
|
||||
if err != nil {
|
||||
t.Fatalf("expect no error, got %v", err)
|
||||
}
|
||||
if e, a := http.StatusOK, req.HTTPResponse.StatusCode; e != a {
|
||||
t.Errorf("expect %d status code, got %d", e, a)
|
||||
}
|
||||
}
|
||||
398
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go
generated
vendored
Normal file
398
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/handlers_test.go
generated
vendored
Normal file
@@ -0,0 +1,398 @@
|
||||
package corehandlers_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"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/request"
|
||||
"github.com/aws/aws-sdk-go/awstesting"
|
||||
"github.com/aws/aws-sdk-go/awstesting/unit"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
func TestValidateEndpointHandler(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
svc := awstesting.NewClient(aws.NewConfig().WithRegion("us-west-2"))
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
|
||||
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
err := req.Build()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateEndpointHandlerErrorRegion(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
svc := awstesting.NewClient()
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
|
||||
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
err := req.Build()
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("expect error, got none")
|
||||
}
|
||||
if e, a := aws.ErrMissingRegion, err; e != a {
|
||||
t.Errorf("expect %v to be %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
type mockCredsProvider struct {
|
||||
expired bool
|
||||
retrieveCalled bool
|
||||
}
|
||||
|
||||
func (m *mockCredsProvider) Retrieve() (credentials.Value, error) {
|
||||
m.retrieveCalled = true
|
||||
return credentials.Value{ProviderName: "mockCredsProvider"}, nil
|
||||
}
|
||||
|
||||
func (m *mockCredsProvider) IsExpired() bool {
|
||||
return m.expired
|
||||
}
|
||||
|
||||
func TestAfterRetryRefreshCreds(t *testing.T) {
|
||||
os.Clearenv()
|
||||
credProvider := &mockCredsProvider{}
|
||||
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
Credentials: credentials.NewCredentials(credProvider),
|
||||
MaxRetries: aws.Int(1),
|
||||
})
|
||||
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.ValidateResponse.PushBack(func(r *request.Request) {
|
||||
r.Error = awserr.New("UnknownError", "", nil)
|
||||
r.HTTPResponse = &http.Response{StatusCode: 400, Body: ioutil.NopCloser(bytes.NewBuffer([]byte{}))}
|
||||
})
|
||||
svc.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
|
||||
r.Error = awserr.New("ExpiredTokenException", "", nil)
|
||||
})
|
||||
svc.Handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
|
||||
if !svc.Config.Credentials.IsExpired() {
|
||||
t.Errorf("Expect to start out expired")
|
||||
}
|
||||
if credProvider.retrieveCalled {
|
||||
t.Errorf("expect not called")
|
||||
}
|
||||
|
||||
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
req.Send()
|
||||
|
||||
if !svc.Config.Credentials.IsExpired() {
|
||||
t.Errorf("Expect to start out expired")
|
||||
}
|
||||
if credProvider.retrieveCalled {
|
||||
t.Errorf("expect not called")
|
||||
}
|
||||
|
||||
_, err := svc.Config.Credentials.Get()
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
if !credProvider.retrieveCalled {
|
||||
t.Errorf("expect not called")
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return nil, fmt.Errorf("mock error")
|
||||
}
|
||||
|
||||
func TestSendHandlerError(t *testing.T) {
|
||||
svc := awstesting.NewClient(&aws.Config{
|
||||
HTTPClient: &http.Client{
|
||||
Transport: &testSendHandlerTransport{},
|
||||
},
|
||||
})
|
||||
svc.Handlers.Clear()
|
||||
svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
r := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
|
||||
|
||||
r.Send()
|
||||
|
||||
if r.Error == nil {
|
||||
t.Errorf("expect error, got none")
|
||||
}
|
||||
if r.HTTPResponse == nil {
|
||||
t.Errorf("expect response, got none")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
Resign bool
|
||||
}{
|
||||
{
|
||||
Req: &request.Request{
|
||||
Config: aws.Config{Credentials: credentials.AnonymousCredentials},
|
||||
Time: time.Now().Add(-15 * time.Minute),
|
||||
},
|
||||
Resign: false,
|
||||
},
|
||||
{
|
||||
Req: &request.Request{
|
||||
Time: time.Now().Add(-15 * time.Minute),
|
||||
},
|
||||
Resign: true,
|
||||
},
|
||||
{
|
||||
Req: &request.Request{
|
||||
Time: time.Now().Add(-1 * time.Minute),
|
||||
},
|
||||
Resign: false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
resigned := false
|
||||
c.Req.Handlers.Sign.PushBack(func(r *request.Request) {
|
||||
resigned = true
|
||||
})
|
||||
|
||||
corehandlers.ValidateReqSigHandler.Fn(c.Req)
|
||||
|
||||
if c.Req.Error != nil {
|
||||
t.Errorf("expect no error, got %v", c.Req.Error)
|
||||
}
|
||||
if e, a := c.Resign, resigned; e != a {
|
||||
t.Errorf("%d, expect %v to be %v", i, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setupContentLengthTestServer(t *testing.T, hasContentLength bool, contentLength int64) *httptest.Server {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, ok := r.Header["Content-Length"]
|
||||
if e, a := hasContentLength, ok; e != a {
|
||||
t.Errorf("expect %v to be %v", e, a)
|
||||
}
|
||||
if hasContentLength {
|
||||
if e, a := contentLength, r.ContentLength; e != a {
|
||||
t.Errorf("expect %v to be %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if hasContentLength {
|
||||
if e, a := "content-length", authHeader; !strings.Contains(a, e) {
|
||||
t.Errorf("expect %v to be in %v", e, a)
|
||||
}
|
||||
} else {
|
||||
if e, a := "content-length", authHeader; strings.Contains(a, e) {
|
||||
t.Errorf("expect %v to not be in %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
if e, a := contentLength, int64(len(b)); e != a {
|
||||
t.Errorf("expect %v to be %v", e, a)
|
||||
}
|
||||
}))
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func TestBuildContentLength_ZeroBody(t *testing.T) {
|
||||
server := setupContentLengthTestServer(t, false, 0)
|
||||
|
||||
svc := s3.New(unit.Session, &aws.Config{
|
||||
Endpoint: aws.String(server.URL),
|
||||
S3ForcePathStyle: aws.Bool(true),
|
||||
DisableSSL: aws.Bool(true),
|
||||
})
|
||||
_, err := svc.GetObject(&s3.GetObjectInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Key: aws.String("keyname"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildContentLength_NegativeBody(t *testing.T) {
|
||||
server := setupContentLengthTestServer(t, false, 0)
|
||||
|
||||
svc := s3.New(unit.Session, &aws.Config{
|
||||
Endpoint: aws.String(server.URL),
|
||||
S3ForcePathStyle: aws.Bool(true),
|
||||
DisableSSL: aws.Bool(true),
|
||||
})
|
||||
req, _ := svc.GetObjectRequest(&s3.GetObjectInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Key: aws.String("keyname"),
|
||||
})
|
||||
|
||||
req.HTTPRequest.Header.Set("Content-Length", "-1")
|
||||
|
||||
if req.Error != nil {
|
||||
t.Errorf("expect no error, got %v", req.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildContentLength_WithBody(t *testing.T) {
|
||||
server := setupContentLengthTestServer(t, true, 1024)
|
||||
|
||||
svc := s3.New(unit.Session, &aws.Config{
|
||||
Endpoint: aws.String(server.URL),
|
||||
S3ForcePathStyle: aws.Bool(true),
|
||||
DisableSSL: aws.Bool(true),
|
||||
})
|
||||
_, err := svc.PutObject(&s3.PutObjectInput{
|
||||
Bucket: aws.String("bucketname"),
|
||||
Key: aws.String("keyname"),
|
||||
Body: bytes.NewReader(make([]byte, 1024)),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("expect no error, got %v", err)
|
||||
}
|
||||
}
|
||||
17
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go
generated
vendored
Normal file
17
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/param_validator.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package corehandlers
|
||||
|
||||
import "github.com/aws/aws-sdk-go/aws/request"
|
||||
|
||||
// ValidateParametersHandler is a request handler to validate the input parameters.
|
||||
// Validating parameters only has meaning if done prior to the request being sent.
|
||||
var ValidateParametersHandler = request.NamedHandler{Name: "core.ValidateParametersHandler", Fn: func(r *request.Request) {
|
||||
if !r.ParamsFilled() {
|
||||
return
|
||||
}
|
||||
|
||||
if v, ok := r.Params.(request.Validator); ok {
|
||||
if err := v.Validate(); err != nil {
|
||||
r.Error = err
|
||||
}
|
||||
}
|
||||
}}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user