mirror of
https://github.com/stefanprodan/podinfo.git
synced 2026-04-09 12:36:50 +00:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ed9271783 | ||
|
|
97157694be | ||
|
|
bf92728234 | ||
|
|
f7c8061ac0 | ||
|
|
943f4e26ab | ||
|
|
f44909ef77 | ||
|
|
1af24bd3cd | ||
|
|
14ef95dac6 | ||
|
|
08a26cef24 | ||
|
|
8013c0bed0 | ||
|
|
6aa4303e08 | ||
|
|
f34fbacf13 | ||
|
|
b7701f6ae7 | ||
|
|
d3208cd8ac | ||
|
|
7d4c89d965 | ||
|
|
3b5ac61680 | ||
|
|
e8e2ac2b34 | ||
|
|
ef571a9b1b | ||
|
|
3d9cabcea4 | ||
|
|
ae4120a24e | ||
|
|
97d36bd8bb | ||
|
|
18a22d1b94 | ||
|
|
083de34465 | ||
|
|
64b85dc30d | ||
|
|
fed964e223 | ||
|
|
efb6a76242 | ||
|
|
fb199b72a1 | ||
|
|
ce117e1706 | ||
|
|
23e67f9923 | ||
|
|
30b030a685 | ||
|
|
0fe4a7a3a9 | ||
|
|
982063ab9b | ||
|
|
c3256bd18f | ||
|
|
d947fc5b2c | ||
|
|
dc6d64137d | ||
|
|
f3c1ee7dbc | ||
|
|
6b6dd86fea | ||
|
|
02e5f233d0 | ||
|
|
b89f46ac04 | ||
|
|
59cd692141 | ||
|
|
bcd61428d1 | ||
|
|
f8ec9c0947 | ||
|
|
6c98fbf1f4 | ||
|
|
54f6d9f74d | ||
|
|
1d35304d9d |
17
.github/actions/docker/Dockerfile
vendored
Normal file
17
.github/actions/docker/Dockerfile
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM docker:stable
|
||||
|
||||
LABEL "name"="Docker tag and push action"
|
||||
LABEL "maintainer"="Stefan Prodan <support@weave.works>"
|
||||
LABEL "version"="1.0.0"
|
||||
|
||||
LABEL "com.github.actions.icon"="package"
|
||||
LABEL "com.github.actions.color"="green"
|
||||
LABEL "com.github.actions.name"="Docker Publish"
|
||||
LABEL "com.github.actions.description"="This is an Action to run docker tag and push commands."
|
||||
|
||||
RUN apk add --no-cache ca-certificates bash git curl \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
25
.github/actions/docker/entrypoint.sh
vendored
Executable file
25
.github/actions/docker/entrypoint.sh
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
DOCKER_TAG="latest"
|
||||
if [[ "${GITHUB_REF}" == "refs/tags"* ]]; then
|
||||
DOCKER_TAG=$(echo ${GITHUB_REF} | rev | cut -d/ -f1 | rev)
|
||||
else
|
||||
DOCKER_TAG=$(echo ${GITHUB_REF} | rev | cut -d/ -f1 | rev)-$(echo ${GITHUB_SHA} | head -c7)
|
||||
fi
|
||||
|
||||
if [[ "$1" == "build" ]]; then
|
||||
docker build -t ${DOCKER_IMAGE}:${DOCKER_TAG} \
|
||||
--build-arg REPOSITORY=${GITHUB_REPOSITORY} \
|
||||
--build-arg SHA=${GITHUB_SHA} -f $2 .
|
||||
echo "Docker image tagged as ${DOCKER_IMAGE}:${DOCKER_TAG}"
|
||||
fi
|
||||
|
||||
if [[ "$1" == "push" ]]; then
|
||||
docker push ${DOCKER_IMAGE}:${DOCKER_TAG}
|
||||
echo "Docker image pushed to ${DOCKER_IMAGE}:${DOCKER_TAG}"
|
||||
fi
|
||||
|
||||
20
.github/actions/golang/Dockerfile
vendored
Normal file
20
.github/actions/golang/Dockerfile
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
FROM golang:1.10
|
||||
|
||||
LABEL "name"="golang tools action"
|
||||
LABEL "maintainer"="Stefan Prodan <support@weave.works>"
|
||||
LABEL "version"="1.0.0"
|
||||
|
||||
LABEL "com.github.actions.icon"="code"
|
||||
LABEL "com.github.actions.color"="green-dark"
|
||||
LABEL "com.github.actions.name"="Go Tools"
|
||||
LABEL "com.github.actions.description"="This is an Action to run go and dep commands."
|
||||
|
||||
ENV DEP_VERSION="v0.5.0"
|
||||
|
||||
RUN curl -fL -o /usr/local/bin/dep https://github.com/golang/dep/releases/download/${DEP_VERSION}/dep-linux-amd64 \
|
||||
&& chmod +x /usr/local/bin/dep
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
26
.github/actions/golang/entrypoint.sh
vendored
Executable file
26
.github/actions/golang/entrypoint.sh
vendored
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
set -e
|
||||
|
||||
APP_DIR="/go/src/github.com/${GITHUB_REPOSITORY}/"
|
||||
|
||||
mkdir -p ${APP_DIR} && cp -r ./ ${APP_DIR} && cd ${APP_DIR}
|
||||
|
||||
if [[ "$1" == "fmt" ]]; then
|
||||
echo "Running go fmt"
|
||||
files=$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*") 2>&1)
|
||||
if [ "$files" ]; then
|
||||
echo "These files did not pass the gofmt check:"
|
||||
echo ${files}
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$1" == "test" ]]; then
|
||||
echo "Running go test"
|
||||
go test $(go list ./... | grep -v /vendor/) -race -coverprofile=coverage.txt -covermode=atomic
|
||||
cat coverage.txt
|
||||
fi
|
||||
35
.github/main.workflow
vendored
Normal file
35
.github/main.workflow
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
workflow "Publish container" {
|
||||
on = "push"
|
||||
resolves = ["Push"]
|
||||
}
|
||||
|
||||
action "Lint" {
|
||||
uses = "./.github/actions/golang"
|
||||
args = "fmt"
|
||||
}
|
||||
|
||||
action "Test" {
|
||||
needs = ["Lint"]
|
||||
uses = "./.github/actions/golang"
|
||||
args = "test"
|
||||
}
|
||||
|
||||
action "Build" {
|
||||
needs = ["Test"]
|
||||
uses = "./.github/actions/docker"
|
||||
secrets = ["DOCKER_IMAGE"]
|
||||
args = ["build", "Dockerfile.gh"]
|
||||
}
|
||||
|
||||
action "Login" {
|
||||
needs = ["Build"]
|
||||
uses = "actions/docker/login@master"
|
||||
secrets = ["DOCKER_USERNAME", "DOCKER_PASSWORD"]
|
||||
}
|
||||
|
||||
action "Push" {
|
||||
needs = ["Login"]
|
||||
uses = "./.github/actions/docker"
|
||||
secrets = ["DOCKER_IMAGE"]
|
||||
args = "push"
|
||||
}
|
||||
39
Dockerfile.gh
Normal file
39
Dockerfile.gh
Normal file
@@ -0,0 +1,39 @@
|
||||
FROM golang:1.11 as builder
|
||||
|
||||
ARG REPOSITORY
|
||||
ARG SHA
|
||||
|
||||
RUN mkdir -p /go/src/github.com/${REPOSITORY}/
|
||||
|
||||
WORKDIR /go/src/github.com/${REPOSITORY}
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||
-ldflags "-s -w -X github.com/${REPOSITORY}/pkg/version.REVISION=${SHA}" \
|
||||
-a -installsuffix cgo -o podinfo ./cmd/podinfo \
|
||||
&& mv podinfo /usr/local/bin/podinfo
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||
-ldflags "-s -w -X github.com/${REPOSITORY}/pkg/version.REVISION=${SHA}" \
|
||||
-a -installsuffix cgo -o podcli ./cmd/podcli \
|
||||
&& mv podcli /usr/local/bin/podcli
|
||||
|
||||
FROM alpine:3.8
|
||||
|
||||
RUN addgroup -S app \
|
||||
&& adduser -S -g app app \
|
||||
&& apk --no-cache add \
|
||||
curl openssl netcat-openbsd
|
||||
|
||||
WORKDIR /home/app
|
||||
|
||||
COPY --from=builder /usr/local/bin/podinfo .
|
||||
COPY --from=builder /usr/local/bin/podcli /usr/local/bin/podcli
|
||||
COPY ./ui ./ui
|
||||
|
||||
RUN chown -R app:app ./
|
||||
|
||||
USER app
|
||||
|
||||
CMD ["./podinfo"]
|
||||
254
Gopkg.lock
generated
254
Gopkg.lock
generated
@@ -1,38 +1,166 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a281ff052e060998bc715e444e448f6762a6da3e20e68c689dd8696e2894a5fd"
|
||||
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/ini",
|
||||
"internal/s3err",
|
||||
"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 = "UT"
|
||||
revision = "f76d9803fd695eebf74cb23c460287fa496efc21"
|
||||
version = "v1.15.63"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
|
||||
name = "github.com/beorn7/perks"
|
||||
packages = ["quantile"]
|
||||
pruneopts = "UT"
|
||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:37011b20a70e205b93ebea5287e1afa5618db54bf3998c36ff5a8e4b146a170a"
|
||||
name = "github.com/bgentry/go-netrc"
|
||||
packages = ["netrc"]
|
||||
pruneopts = "UT"
|
||||
revision = "9fd32a8b3d3d3f9d43c341bfe098430e07609480"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b95738a1e6ace058b5b8544303c0871fc01d224ef0d672f778f696265d0f2917"
|
||||
name = "github.com/chzyer/readline"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "62c6fe6193755f722b8b8788aa7357be55a50ff1"
|
||||
version = "v1.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:865079840386857c809b72ce300be7580cb50d3d3129ce11bf9aa6ca2bc1934a"
|
||||
name = "github.com/fatih/color"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = ["proto"]
|
||||
pruneopts = "UT"
|
||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1"
|
||||
name = "github.com/gorilla/context"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e73f5b0152105f18bc131fba127d9949305c8693f8a762588a82a48f61756f5f"
|
||||
name = "github.com/gorilla/mux"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
|
||||
version = "v1.6.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
|
||||
name = "github.com/gorilla/websocket"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f47d6109c2034cb16bd62b220e18afd5aa9d5a1630fe5d937ad96a4fb7cbb277"
|
||||
name = "github.com/hashicorp/go-cleanhttp"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "e8ab9daed8d1ddd2d3c4efba338fe2eeae2e4f18"
|
||||
version = "v0.5.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:724d270a4cac0945dedb8de6357625a9d976cb640d381d3dab3144cec295db26"
|
||||
name = "github.com/hashicorp/go-getter"
|
||||
packages = [
|
||||
".",
|
||||
"helper/url",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "4bda8fa99001c61db3cad96b421d4c12a81f256d"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:605c47454db9040e30b20dc1b29e3e9d42d6ee742545729cdef74afb1b898ad0"
|
||||
name = "github.com/hashicorp/go-safetemp"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c9a55de4fe06c920a71964b53cfe3dd293a3c743"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:77395dd3847dac9c45118c668f5dab85aedf0163dc3b38aea6578c5cf0d502f9"
|
||||
name = "github.com/hashicorp/go-version"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "b5a281d3160aa11950a6182bd9a9dc2cb1e02d50"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:a361611b8c8c75a1091f00027767f7779b29cb37c456a71b8f2604c88057ab40"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
@@ -44,128 +172,216 @@
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token"
|
||||
"json/token",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e22af8c7518e1eab6f2eab2b7d7558927f816262586cd6ed9f349c97a6c285c4"
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "0b12d6b5"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7"
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
|
||||
name = "github.com/mattn/go-colorable"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0981502f9816113c9c8c4ac301583841855c8cf4da8c72f696b3ebedf6d0e4e5"
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c"
|
||||
version = "v0.0.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
packages = ["pbutil"]
|
||||
pruneopts = "UT"
|
||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:78bbb1ba5b7c3f2ed0ea1eab57bdd3859aec7e177811563edc41198a760b06af"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:42eb1f52b84a06820cedc9baec2e710bfbda3ee6dac6cdb97f8b9a5066134ec6"
|
||||
name = "github.com/mitchellh/go-testing-interface"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "6d0b8010fcc857872e42fc6c931227569016843c"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5ab79470a1d0fb19b041a624415612f8236b3c06070161a910562f2b2d064355"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "f15292f7a699fcc1a38a80977f80a046874ba8ac"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d14a5f4bfecf017cb780bdde1b6483e5deb87e12c332544d2c430eda58734bcb"
|
||||
name = "github.com/prometheus/client_golang"
|
||||
packages = [
|
||||
"prometheus",
|
||||
"prometheus/promhttp"
|
||||
"prometheus/promhttp",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "c5b7fccd204277076155f10851dad72b76a49317"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
|
||||
name = "github.com/prometheus/client_model"
|
||||
packages = ["go"]
|
||||
pruneopts = "UT"
|
||||
revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5"
|
||||
name = "github.com/prometheus/common"
|
||||
packages = [
|
||||
"expfmt",
|
||||
"internal/bitbucket.org/ww/goautoneg",
|
||||
"model"
|
||||
"model",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "c7de2306084e37d54b8be01f3541a8464345e9a5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290"
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [
|
||||
".",
|
||||
"internal/util",
|
||||
"nfs",
|
||||
"xfs"
|
||||
"xfs",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:bd1ae00087d17c5a748660b8e89e1043e1e5479d0fea743352cda2f8dd8c4f84"
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem"
|
||||
"mem",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:516e71bed754268937f57d4ecb190e01958452336fa73dbac880894164e91c1f"
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939"
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8a020f916b23ff574845789daee6818daf8d25a4852419aae3f0b12378ba432a"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "14d3d4c518341bea657dd8a226f5121c0ff8c9f2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:dab83a1bbc7ad3d7a6ba1a1cc1760f25ac38cdf7d96a5cdd55cd915a4f5ceaf9"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4fc8a61287ccfb4286e1ca5ad2ce3b0b301d746053bf44ac38cf34e40ae10372"
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "907c19d40d9a6c9bb55f040ff4ae45271a4754b9"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4aeb3860275fa1fd60cccfb5a6ef85da438bf17402e1e84412ade4d4b55066a0"
|
||||
name = "github.com/ulikunitz/xz"
|
||||
packages = [
|
||||
".",
|
||||
"internal/hash",
|
||||
"internal/xlog",
|
||||
"lzma",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "0c6b41e72360850ca4f98dc341fd999726ea007f"
|
||||
version = "v0.5.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3c1a69cdae3501bf75e76d0d86dc6f2b0a7421bc205c0cb7b96b19eed464a34d"
|
||||
name = "go.uber.org/atomic"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
|
||||
version = "v1.3.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:60bf2a5e347af463c42ed31a493d817f8a72f102543060ed992754e689805d1a"
|
||||
name = "go.uber.org/multierr"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c52caf7bd44f92e54627a31b85baf06a68333a196b3d8d241480a774733dcf8b"
|
||||
name = "go.uber.org/zap"
|
||||
packages = [
|
||||
".",
|
||||
@@ -173,18 +389,22 @@
|
||||
"internal/bufferpool",
|
||||
"internal/color",
|
||||
"internal/exit",
|
||||
"zapcore"
|
||||
"zapcore",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "ff33455a0e382e8a81d14dd7c922020b6b5e7982"
|
||||
version = "v1.9.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e3e7f51633f98fce9404940f74dfd65cf306ee173ddf5a8b247c9c830e42b38a"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
pruneopts = "UT"
|
||||
revision = "1a700e749ce29638d0bbcb531cce1094ea096bd3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8029e9743749d4be5bc9f7d42ea1659471767860f0cdc34d37c3111bd308a295"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"internal/gen",
|
||||
@@ -192,20 +412,38 @@
|
||||
"internal/ucd",
|
||||
"transform",
|
||||
"unicode/cldr",
|
||||
"unicode/norm"
|
||||
"unicode/norm",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "5fcfa1cbebd2064a6f91f7c7582a6bc99d864fd721a9ffb9bc1a9bd23f501b99"
|
||||
input-imports = [
|
||||
"github.com/chzyer/readline",
|
||||
"github.com/dgrijalva/jwt-go",
|
||||
"github.com/fatih/color",
|
||||
"github.com/fsnotify/fsnotify",
|
||||
"github.com/gorilla/mux",
|
||||
"github.com/gorilla/websocket",
|
||||
"github.com/hashicorp/go-getter",
|
||||
"github.com/prometheus/client_golang/prometheus",
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp",
|
||||
"github.com/spf13/cobra",
|
||||
"github.com/spf13/pflag",
|
||||
"github.com/spf13/viper",
|
||||
"go.uber.org/zap",
|
||||
"go.uber.org/zap/zapcore",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
name = "github.com/gorilla/mux"
|
||||
version = "v1.6.2"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "go.uber.org/zap"
|
||||
version = "v1.9.1"
|
||||
@@ -26,6 +30,10 @@
|
||||
name = "github.com/spf13/cobra"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
version = "v3.2.0"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
6
Makefile
6
Makefile
@@ -73,9 +73,9 @@ docker-build: tar
|
||||
.PHONY: docker-push
|
||||
docker-push:
|
||||
@echo Pushing: $(VERSION) to $(DOCKER_IMAGE_NAME)
|
||||
for arch in $(LINUX_ARCH); do \
|
||||
docker push $(DOCKER_IMAGE_NAME):$(NAME)-$$arch ;\
|
||||
done
|
||||
for arch in $(LINUX_ARCH); do \
|
||||
docker push $(DOCKER_IMAGE_NAME):$(NAME)-$$arch ;\
|
||||
done
|
||||
manifest-tool push from-args --platforms $(PLATFORMS) --template $(DOCKER_IMAGE_NAME):podinfo-ARCH --target $(DOCKER_IMAGE_NAME):$(VERSION)
|
||||
manifest-tool push from-args --platforms $(PLATFORMS) --template $(DOCKER_IMAGE_NAME):podinfo-ARCH --target $(DOCKER_IMAGE_NAME):latest
|
||||
|
||||
|
||||
17
Makefile.gh
Normal file
17
Makefile.gh
Normal file
@@ -0,0 +1,17 @@
|
||||
DOCKER_IMAGE?=stefanprodan/k8s-podinfo
|
||||
DOCKER_TAG?=$(shell git symbolic-ref --short HEAD)
|
||||
GIT_REPOSITORY?=stefanprodan/k8s-podinfo
|
||||
GIT_SHA:=$(shell git describe --dirty --always)
|
||||
|
||||
.PHONY: all
|
||||
all: test build
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test ./...
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
docker build -t $(DOCKER_IMAGE):$(DOCKER_TAG) \
|
||||
--build-arg REPOSITORY=${GIT_REPOSITORY} \
|
||||
--build-arg SHA=${GIT_SHA} -f Dockerfile.gh .
|
||||
@@ -29,11 +29,15 @@ Web API:
|
||||
* `GET /status/{code}` returns the status code
|
||||
* `GET /panic` crashes the process with exit code 255
|
||||
* `POST /echo` forwards the call to the backend service and echos the posted content
|
||||
* `GET /env` returns the environment variables as a JSON array
|
||||
* `GET /headers` returns a JSON with the request HTTP headers
|
||||
* `GET /delay/{seconds}` waits for the specified period
|
||||
* `POST /token` issues a JWT token valid for one minute `JWT=$(curl -sd 'anon' podinfo:9898/token | jq -r .token)`
|
||||
* `GET /token/validate` validates the JWT token `curl -H "Authorization: Bearer $JWT" podinfo:9898/token/validate`
|
||||
* `GET /configs` returns a JSON with configmaps and/or secrets mounted in the `config` volume
|
||||
* `POST /write` writes the posted content to disk at /data/hash and returns the SHA1 hash of the content
|
||||
* `GET /read/{hash}` returns the content of the file /data/hash if exists
|
||||
* `GET /ws/echo` echos content via websockets `podcli ws ws://localhost:9898/ws/echo`
|
||||
|
||||
### Guides
|
||||
|
||||
@@ -44,3 +48,4 @@ Web API:
|
||||
* [Expose Kubernetes services over HTTPS with Ngrok](docs/6-ngrok.md)
|
||||
* [A/B Testing with Ambassador API Gateway](docs/5-canary.md)
|
||||
* [Canary Deployments with Istio](docs/7-istio.md)
|
||||
* [GitHub Actions CI demo](docs/8-gh-actions.md)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
apiVersion: v1
|
||||
version: 0.2.0
|
||||
appVersion: 1.1.0
|
||||
version: 1.2.1
|
||||
appVersion: 1.2.1
|
||||
engine: gotpl
|
||||
name: podinfo-istio
|
||||
description: Podinfo Helm chart for Istio
|
||||
|
||||
@@ -6,13 +6,13 @@ host: backend
|
||||
# stable release
|
||||
blue:
|
||||
replicas: 2
|
||||
tag: "1.1.0"
|
||||
tag: "1.1.1"
|
||||
backend: http://store:9898/api/echo
|
||||
|
||||
# canary release
|
||||
green:
|
||||
replicas: 2
|
||||
tag: "1.1.0"
|
||||
tag: "1.2.0"
|
||||
routing:
|
||||
# target green callers
|
||||
- match:
|
||||
|
||||
@@ -16,14 +16,14 @@ gateway:
|
||||
# stable release
|
||||
blue:
|
||||
replicas: 2
|
||||
tag: "1.1.0"
|
||||
tag: "1.1.1"
|
||||
message: "Greetings from the blue frontend"
|
||||
backend: http://backend:9898/api/echo
|
||||
|
||||
# canary release
|
||||
green:
|
||||
replicas: 2
|
||||
tag: "1.1.0"
|
||||
tag: "1.2.0"
|
||||
routing:
|
||||
# target Safari
|
||||
- match:
|
||||
|
||||
@@ -6,13 +6,13 @@ host: store
|
||||
# load balance 80/20 between blue and green
|
||||
blue:
|
||||
replicas: 2
|
||||
tag: "1.1.0"
|
||||
tag: "1.1.1"
|
||||
backend: https://httpbin.org/anything
|
||||
weight: 80
|
||||
|
||||
green:
|
||||
replicas: 2
|
||||
tag: "1.1.0"
|
||||
tag: "1.2.0"
|
||||
backend: https://httpbin.org/anything
|
||||
|
||||
externalServices:
|
||||
|
||||
@@ -60,14 +60,15 @@ spec:
|
||||
- podcli
|
||||
- check
|
||||
- http
|
||||
- http://localhost:{{ .Values.service.containerPort }}/healthz
|
||||
- localhost:{{ .Values.containerPort }}/healthz
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- podcli
|
||||
- check
|
||||
- http
|
||||
- http://localhost:{{ .Values.service.containerPort }}/readyz
|
||||
- localhost:{{ .Values.containerPort }}/readyz
|
||||
periodSeconds: 3
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
|
||||
@@ -61,14 +61,15 @@ spec:
|
||||
- podcli
|
||||
- check
|
||||
- http
|
||||
- http://localhost:{{ .Values.service.containerPort }}/healthz
|
||||
- localhost:{{ .Values.containerPort }}/healthz
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- podcli
|
||||
- check
|
||||
- http
|
||||
- http://localhost:{{ .Values.service.containerPort }}/readyz
|
||||
- localhost:{{ .Values.containerPort }}/readyz
|
||||
periodSeconds: 3
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
|
||||
@@ -27,7 +27,7 @@ gateway:
|
||||
blue:
|
||||
replicas: 2
|
||||
repository: quay.io/stefanprodan/podinfo
|
||||
tag: "1.1.0"
|
||||
tag: "1.2.1"
|
||||
# green must have at at least one replica to set weight under 100
|
||||
weight: 100
|
||||
message:
|
||||
@@ -41,7 +41,7 @@ blue:
|
||||
green:
|
||||
replicas: 0
|
||||
repository: quay.io/stefanprodan/podinfo
|
||||
tag: "1.1.0"
|
||||
tag: "1.2.1"
|
||||
message:
|
||||
backend:
|
||||
routing:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
apiVersion: v1
|
||||
version: 1.1.0
|
||||
appVersion: 1.1.0
|
||||
version: 1.3.1
|
||||
appVersion: 1.3.1
|
||||
name: podinfo
|
||||
engine: gotpl
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
|
||||
@@ -63,14 +63,15 @@ spec:
|
||||
- podcli
|
||||
- check
|
||||
- http
|
||||
- http://localhost:{{ .Values.service.containerPort }}/healthz
|
||||
- localhost:{{ .Values.service.containerPort }}/healthz
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- podcli
|
||||
- check
|
||||
- http
|
||||
- http://localhost:{{ .Values.service.containerPort }}/readyz
|
||||
- localhost:{{ .Values.service.containerPort }}/readyz
|
||||
periodSeconds: 3
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
|
||||
@@ -12,7 +12,7 @@ faults:
|
||||
|
||||
image:
|
||||
repository: quay.io/stefanprodan/podinfo
|
||||
tag: 1.1.0
|
||||
tag: 1.3.1
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
service:
|
||||
|
||||
331
cmd/podcli/code.go
Normal file
331
cmd/podcli/code.go
Normal file
@@ -0,0 +1,331 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-getter"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
codeProjectName string
|
||||
codeGitUser string
|
||||
codeVersion string
|
||||
codeProjectPath string
|
||||
)
|
||||
|
||||
var codeCmd = &cobra.Command{
|
||||
Use: `code`,
|
||||
Short: "Code commands",
|
||||
}
|
||||
|
||||
var codeInitCmd = &cobra.Command{
|
||||
Use: `init [name]`,
|
||||
Short: "initialize podinfo code repo",
|
||||
Example: ` code init demo-app --version=v1.2.0 --git-user=stefanprodan`,
|
||||
RunE: runCodeInit,
|
||||
}
|
||||
|
||||
func init() {
|
||||
codeInitCmd.Flags().StringVar(&codeGitUser, "git-user", "", "GitHub user or org")
|
||||
codeInitCmd.Flags().StringVar(&codeVersion, "version", "master", "podinfo repo tag or branch name")
|
||||
codeInitCmd.Flags().StringVar(&codeProjectPath, "path", ".", "destination repo")
|
||||
|
||||
codeCmd.AddCommand(codeInitCmd)
|
||||
|
||||
rootCmd.AddCommand(codeCmd)
|
||||
}
|
||||
|
||||
func runCodeInit(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if len(codeGitUser) < 0 {
|
||||
return fmt.Errorf("--git-user is required")
|
||||
}
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("project name is required")
|
||||
}
|
||||
|
||||
codeProjectName = args[0]
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatalf("Error getting pwd: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
tmpPath := "/tmp/k8s-podinfo"
|
||||
versionName := fmt.Sprintf("k8s-podinfo-%s", codeVersion)
|
||||
|
||||
downloadURL := fmt.Sprintf("https://github.com/stefanprodan/k8s-podinfo/archive/%s.zip", codeVersion)
|
||||
client := &getter.Client{
|
||||
Src: downloadURL,
|
||||
Dst: tmpPath,
|
||||
Pwd: pwd,
|
||||
Mode: getter.ClientModeAny,
|
||||
}
|
||||
|
||||
fmt.Printf("Downloading %s\n", downloadURL)
|
||||
|
||||
if err := client.Get(); err != nil {
|
||||
log.Fatalf("Error downloading: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
pkgFrom := "github.com/stefanprodan/k8s-podinfo"
|
||||
pkgTo := fmt.Sprintf("github.com/%s/%s", codeGitUser, codeProjectName)
|
||||
|
||||
if err := replaceImports(tmpPath, pkgFrom, pkgTo); err != nil {
|
||||
log.Fatalf("Error parsing imports: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
dirs := []string{"pkg", "cmd", "ui", "vendor", ".github"}
|
||||
for _, dir := range dirs {
|
||||
|
||||
err = os.MkdirAll(path.Join(codeProjectPath, dir), os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := copyDir(path.Join(tmpPath, versionName, dir), path.Join(codeProjectPath, dir)); err != nil {
|
||||
log.Fatalf("Error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
files := []string{"Gopkg.toml", "Gopkg.lock"}
|
||||
for _, file := range files {
|
||||
if err := copyFile(path.Join(tmpPath, versionName, file), path.Join(codeProjectPath, file)); err != nil {
|
||||
log.Fatalf("Error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fileContent, err := ioutil.ReadFile(path.Join(codeProjectPath, file))
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
newContent := strings.Replace(string(fileContent), pkgFrom, pkgTo, -1)
|
||||
err = ioutil.WriteFile(path.Join(codeProjectPath, file), []byte(newContent), os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
projFrom := "stefanprodan/k8s-podinfo"
|
||||
projTo := fmt.Sprintf("%s/%s", codeGitUser, codeProjectName)
|
||||
|
||||
makeFiles := []string{"Makefile.gh", "Dockerfile.gh"}
|
||||
for _, file := range makeFiles {
|
||||
fileContent, err := ioutil.ReadFile(path.Join(tmpPath, versionName, file))
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
destFile := strings.Replace(file, ".gh", "", -1)
|
||||
newContent := strings.Replace(string(fileContent), projFrom, projTo, -1)
|
||||
err = ioutil.WriteFile(path.Join(codeProjectPath, destFile), []byte(newContent), os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
workflows := []string{".github/main.workflow"}
|
||||
for _, file := range workflows {
|
||||
fileContent, err := ioutil.ReadFile(path.Join(codeProjectPath, file))
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
newContent := strings.Replace(string(fileContent), "Dockerfile.gh", "Dockerfile", -1)
|
||||
err = ioutil.WriteFile(path.Join(codeProjectPath, file), []byte(newContent), os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatalf("Error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
err = gitPush()
|
||||
if err != nil {
|
||||
log.Fatalf("git push error: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("Initialization finished")
|
||||
return nil
|
||||
}
|
||||
|
||||
func gitPush() error {
|
||||
cmd := exec.Command("sh", "-c", "git add . && git commit -m \"init\" && git push")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
func replaceImports(projectPath string, pkgFrom string, pkgTo string) error {
|
||||
regexImport, err := regexp.Compile(`(?s)(import(.*?)\)|import.*$)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
regexImportedPackage, err := regexp.Compile(`"(.*?)"`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
found := []string{}
|
||||
|
||||
err = filepath.Walk(projectPath, func(path string, info os.FileInfo, err error) error {
|
||||
if filepath.Ext(path) == ".go" {
|
||||
bts, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
content := string(bts)
|
||||
matches := regexImport.FindAllString(content, -1)
|
||||
isExists := false
|
||||
|
||||
isReplaceable:
|
||||
for _, each := range matches {
|
||||
for _, eachLine := range strings.Split(each, "\n") {
|
||||
matchesInline := regexImportedPackage.FindAllString(eachLine, -1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, eachSubline := range matchesInline {
|
||||
if strings.Contains(eachSubline, pkgFrom) {
|
||||
isExists = true
|
||||
break isReplaceable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isExists {
|
||||
content = strings.Replace(content, `"`+pkgFrom+`"`, `"`+pkgTo+`"`, -1)
|
||||
content = strings.Replace(content, `"`+pkgFrom+`/`, `"`+pkgTo+`/`, -1)
|
||||
found = append(found, path)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(path, []byte(content), info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("ERROR", err.Error())
|
||||
}
|
||||
|
||||
if len(found) == 0 {
|
||||
fmt.Println("Nothing replaced")
|
||||
} else {
|
||||
fmt.Printf("Go imports total %d file replaced\n", len(found))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyDir(src string, dst string) error {
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !si.IsDir() {
|
||||
return fmt.Errorf("source is not a directory")
|
||||
}
|
||||
|
||||
err = os.MkdirAll(dst, si.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entries, err := ioutil.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
err = copyDir(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Skip symlinks.
|
||||
if entry.Mode()&os.ModeSymlink != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
err = copyFile(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) (err error) {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if e := out.Close(); e != nil {
|
||||
err = e
|
||||
}
|
||||
}()
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = out.Sync()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = os.Chmod(dst, si.Mode())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
143
cmd/podcli/ws.go
Normal file
143
cmd/podcli/ws.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/chzyer/readline"
|
||||
"github.com/fatih/color"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var origin string
|
||||
|
||||
func init() {
|
||||
wsCmd.Flags().StringVarP(&origin, "origin", "o", "", "websocket origin")
|
||||
rootCmd.AddCommand(wsCmd)
|
||||
}
|
||||
|
||||
var wsCmd = &cobra.Command{
|
||||
Use: `ws [address]`,
|
||||
Short: "Websocket client",
|
||||
Example: ` ws localhost:9898/ws/echo`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("address is required")
|
||||
}
|
||||
|
||||
address := args[0]
|
||||
if !strings.HasPrefix(address, "ws://") && !strings.HasPrefix(address, "wss://") {
|
||||
address = fmt.Sprintf("ws://%s", address)
|
||||
}
|
||||
|
||||
dest, err := url.Parse(address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if origin != "" {
|
||||
} else {
|
||||
originURL := *dest
|
||||
if dest.Scheme == "wss" {
|
||||
originURL.Scheme = "https"
|
||||
} else {
|
||||
originURL.Scheme = "http"
|
||||
}
|
||||
origin = originURL.String()
|
||||
}
|
||||
|
||||
err = connect(dest.String(), origin, &readline.Config{
|
||||
Prompt: "> ",
|
||||
})
|
||||
if err != nil {
|
||||
logger.Info("websocket closed", zap.Error(err))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
type session struct {
|
||||
ws *websocket.Conn
|
||||
rl *readline.Instance
|
||||
errChan chan error
|
||||
}
|
||||
|
||||
func connect(url, origin string, rlConf *readline.Config) error {
|
||||
headers := make(http.Header)
|
||||
headers.Add("Origin", origin)
|
||||
|
||||
ws, _, err := websocket.DefaultDialer.Dial(url, headers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rl, err := readline.NewEx(rlConf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rl.Close()
|
||||
|
||||
sess := &session{
|
||||
ws: ws,
|
||||
rl: rl,
|
||||
errChan: make(chan error),
|
||||
}
|
||||
|
||||
go sess.readConsole()
|
||||
go sess.readWebsocket()
|
||||
|
||||
return <-sess.errChan
|
||||
}
|
||||
|
||||
func (s *session) readConsole() {
|
||||
for {
|
||||
line, err := s.rl.Readline()
|
||||
if err != nil {
|
||||
s.errChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
err = s.ws.WriteMessage(websocket.TextMessage, []byte(line))
|
||||
if err != nil {
|
||||
s.errChan <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func bytesToFormattedHex(bytes []byte) string {
|
||||
text := hex.EncodeToString(bytes)
|
||||
return regexp.MustCompile("(..)").ReplaceAllString(text, "$1 ")
|
||||
}
|
||||
|
||||
func (s *session) readWebsocket() {
|
||||
rxSprintf := color.New(color.FgGreen).SprintfFunc()
|
||||
|
||||
for {
|
||||
msgType, buf, err := s.ws.ReadMessage()
|
||||
if err != nil {
|
||||
fmt.Fprint(s.rl.Stdout(), rxSprintf("< %s\n", err.Error()))
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
var text string
|
||||
switch msgType {
|
||||
case websocket.TextMessage:
|
||||
text = string(buf)
|
||||
case websocket.BinaryMessage:
|
||||
text = bytesToFormattedHex(buf)
|
||||
default:
|
||||
s.errChan <- fmt.Errorf("unknown websocket frame type: %d", msgType)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprint(s.rl.Stdout(), rxSprintf("< %s\n", text))
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,7 @@ func main() {
|
||||
viper.BindPFlags(fs)
|
||||
viper.RegisterAlias("backendUrl", "backend-url")
|
||||
hostname, _ := os.Hostname()
|
||||
viper.SetDefault("jwt-secret", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9")
|
||||
viper.Set("hostname", hostname)
|
||||
viper.Set("version", version.VERSION)
|
||||
viper.Set("revision", version.REVISION)
|
||||
|
||||
32
deploy/istio-system/chartmuseum-virtual-service.yaml
Normal file
32
deploy/istio-system/chartmuseum-virtual-service.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: grafana
|
||||
namespace: adm
|
||||
spec:
|
||||
hosts:
|
||||
- "helm.iowa.weavedx.com"
|
||||
gateways:
|
||||
- public-gateway.istio-system.svc.cluster.local
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: chartmuseum-chartmuseum
|
||||
timeout: 30s
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: kubeapps
|
||||
namespace: adm
|
||||
spec:
|
||||
hosts:
|
||||
- "kubeapps.iowa.weavedx.com"
|
||||
gateways:
|
||||
- public-gateway.istio-system.svc.cluster.local
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: kubeapps
|
||||
timeout: 30s
|
||||
19
deploy/istio-system/openfaas-canary-virtual-service.yaml
Normal file
19
deploy/istio-system/openfaas-canary-virtual-service.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: env
|
||||
namespace: openfaas-fn
|
||||
spec:
|
||||
hosts:
|
||||
- env
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: env
|
||||
weight: 90
|
||||
- destination:
|
||||
host: env-canary
|
||||
weight: 10
|
||||
timeout: 30s
|
||||
|
||||
36
docs/8-gh-actions.md
Normal file
36
docs/8-gh-actions.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# GitHub Actions
|
||||
|
||||
Create a private repository named `demo-app` on GitHub and navigate to Settings/Secrets and add the following secrets:
|
||||
|
||||
* `DOCKER_IMAGE` eg stefanprodan/demo-app
|
||||
* `DOCKER_USERNAME` eg stefanprodan
|
||||
* `DOCKER_PASSWORD` eg my-docker-hub-pass
|
||||
|
||||
Install podinfo CLI:
|
||||
|
||||
```bash
|
||||
go get -u github.com/stefanprodan/k8s-podinfo/cmd/podcli
|
||||
```
|
||||
|
||||
If you don't have golang installed go to the
|
||||
[release page](https://github.com/stefanprodan/k8s-podinfo/releases), download the latest podcli release and add it to your path.
|
||||
|
||||
Clone your private repository (preferable in your `$GOPATH`) and initialize podinfo.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/stefanprodan/demo-app
|
||||
cd demo-app
|
||||
|
||||
podcli code init demo-app --git-user=stefanprodan --version=v1.3.1
|
||||
```
|
||||
|
||||
The above command does the following:
|
||||
* downloads podinfo source code v1.3.1 from GitHub
|
||||
* replaces golang import with your git username and project name
|
||||
* commits and pushes the code to GitHub
|
||||
|
||||
When the code init command finishes, GitHub will test, build and push a Docker image
|
||||
`${DOCKER_IMAGE}:${GIT-BRANCH}-${GIT-SHORT-SHA}` to your Docker Hub account.
|
||||
|
||||
If you create a GitHub release a Docker image with the format `${DOCKER_IMAGE}:${GIT-TAG}` will be published to Docker Hub.
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
# OpenFaaS + Istio
|
||||
|
||||
### Install Istio
|
||||
|
||||
Download latest release:
|
||||
|
||||
```bash
|
||||
curl -L https://git.io/getLatestIstio | sh -
|
||||
```
|
||||
|
||||
Configure Istio with Prometheus, Jaeger and cert-manager:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
nodePort: false
|
||||
proxy:
|
||||
includeIPRanges: "10.28.0.0/14,10.7.240.0/20"
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
|
||||
sidecarInjectorWebhook:
|
||||
enabled: true
|
||||
enableNamespacesByDefault: false
|
||||
|
||||
gateways:
|
||||
enabled: true
|
||||
|
||||
grafana:
|
||||
enabled: true
|
||||
|
||||
prometheus:
|
||||
enabled: true
|
||||
|
||||
servicegraph:
|
||||
enabled: true
|
||||
|
||||
tracing:
|
||||
enabled: true
|
||||
|
||||
certmanager:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
Save the above file as `istio-of.yaml` and install Istio with Helm:
|
||||
|
||||
```bash
|
||||
helm upgrade --install istio ./install/kubernetes/helm/istio \
|
||||
--namespace=istio-system \
|
||||
-f ./istio-of.yaml
|
||||
```
|
||||
|
||||
### Configure Istio Gateway with LE certs
|
||||
|
||||
Istio Gateway:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: public-gateway
|
||||
namespace: istio-system
|
||||
spec:
|
||||
selector:
|
||||
istio: ingressgateway
|
||||
servers:
|
||||
- port:
|
||||
number: 80
|
||||
name: http
|
||||
protocol: HTTP
|
||||
hosts:
|
||||
- "*"
|
||||
tls:
|
||||
httpsRedirect: true
|
||||
- port:
|
||||
number: 443
|
||||
name: https
|
||||
protocol: HTTPS
|
||||
hosts:
|
||||
- "*"
|
||||
tls:
|
||||
mode: SIMPLE
|
||||
privateKey: /etc/istio/ingressgateway-certs/tls.key
|
||||
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
|
||||
```
|
||||
|
||||
Find the gateway public IP:
|
||||
|
||||
```bash
|
||||
IP=$(kubectl -n istio-system describe svc/istio-ingressgateway | grep 'Ingress' | awk '{print $NF}')
|
||||
```
|
||||
|
||||
Create a zone in GCP Cloud DNS with the following records:
|
||||
|
||||
```bash
|
||||
istio.example.com. A $IP
|
||||
*.istio.example.com. A $IP
|
||||
```
|
||||
|
||||
Create a service account with Cloud DNS admin role (replace `my-gcp-project` with your project ID):
|
||||
|
||||
```bash
|
||||
GCP_PROJECT=my-gcp-project
|
||||
|
||||
gcloud iam service-accounts create dns-admin \
|
||||
--display-name=dns-admin \
|
||||
--project=${GCP_PROJECT}
|
||||
|
||||
gcloud iam service-accounts keys create ./gcp-dns-admin.json \
|
||||
--iam-account=dns-admin@${GCP_PROJECT}.iam.gserviceaccount.com \
|
||||
--project=${GCP_PROJECT}
|
||||
|
||||
gcloud projects add-iam-policy-binding ${GCP_PROJECT} \
|
||||
--member=serviceAccount:dns-admin@${GCP_PROJECT}.iam.gserviceaccount.com \
|
||||
--role=roles/dns.admin
|
||||
```
|
||||
|
||||
Create a Kubernetes secret with the GCP Cloud DNS admin key:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic cert-manager-credentials \
|
||||
--from-file=./gcp-dns-admin.json \
|
||||
--namespace=istio-system
|
||||
```
|
||||
|
||||
LE issuer for GCP Cloud DNS:
|
||||
|
||||
```yaml
|
||||
apiVersion: certmanager.k8s.io/v1alpha1
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: letsencrypt-prod
|
||||
namespace: istio-system
|
||||
spec:
|
||||
acme:
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
email: email@example.com
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-prod
|
||||
dns01:
|
||||
providers:
|
||||
- name: cloud-dns
|
||||
clouddns:
|
||||
serviceAccountSecretRef:
|
||||
name: cert-manager-credentials
|
||||
key: gcp-dns-admin.json
|
||||
project: my-gcp-project
|
||||
```
|
||||
|
||||
Wildcard cert:
|
||||
|
||||
```yaml
|
||||
apiVersion: certmanager.k8s.io/v1alpha1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: istio-gateway
|
||||
namespace: istio-system
|
||||
spec:
|
||||
secretname: istio-ingressgateway-certs
|
||||
issuerRef:
|
||||
name: letsencrypt-prod
|
||||
commonName: "*.istio.example.com"
|
||||
dnsNames:
|
||||
- istio.example.com
|
||||
acme:
|
||||
config:
|
||||
- dns01:
|
||||
provider: cloud-dns
|
||||
domains:
|
||||
- "*.istio.example.com"
|
||||
- "istio.example.com"
|
||||
```
|
||||
|
||||
### Configure OpenFaaS
|
||||
|
||||
Create the OpenFaaS namespaces:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
istio-injection: enabled
|
||||
name: openfaas
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
istio-injection: enabled
|
||||
name: openfaas-fn
|
||||
```
|
||||
|
||||
Create an Istio virtual service for OpenFaaS Gateway:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: gateway
|
||||
namespace: openfaas
|
||||
spec:
|
||||
hosts:
|
||||
- "openfaas.istio.example.com"
|
||||
gateways:
|
||||
- public-gateway.istio-system.svc.cluster.local
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: gateway
|
||||
timeout: 30s
|
||||
```
|
||||
|
||||
Enable mTLS on `openfaas` namespace:
|
||||
|
||||
```yaml
|
||||
apiVersion: authentication.istio.io/v1alpha1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: default
|
||||
namespace: openfaas
|
||||
spec:
|
||||
peers:
|
||||
- mtls: {}
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: DestinationRule
|
||||
metadata:
|
||||
name: default
|
||||
namespace: openfaas
|
||||
spec:
|
||||
host: "*.openfaas.svc.cluster.local"
|
||||
trafficPolicy:
|
||||
tls:
|
||||
mode: ISTIO_MUTUAL
|
||||
```
|
||||
|
||||
Allow plaintext traffic to OpenFaaS Gateway:
|
||||
|
||||
```yaml
|
||||
apiVersion: authentication.istio.io/v1alpha1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: permissive
|
||||
namespace: openfaas
|
||||
spec:
|
||||
targets:
|
||||
- name: gateway
|
||||
peers:
|
||||
- mtls:
|
||||
mode: PERMISSIVE
|
||||
```
|
||||
|
||||
Enable mTLS on `openfaas-fn` namespace:
|
||||
|
||||
```yaml
|
||||
apiVersion: authentication.istio.io/v1alpha1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: default
|
||||
namespace: openfaas-fn
|
||||
spec:
|
||||
peers:
|
||||
- mtls: {}
|
||||
---
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: DestinationRule
|
||||
metadata:
|
||||
name: default
|
||||
namespace: openfaas-fn
|
||||
spec:
|
||||
host: "*.openfaas-fn.svc.cluster.local"
|
||||
trafficPolicy:
|
||||
tls:
|
||||
mode: ISTIO_MUTUAL
|
||||
```
|
||||
|
||||
Deny access to OpenFaaS core services from the `openfaas-fn` namespace except for system functions:
|
||||
|
||||
```yaml
|
||||
apiVersion: config.istio.io/v1alpha2
|
||||
kind: denier
|
||||
metadata:
|
||||
name: denyhandler
|
||||
namespace: openfaas
|
||||
spec:
|
||||
status:
|
||||
code: 7
|
||||
message: Not allowed
|
||||
---
|
||||
apiVersion: config.istio.io/v1alpha2
|
||||
kind: checknothing
|
||||
metadata:
|
||||
name: denyrequest
|
||||
namespace: openfaas
|
||||
spec:
|
||||
---
|
||||
apiVersion: config.istio.io/v1alpha2
|
||||
kind: rule
|
||||
metadata:
|
||||
name: denyopenfaasfn
|
||||
namespace: openfaas
|
||||
spec:
|
||||
match: destination.namespace == "openfaas" && source.namespace == "openfaas-fn" && source.labels["role"] != "openfaas-system"
|
||||
actions:
|
||||
- handler: denyhandler.denier
|
||||
instances: [ denyrequest.checknothing ]
|
||||
```
|
||||
|
||||
Deny access to functions except for OpenFaaS core services:
|
||||
|
||||
```yaml
|
||||
apiVersion: config.istio.io/v1alpha2
|
||||
kind: denier
|
||||
metadata:
|
||||
name: denyhandler
|
||||
namespace: openfaas-fn
|
||||
spec:
|
||||
status:
|
||||
code: 7
|
||||
message: Not allowed
|
||||
---
|
||||
apiVersion: config.istio.io/v1alpha2
|
||||
kind: checknothing
|
||||
metadata:
|
||||
name: denyrequest
|
||||
namespace: openfaas-fn
|
||||
spec:
|
||||
---
|
||||
apiVersion: config.istio.io/v1alpha2
|
||||
kind: rule
|
||||
metadata:
|
||||
name: denyopenfaasfn
|
||||
namespace: openfaas-fn
|
||||
spec:
|
||||
match: destination.namespace == "openfaas-fn" && source.namespace != "openfaas" && source.labels["role"] != "openfaas-system"
|
||||
actions:
|
||||
- handler: denyhandler.denier
|
||||
instances: [ denyrequest.checknothing ]
|
||||
```
|
||||
|
||||
### Install OpenFaaS
|
||||
|
||||
Add the OpenFaaS `helm` chart:
|
||||
|
||||
```bash
|
||||
$ helm repo add openfaas https://openfaas.github.io/faas-netes/
|
||||
```
|
||||
|
||||
Create a secret named `basic-auth` in the `openfaas` namespace:
|
||||
|
||||
```bash
|
||||
# generate a random password
|
||||
password=$(head -c 12 /dev/urandom | shasum| cut -d' ' -f1)
|
||||
|
||||
kubectl -n openfaas create secret generic basic-auth \
|
||||
--from-literal=basic-auth-user=admin \
|
||||
--from-literal=basic-auth-password=$password
|
||||
```
|
||||
|
||||
Install OpenFaaS with Helm:
|
||||
|
||||
```bash
|
||||
helm upgrade --install openfaas ./chart/openfaas \
|
||||
--namespace openfaas \
|
||||
--set functionNamespace=openfaas-fn \
|
||||
--set operator.create=true \
|
||||
--set securityContext=true \
|
||||
--set basic_auth=true \
|
||||
--set exposeServices=false \
|
||||
--set operator.createCRD=true \
|
||||
--set gateway.image=stefanprodan/gateway:istio5
|
||||
```
|
||||
|
||||
Wait for OpenFaaS Gateway to come online:
|
||||
|
||||
```bash
|
||||
watch curl -v http://openfaas.istio.example.com/heathz
|
||||
```
|
||||
|
||||
Save your credentials in faas-cli store:
|
||||
|
||||
```bash
|
||||
echo $password | faas-cli login -g https://openfaas.istio.example.com -u admin --password-stdin
|
||||
```
|
||||
|
||||
Binary file not shown.
Binary file not shown.
130
docs/index.yaml
130
docs/index.yaml
@@ -3,9 +3,9 @@ entries:
|
||||
ambassador:
|
||||
- apiVersion: v1
|
||||
appVersion: 0.29.0
|
||||
created: 2018-09-08T11:36:06.780759116+03:00
|
||||
created: 2018-10-27T11:49:54.792088+03:00
|
||||
description: A Helm chart for Datawire Ambassador
|
||||
digest: e47efa287956046b96957e9e24c3d5d939992f557563c29e12ed92d43302be6d
|
||||
digest: f82505d3abaff6d039e189787e22e44dc4a9fde81976bf7771ed664aeabc75a1
|
||||
engine: gotpl
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
@@ -19,9 +19,9 @@ entries:
|
||||
grafana:
|
||||
- apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
created: 2018-09-08T11:36:06.781595666+03:00
|
||||
created: 2018-10-27T11:49:54.79284+03:00
|
||||
description: A Helm chart for Kubernetes
|
||||
digest: 414ebcc86d50191f8b9f44320c5b24f304a28ad8fb441319c055a9c3fef9018f
|
||||
digest: ee244448260eda8029a182d603715c48c97b1cc00c376d84f67a2e0b0653ed50
|
||||
name: grafana
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/grafana-0.1.0.tgz
|
||||
@@ -29,9 +29,9 @@ entries:
|
||||
loadtest:
|
||||
- apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
created: 2018-09-08T11:36:06.781794881+03:00
|
||||
created: 2018-10-27T11:49:54.793039+03:00
|
||||
description: Hey load test Helm chart for Kubernetes
|
||||
digest: 7689a7beedce35fef70ca6659d060a3e37c55d9a6c3af0941477d76e2f1683c7
|
||||
digest: 413fbb941e72ebe8d94f2ce1ae42946aa68d88276e969ed2f12595af8da1cbf4
|
||||
name: loadtest
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/loadtest-0.1.0.tgz
|
||||
@@ -39,17 +39,81 @@ entries:
|
||||
ngrok:
|
||||
- apiVersion: v1
|
||||
appVersion: "1.0"
|
||||
created: 2018-09-08T11:36:06.782060752+03:00
|
||||
created: 2018-10-27T11:49:54.793328+03:00
|
||||
description: A Ngrok Helm chart for Kubernetes
|
||||
digest: fc044fd5e97cda2d17b01ed82a4cac816367052d6f646079f16573220c4723b4
|
||||
digest: 5678de7c8aac246df507f40b3f4f8fd6d06f4447e636398819a232dd26e1fc41
|
||||
name: ngrok
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/ngrok-0.1.0.tgz
|
||||
version: 0.1.0
|
||||
podinfo:
|
||||
- apiVersion: v1
|
||||
appVersion: 1.3.1
|
||||
created: 2018-10-27T11:49:54.804223+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: d863e2511ec5f0a7705ae12886aa9cfb40ab1c07d2ab6afd69bba69b39abcf21
|
||||
engine: gotpl
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: podinfo
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-1.3.1.tgz
|
||||
version: 1.3.1
|
||||
- apiVersion: v1
|
||||
appVersion: 1.3.0
|
||||
created: 2018-10-27T11:49:54.803825+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: 7111b868a11014ab56da11b7edbea9ce0d1a483500969252f66c9ae1943bac67
|
||||
engine: gotpl
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: podinfo
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-1.3.0.tgz
|
||||
version: 1.3.0
|
||||
- apiVersion: v1
|
||||
appVersion: 1.2.1
|
||||
created: 2018-10-27T11:49:54.802868+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: c750c1d4a7606a06cd89ae4433431c7e3ecf2ccc9a0e5f6baa26095397bd72da
|
||||
engine: gotpl
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: podinfo
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-1.2.1.tgz
|
||||
version: 1.2.1
|
||||
- apiVersion: v1
|
||||
appVersion: 1.2.0
|
||||
created: 2018-10-27T11:49:54.80169+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: 24460e15e6da77106eb5212cd683dc2c1d4404b927be6b9f0c89433ba865722e
|
||||
engine: gotpl
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: podinfo
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-1.2.0.tgz
|
||||
version: 1.2.0
|
||||
- apiVersion: v1
|
||||
appVersion: 1.1.0
|
||||
created: 2018-09-08T11:36:06.78680158+03:00
|
||||
created: 2018-10-27T11:49:54.800849+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: 973d60c629d7ae476776098ad6b654d78d91f91b3faa8bc016b94c73c42be094
|
||||
engine: gotpl
|
||||
@@ -65,7 +129,7 @@ entries:
|
||||
version: 1.1.0
|
||||
- apiVersion: v1
|
||||
appVersion: 1.0.0
|
||||
created: 2018-09-08T11:36:06.786342356+03:00
|
||||
created: 2018-10-27T11:49:54.799786+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: 82068727ba5b552341b14a980e954e27a8517f0ef76aab314c160b0f075e6de4
|
||||
engine: gotpl
|
||||
@@ -81,7 +145,7 @@ entries:
|
||||
version: 1.0.0
|
||||
- apiVersion: v1
|
||||
appVersion: 0.6.0
|
||||
created: 2018-09-08T11:36:06.785478988+03:00
|
||||
created: 2018-10-27T11:49:54.798697+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: bd25a710eddb3985d3bd921a11022b5c68a04d37cf93a1a4aab17eeda35aa2f8
|
||||
engine: gotpl
|
||||
@@ -97,7 +161,7 @@ entries:
|
||||
version: 0.2.2
|
||||
- apiVersion: v1
|
||||
appVersion: 0.5.1
|
||||
created: 2018-09-08T11:36:06.784529082+03:00
|
||||
created: 2018-10-27T11:49:54.797853+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: 631ca3e2db5553541a50b625f538e6a1f2a103c13aa8148fdd38baf2519e5235
|
||||
engine: gotpl
|
||||
@@ -113,7 +177,7 @@ entries:
|
||||
version: 0.2.1
|
||||
- apiVersion: v1
|
||||
appVersion: 0.5.0
|
||||
created: 2018-09-08T11:36:06.783626713+03:00
|
||||
created: 2018-10-27T11:49:54.797046+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: dfe7cf44aef0d170549918b00966422a07e7611f9d0081fb34f5b5beb0641c00
|
||||
engine: gotpl
|
||||
@@ -129,7 +193,7 @@ entries:
|
||||
version: 0.2.0
|
||||
- apiVersion: v1
|
||||
appVersion: 0.3.0
|
||||
created: 2018-09-08T11:36:06.782841845+03:00
|
||||
created: 2018-10-27T11:49:54.796003+03:00
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
digest: 4865a2d8b269cf453935cda9661c2efb82c16411471f8c11221a6d03d9bb58b1
|
||||
engine: gotpl
|
||||
@@ -144,9 +208,41 @@ entries:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-0.1.0.tgz
|
||||
version: 0.1.0
|
||||
podinfo-istio:
|
||||
- apiVersion: v1
|
||||
appVersion: 1.2.1
|
||||
created: 2018-10-27T11:49:54.808061+03:00
|
||||
description: Podinfo Helm chart for Istio
|
||||
digest: 4f47d5373ee5a8cec6bacb61cdd1ac5bad650a62381721ea0178a568ead2b539
|
||||
engine: gotpl
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: podinfo-istio
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-istio-1.2.1.tgz
|
||||
version: 1.2.1
|
||||
- apiVersion: v1
|
||||
appVersion: 1.2.0
|
||||
created: 2018-10-27T11:49:54.807262+03:00
|
||||
description: Podinfo Helm chart for Istio
|
||||
digest: 8115e72f232f82eb3e6da1965364cfede7c069f95a627dddac45cfbe6cb90dc4
|
||||
engine: gotpl
|
||||
home: https://github.com/stefanprodan/k8s-podinfo
|
||||
maintainers:
|
||||
- email: stefanprodan@users.noreply.github.com
|
||||
name: stefanprodan
|
||||
name: podinfo-istio
|
||||
sources:
|
||||
- https://github.com/stefanprodan/k8s-podinfo
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-istio-1.2.0.tgz
|
||||
version: 1.2.0
|
||||
- apiVersion: v1
|
||||
appVersion: 1.1.0
|
||||
created: 2018-09-08T11:36:06.789393642+03:00
|
||||
created: 2018-10-27T11:49:54.806166+03:00
|
||||
description: Podinfo Helm chart for Istio
|
||||
digest: bcceb63ff780a8f0ba0b30997040e4e82170f9cce17c26ec817648ed024c83f5
|
||||
engine: gotpl
|
||||
@@ -162,7 +258,7 @@ entries:
|
||||
version: 0.2.0
|
||||
- apiVersion: v1
|
||||
appVersion: 0.6.0
|
||||
created: 2018-09-08T11:36:06.788591612+03:00
|
||||
created: 2018-10-27T11:49:54.805124+03:00
|
||||
description: Podinfo Helm chart for Istio
|
||||
digest: f12f8aa1eca1328e9eaa30bd757f6ed3ff97205e2bf016a47265bc2de6a63d8f
|
||||
engine: gotpl
|
||||
@@ -176,4 +272,4 @@ entries:
|
||||
urls:
|
||||
- https://stefanprodan.github.io/k8s-podinfo/podinfo-istio-0.1.0.tgz
|
||||
version: 0.1.0
|
||||
generated: 2018-09-08T11:36:06.780217936+03:00
|
||||
generated: 2018-10-27T11:49:54.791526+03:00
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
docs/podinfo-1.2.0.tgz
Normal file
BIN
docs/podinfo-1.2.0.tgz
Normal file
Binary file not shown.
BIN
docs/podinfo-1.2.1.tgz
Normal file
BIN
docs/podinfo-1.2.1.tgz
Normal file
Binary file not shown.
BIN
docs/podinfo-1.3.0.tgz
Normal file
BIN
docs/podinfo-1.3.0.tgz
Normal file
Binary file not shown.
BIN
docs/podinfo-1.3.1.tgz
Normal file
BIN
docs/podinfo-1.3.1.tgz
Normal file
Binary file not shown.
BIN
docs/podinfo-istio-1.2.0.tgz
Normal file
BIN
docs/podinfo-istio-1.2.0.tgz
Normal file
Binary file not shown.
BIN
docs/podinfo-istio-1.2.1.tgz
Normal file
BIN
docs/podinfo-istio-1.2.1.tgz
Normal file
Binary file not shown.
@@ -3,8 +3,8 @@ package api
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDelayHandler(t *testing.T) {
|
||||
|
||||
@@ -3,8 +3,8 @@ package api
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEchoHandler(t *testing.T) {
|
||||
|
||||
82
pkg/api/echows.go
Normal file
82
pkg/api/echows.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var wsCon = websocket.Upgrader{}
|
||||
|
||||
// Test: go run ./cmd/podcli/* ws localhost:9898/ws/echo
|
||||
func (s *Server) echoWsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := wsCon.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
s.logger.Warn("websocket upgrade error", zap.Error(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
defer c.Close()
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
in := make(chan interface{})
|
||||
defer close(in)
|
||||
go s.writeWs(c, in)
|
||||
go s.sendHostWs(c, in, done)
|
||||
for {
|
||||
_, message, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "close") {
|
||||
s.logger.Warn("websocket read error", zap.Error(err))
|
||||
}
|
||||
break
|
||||
}
|
||||
var response = struct {
|
||||
Time time.Time `json:"ts"`
|
||||
Message string `json:"msg"`
|
||||
}{
|
||||
Time: time.Now(),
|
||||
Message: string(message),
|
||||
}
|
||||
in <- response
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) sendHostWs(ws *websocket.Conn, in chan interface{}, done chan struct{}) {
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
var status = struct {
|
||||
Time time.Time `json:"ts"`
|
||||
Host string `json:"server"`
|
||||
}{
|
||||
Time: time.Now(),
|
||||
Host: s.config.Hostname,
|
||||
}
|
||||
in <- status
|
||||
case <-done:
|
||||
s.logger.Debug("websocket exit")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) writeWs(ws *websocket.Conn, in chan interface{}) {
|
||||
for {
|
||||
select {
|
||||
case msg := <-in:
|
||||
if err := ws.WriteJSON(msg); err != nil {
|
||||
if !strings.Contains(err.Error(), "close") {
|
||||
s.logger.Warn("websocket write error", zap.Error(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
pkg/api/env.go
Normal file
11
pkg/api/env.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"os"
|
||||
)
|
||||
|
||||
func (s *Server) envHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.JSONResponse(w, r, os.Environ())
|
||||
}
|
||||
35
pkg/api/env_test.go
Normal file
35
pkg/api/env_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"regexp"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEnvHandler(t *testing.T) {
|
||||
req, err := http.NewRequest("GET", "/api/env", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
srv := NewMockServer()
|
||||
handler := http.HandlerFunc(srv.infoHandler)
|
||||
|
||||
handler.ServeHTTP(rr, req)
|
||||
|
||||
// Check the status code is what we expect.
|
||||
if status := rr.Code; status != http.StatusOK {
|
||||
t.Errorf("handler returned wrong status code: got %v want %v",
|
||||
status, http.StatusOK)
|
||||
}
|
||||
|
||||
// Check the response body is what we expect.
|
||||
expected := ".*hostname.*"
|
||||
r := regexp.MustCompile(expected)
|
||||
if !r.MatchString(rr.Body.String()) {
|
||||
t.Fatalf("handler returned unexpected body:\ngot \n%v \nwant \n%s",
|
||||
rr.Body.String(), expected)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
)
|
||||
|
||||
func (s *Server) echoHeadersHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -3,8 +3,8 @@ package api
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"github.com/gorilla/mux"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func NewMockServer() *Server {
|
||||
|
||||
@@ -2,7 +2,6 @@ package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
)
|
||||
|
||||
func (s *Server) panicHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/stefanprodan/k8s-podinfo/pkg/fscache"
|
||||
@@ -36,6 +38,7 @@ type Config struct {
|
||||
Hostname string `mapstructure:"hostname"`
|
||||
RandomDelay bool `mapstructure:"random-delay"`
|
||||
RandomError bool `mapstructure:"random-error"`
|
||||
JWTSecret string `mapstructure:"jwt-secret"`
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
@@ -61,6 +64,7 @@ func (s *Server) registerHandlers() {
|
||||
s.router.HandleFunc("/", s.infoHandler).Methods("GET")
|
||||
s.router.HandleFunc("/version", s.versionHandler).Methods("GET")
|
||||
s.router.HandleFunc("/echo", s.echoHandler).Methods("POST")
|
||||
s.router.HandleFunc("/env", s.envHandler).Methods("GET", "POST")
|
||||
s.router.HandleFunc("/headers", s.echoHeadersHandler).Methods("GET", "POST")
|
||||
s.router.HandleFunc("/delay/{wait:[0-9]+}", s.delayHandler).Methods("GET").Name("delay")
|
||||
s.router.HandleFunc("/healthz", s.healthzHandler).Methods("GET")
|
||||
@@ -72,8 +76,11 @@ func (s *Server) registerHandlers() {
|
||||
s.router.HandleFunc("/store", s.storeWriteHandler).Methods("POST")
|
||||
s.router.HandleFunc("/store/{hash}", s.storeReadHandler).Methods("GET").Name("store")
|
||||
s.router.HandleFunc("/configs", s.configReadHandler).Methods("GET")
|
||||
s.router.HandleFunc("/token", s.tokenGenerateHandler).Methods("POST")
|
||||
s.router.HandleFunc("/token/validate", s.tokenValidateHandler).Methods("GET")
|
||||
s.router.HandleFunc("/api/info", s.infoHandler).Methods("GET")
|
||||
s.router.HandleFunc("/api/echo", s.echoHandler).Methods("POST")
|
||||
s.router.HandleFunc("/ws/echo", s.echoWsHandler)
|
||||
}
|
||||
|
||||
func (s *Server) registerMiddlewares() {
|
||||
@@ -138,10 +145,11 @@ func (s *Server) ListenAndServe(stopCh <-chan struct{}) {
|
||||
|
||||
s.logger.Info("Shutting down HTTP server", zap.Duration("timeout", s.config.HttpServerShutdownTimeout))
|
||||
|
||||
// wait for Kubernetes readiness probe
|
||||
// to remove this instance from the load balancer
|
||||
// the readiness check interval must lower than the timeout
|
||||
//time.Sleep(s.config.HttpServerShutdownTimeout)
|
||||
// wait for Kubernetes readiness probe to remove this instance from the load balancer
|
||||
// the readiness check interval must be lower than the timeout
|
||||
if viper.GetString("level") != "debug" {
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
// attempt graceful shutdown
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
|
||||
@@ -16,5 +16,5 @@ func (s *Server) statusHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
s.JSONResponseCode(w, r, map[string]int{"status": code}, code)
|
||||
s.JSONResponseCode(w, r, map[string]int{"status": code}, code)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"github.com/gorilla/mux"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (s *Server) storeWriteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -26,7 +26,7 @@ func (s *Server) storeWriteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.ErrorResponse(w, r, "writing file failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
s.JSONResponseCode(w, r, map[string]string{"hash": hash}, http.StatusAccepted)
|
||||
s.JSONResponseCode(w, r, map[string]string{"hash": hash}, http.StatusAccepted)
|
||||
}
|
||||
|
||||
func (s *Server) storeReadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
102
pkg/api/token.go
Normal file
102
pkg/api/token.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type jwtCustomClaims struct {
|
||||
Name string `json:"name"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
func (s *Server) tokenGenerateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
s.logger.Error("reading the request body failed", zap.Error(err))
|
||||
s.ErrorResponse(w, r, "invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
user := "anonymous"
|
||||
if len(body) > 0 {
|
||||
user = string(body)
|
||||
}
|
||||
|
||||
claims := &jwtCustomClaims{
|
||||
user,
|
||||
jwt.StandardClaims{
|
||||
Issuer: "podinfo",
|
||||
ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
t, err := token.SignedString([]byte(s.config.JWTSecret))
|
||||
if err != nil {
|
||||
s.ErrorResponse(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var result = struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}{
|
||||
Token: t,
|
||||
ExpiresAt: time.Unix(claims.StandardClaims.ExpiresAt, 0),
|
||||
}
|
||||
|
||||
s.JSONResponse(w, r, result)
|
||||
}
|
||||
|
||||
// Get: JWT=$(curl -s -d 'test' localhost:9898/token | jq -r .token)
|
||||
// Post: curl -H "Authorization: Bearer ${JWT}" localhost:9898/token/validate
|
||||
func (s *Server) tokenValidateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
authorizationHeader := r.Header.Get("authorization")
|
||||
if authorizationHeader == "" {
|
||||
s.ErrorResponse(w, r, "authorization bearer header required", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
bearerToken := strings.Split(authorizationHeader, " ")
|
||||
if len(bearerToken) != 2 || strings.ToLower(bearerToken[0]) != "bearer" {
|
||||
s.ErrorResponse(w, r, "authorization bearer header required", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
claims := jwtCustomClaims{}
|
||||
token, err := jwt.ParseWithClaims(bearerToken[1], &claims, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("invalid signing method")
|
||||
}
|
||||
return []byte(s.config.JWTSecret), nil
|
||||
})
|
||||
if err != nil {
|
||||
s.ErrorResponse(w, r, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if token.Valid {
|
||||
if claims.StandardClaims.Issuer != "podinfo" {
|
||||
s.ErrorResponse(w, r, "invalid issuer", http.StatusUnauthorized)
|
||||
} else {
|
||||
var result = struct {
|
||||
TokenName string `json:"token_name"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}{
|
||||
TokenName: claims.Name,
|
||||
ExpiresAt: time.Unix(claims.StandardClaims.ExpiresAt, 0),
|
||||
}
|
||||
s.JSONResponse(w, r, result)
|
||||
}
|
||||
} else {
|
||||
s.ErrorResponse(w, r, "Invalid authorization token", http.StatusUnauthorized)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package version
|
||||
|
||||
var VERSION = "1.1.1"
|
||||
var VERSION = "1.3.1"
|
||||
var REVISION = "unknown"
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
if (self.info.version) {
|
||||
if (self.info.version != data.version) {
|
||||
console.log("New version", data.version)
|
||||
window.location.reload()
|
||||
//window.location.reload()
|
||||
}
|
||||
}
|
||||
self.info = data
|
||||
|
||||
@@ -1,37 +1,4 @@
|
||||
// Copyright © 2015 Steve Francia <spf@spf13.com>.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Parts inspired by https://github.com/ryanuber/go-license
|
||||
|
||||
package cmd
|
||||
|
||||
func initApache2() {
|
||||
Licenses["apache"] = License{
|
||||
Name: "Apache 2.0",
|
||||
PossibleMatches: []string{"apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"},
|
||||
Header: `
|
||||
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.`,
|
||||
Text: `
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
@@ -233,6 +200,3 @@ limitations under the License.`,
|
||||
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.
|
||||
`,
|
||||
}
|
||||
}
|
||||
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.
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
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())
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
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)
|
||||
}
|
||||
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
|
||||
}
|
||||
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)))
|
||||
}
|
||||
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 structure.
|
||||
//
|
||||
// // 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
|
||||
}
|
||||
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()
|
||||
)
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
}}
|
||||
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
|
||||
}
|
||||
}
|
||||
}}
|
||||
37
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent.go
generated
vendored
Normal file
37
vendor/github.com/aws/aws-sdk-go/aws/corehandlers/user_agent.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package corehandlers
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// SDKVersionUserAgentHandler is a request handler for adding the SDK Version
|
||||
// to the user agent.
|
||||
var SDKVersionUserAgentHandler = request.NamedHandler{
|
||||
Name: "core.SDKVersionUserAgentHandler",
|
||||
Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion,
|
||||
runtime.Version(), runtime.GOOS, runtime.GOARCH),
|
||||
}
|
||||
|
||||
const execEnvVar = `AWS_EXECUTION_ENV`
|
||||
const execEnvUAKey = `exec_env`
|
||||
|
||||
// AddHostExecEnvUserAgentHander is a request handler appending the SDK's
|
||||
// execution environment to the user agent.
|
||||
//
|
||||
// If the environment variable AWS_EXECUTION_ENV is set, its value will be
|
||||
// appended to the user agent string.
|
||||
var AddHostExecEnvUserAgentHander = request.NamedHandler{
|
||||
Name: "core.AddHostExecEnvUserAgentHander",
|
||||
Fn: func(r *request.Request) {
|
||||
v := os.Getenv(execEnvVar)
|
||||
if len(v) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
request.AddToUserAgent(r, execEnvUAKey+"/"+v)
|
||||
},
|
||||
}
|
||||
102
vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go
generated
vendored
Normal file
102
vendor/github.com/aws/aws-sdk-go/aws/credentials/chain_provider.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
package credentials
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoValidProvidersFoundInChain Is returned when there are no valid
|
||||
// providers in the ChainProvider.
|
||||
//
|
||||
// This has been deprecated. For verbose error messaging set
|
||||
// aws.Config.CredentialsChainVerboseErrors to true
|
||||
//
|
||||
// @readonly
|
||||
ErrNoValidProvidersFoundInChain = awserr.New("NoCredentialProviders",
|
||||
`no valid providers in chain. Deprecated.
|
||||
For verbose messaging see aws.Config.CredentialsChainVerboseErrors`,
|
||||
nil)
|
||||
)
|
||||
|
||||
// A ChainProvider will search for a provider which returns credentials
|
||||
// and cache that provider until Retrieve is called again.
|
||||
//
|
||||
// The ChainProvider provides a way of chaining multiple providers together
|
||||
// which will pick the first available using priority order of the Providers
|
||||
// in the list.
|
||||
//
|
||||
// If none of the Providers retrieve valid credentials Value, ChainProvider's
|
||||
// Retrieve() will return the error ErrNoValidProvidersFoundInChain.
|
||||
//
|
||||
// If a Provider is found which returns valid credentials Value ChainProvider
|
||||
// will cache that Provider for all calls to IsExpired(), until Retrieve is
|
||||
// called again.
|
||||
//
|
||||
// Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider.
|
||||
// In this example EnvProvider will first check if any credentials are available
|
||||
// via the environment variables. If there are none ChainProvider will check
|
||||
// the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider
|
||||
// does not return any credentials ChainProvider will return the error
|
||||
// ErrNoValidProvidersFoundInChain
|
||||
//
|
||||
// creds := credentials.NewChainCredentials(
|
||||
// []credentials.Provider{
|
||||
// &credentials.EnvProvider{},
|
||||
// &ec2rolecreds.EC2RoleProvider{
|
||||
// Client: ec2metadata.New(sess),
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// // Usage of ChainCredentials with aws.Config
|
||||
// svc := ec2.New(session.Must(session.NewSession(&aws.Config{
|
||||
// Credentials: creds,
|
||||
// })))
|
||||
//
|
||||
type ChainProvider struct {
|
||||
Providers []Provider
|
||||
curr Provider
|
||||
VerboseErrors bool
|
||||
}
|
||||
|
||||
// NewChainCredentials returns a pointer to a new Credentials object
|
||||
// wrapping a chain of providers.
|
||||
func NewChainCredentials(providers []Provider) *Credentials {
|
||||
return NewCredentials(&ChainProvider{
|
||||
Providers: append([]Provider{}, providers...),
|
||||
})
|
||||
}
|
||||
|
||||
// Retrieve returns the credentials value or error if no provider returned
|
||||
// without error.
|
||||
//
|
||||
// If a provider is found it will be cached and any calls to IsExpired()
|
||||
// will return the expired state of the cached provider.
|
||||
func (c *ChainProvider) Retrieve() (Value, error) {
|
||||
var errs []error
|
||||
for _, p := range c.Providers {
|
||||
creds, err := p.Retrieve()
|
||||
if err == nil {
|
||||
c.curr = p
|
||||
return creds, nil
|
||||
}
|
||||
errs = append(errs, err)
|
||||
}
|
||||
c.curr = nil
|
||||
|
||||
var err error
|
||||
err = ErrNoValidProvidersFoundInChain
|
||||
if c.VerboseErrors {
|
||||
err = awserr.NewBatchError("NoCredentialProviders", "no valid providers in chain", errs)
|
||||
}
|
||||
return Value{}, err
|
||||
}
|
||||
|
||||
// IsExpired will returned the expired state of the currently cached provider
|
||||
// if there is one. If there is no current provider, true will be returned.
|
||||
func (c *ChainProvider) IsExpired() bool {
|
||||
if c.curr != nil {
|
||||
return c.curr.IsExpired()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
259
vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go
generated
vendored
Normal file
259
vendor/github.com/aws/aws-sdk-go/aws/credentials/credentials.go
generated
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
// Package credentials provides credential retrieval and management
|
||||
//
|
||||
// The Credentials is the primary method of getting access to and managing
|
||||
// credentials Values. Using dependency injection retrieval of the credential
|
||||
// values is handled by a object which satisfies the Provider interface.
|
||||
//
|
||||
// By default the Credentials.Get() will cache the successful result of a
|
||||
// Provider's Retrieve() until Provider.IsExpired() returns true. At which
|
||||
// point Credentials will call Provider's Retrieve() to get new credential Value.
|
||||
//
|
||||
// The Provider is responsible for determining when credentials Value have expired.
|
||||
// It is also important to note that Credentials will always call Retrieve the
|
||||
// first time Credentials.Get() is called.
|
||||
//
|
||||
// Example of using the environment variable credentials.
|
||||
//
|
||||
// creds := credentials.NewEnvCredentials()
|
||||
//
|
||||
// // Retrieve the credentials value
|
||||
// credValue, err := creds.Get()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
//
|
||||
// Example of forcing credentials to expire and be refreshed on the next Get().
|
||||
// This may be helpful to proactively expire credentials and refresh them sooner
|
||||
// than they would naturally expire on their own.
|
||||
//
|
||||
// creds := credentials.NewCredentials(&ec2rolecreds.EC2RoleProvider{})
|
||||
// creds.Expire()
|
||||
// credsValue, err := creds.Get()
|
||||
// // New credentials will be retrieved instead of from cache.
|
||||
//
|
||||
//
|
||||
// Custom Provider
|
||||
//
|
||||
// Each Provider built into this package also provides a helper method to generate
|
||||
// a Credentials pointer setup with the provider. To use a custom Provider just
|
||||
// create a type which satisfies the Provider interface and pass it to the
|
||||
// NewCredentials method.
|
||||
//
|
||||
// type MyProvider struct{}
|
||||
// func (m *MyProvider) Retrieve() (Value, error) {...}
|
||||
// func (m *MyProvider) IsExpired() bool {...}
|
||||
//
|
||||
// creds := credentials.NewCredentials(&MyProvider{})
|
||||
// credValue, err := creds.Get()
|
||||
//
|
||||
package credentials
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// AnonymousCredentials is an empty Credential object that can be used as
|
||||
// dummy placeholder credentials for requests that do not need signed.
|
||||
//
|
||||
// This Credentials can be used to configure a service to not sign requests
|
||||
// when making service API calls. For example, when accessing public
|
||||
// s3 buckets.
|
||||
//
|
||||
// svc := s3.New(session.Must(session.NewSession(&aws.Config{
|
||||
// Credentials: credentials.AnonymousCredentials,
|
||||
// })))
|
||||
// // Access public S3 buckets.
|
||||
//
|
||||
// @readonly
|
||||
var AnonymousCredentials = NewStaticCredentials("", "", "")
|
||||
|
||||
// A Value is the AWS credentials value for individual credential fields.
|
||||
type Value struct {
|
||||
// AWS Access key ID
|
||||
AccessKeyID string
|
||||
|
||||
// AWS Secret Access Key
|
||||
SecretAccessKey string
|
||||
|
||||
// AWS Session Token
|
||||
SessionToken string
|
||||
|
||||
// Provider used to get credentials
|
||||
ProviderName string
|
||||
}
|
||||
|
||||
// A Provider is the interface for any component which will provide credentials
|
||||
// Value. A provider is required to manage its own Expired state, and what to
|
||||
// be expired means.
|
||||
//
|
||||
// The Provider should not need to implement its own mutexes, because
|
||||
// that will be managed by Credentials.
|
||||
type Provider interface {
|
||||
// Retrieve returns nil if it successfully retrieved the value.
|
||||
// Error is returned if the value were not obtainable, or empty.
|
||||
Retrieve() (Value, error)
|
||||
|
||||
// IsExpired returns if the credentials are no longer valid, and need
|
||||
// to be retrieved.
|
||||
IsExpired() bool
|
||||
}
|
||||
|
||||
// An ErrorProvider is a stub credentials provider that always returns an error
|
||||
// this is used by the SDK when construction a known provider is not possible
|
||||
// due to an error.
|
||||
type ErrorProvider struct {
|
||||
// The error to be returned from Retrieve
|
||||
Err error
|
||||
|
||||
// The provider name to set on the Retrieved returned Value
|
||||
ProviderName string
|
||||
}
|
||||
|
||||
// Retrieve will always return the error that the ErrorProvider was created with.
|
||||
func (p ErrorProvider) Retrieve() (Value, error) {
|
||||
return Value{ProviderName: p.ProviderName}, p.Err
|
||||
}
|
||||
|
||||
// IsExpired will always return not expired.
|
||||
func (p ErrorProvider) IsExpired() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// A Expiry provides shared expiration logic to be used by credentials
|
||||
// providers to implement expiry functionality.
|
||||
//
|
||||
// The best method to use this struct is as an anonymous field within the
|
||||
// provider's struct.
|
||||
//
|
||||
// Example:
|
||||
// type EC2RoleProvider struct {
|
||||
// Expiry
|
||||
// ...
|
||||
// }
|
||||
type Expiry struct {
|
||||
// The date/time when to expire on
|
||||
expiration time.Time
|
||||
|
||||
// If set will be used by IsExpired to determine the current time.
|
||||
// Defaults to time.Now if CurrentTime is not set. Available for testing
|
||||
// to be able to mock out the current time.
|
||||
CurrentTime func() time.Time
|
||||
}
|
||||
|
||||
// SetExpiration sets the expiration IsExpired will check when called.
|
||||
//
|
||||
// If window is greater than 0 the expiration time will be reduced by the
|
||||
// window value.
|
||||
//
|
||||
// Using a window is helpful to trigger credentials to expire sooner than
|
||||
// the expiration time given to ensure no requests are made with expired
|
||||
// tokens.
|
||||
func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) {
|
||||
e.expiration = expiration
|
||||
if window > 0 {
|
||||
e.expiration = e.expiration.Add(-window)
|
||||
}
|
||||
}
|
||||
|
||||
// IsExpired returns if the credentials are expired.
|
||||
func (e *Expiry) IsExpired() bool {
|
||||
curTime := e.CurrentTime
|
||||
if curTime == nil {
|
||||
curTime = time.Now
|
||||
}
|
||||
return e.expiration.Before(curTime())
|
||||
}
|
||||
|
||||
// A Credentials provides concurrency safe retrieval of AWS credentials Value.
|
||||
// Credentials will cache the credentials value until they expire. Once the value
|
||||
// expires the next Get will attempt to retrieve valid credentials.
|
||||
//
|
||||
// Credentials is safe to use across multiple goroutines and will manage the
|
||||
// synchronous state so the Providers do not need to implement their own
|
||||
// synchronization.
|
||||
//
|
||||
// The first Credentials.Get() will always call Provider.Retrieve() to get the
|
||||
// first instance of the credentials Value. All calls to Get() after that
|
||||
// will return the cached credentials Value until IsExpired() returns true.
|
||||
type Credentials struct {
|
||||
creds Value
|
||||
forceRefresh bool
|
||||
|
||||
m sync.RWMutex
|
||||
|
||||
provider Provider
|
||||
}
|
||||
|
||||
// NewCredentials returns a pointer to a new Credentials with the provider set.
|
||||
func NewCredentials(provider Provider) *Credentials {
|
||||
return &Credentials{
|
||||
provider: provider,
|
||||
forceRefresh: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the credentials value, or error if the credentials Value failed
|
||||
// to be retrieved.
|
||||
//
|
||||
// Will return the cached credentials Value if it has not expired. If the
|
||||
// credentials Value has expired the Provider's Retrieve() will be called
|
||||
// to refresh the credentials.
|
||||
//
|
||||
// If Credentials.Expire() was called the credentials Value will be force
|
||||
// expired, and the next call to Get() will cause them to be refreshed.
|
||||
func (c *Credentials) Get() (Value, error) {
|
||||
// Check the cached credentials first with just the read lock.
|
||||
c.m.RLock()
|
||||
if !c.isExpired() {
|
||||
creds := c.creds
|
||||
c.m.RUnlock()
|
||||
return creds, nil
|
||||
}
|
||||
c.m.RUnlock()
|
||||
|
||||
// Credentials are expired need to retrieve the credentials taking the full
|
||||
// lock.
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
if c.isExpired() {
|
||||
creds, err := c.provider.Retrieve()
|
||||
if err != nil {
|
||||
return Value{}, err
|
||||
}
|
||||
c.creds = creds
|
||||
c.forceRefresh = false
|
||||
}
|
||||
|
||||
return c.creds, nil
|
||||
}
|
||||
|
||||
// Expire expires the credentials and forces them to be retrieved on the
|
||||
// next call to Get().
|
||||
//
|
||||
// This will override the Provider's expired state, and force Credentials
|
||||
// to call the Provider's Retrieve().
|
||||
func (c *Credentials) Expire() {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
c.forceRefresh = true
|
||||
}
|
||||
|
||||
// IsExpired returns if the credentials are no longer valid, and need
|
||||
// to be retrieved.
|
||||
//
|
||||
// If the Credentials were forced to be expired with Expire() this will
|
||||
// reflect that override.
|
||||
func (c *Credentials) IsExpired() bool {
|
||||
c.m.RLock()
|
||||
defer c.m.RUnlock()
|
||||
|
||||
return c.isExpired()
|
||||
}
|
||||
|
||||
// isExpired helper method wrapping the definition of expired credentials.
|
||||
func (c *Credentials) isExpired() bool {
|
||||
return c.forceRefresh || c.provider.IsExpired()
|
||||
}
|
||||
178
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
Normal file
178
vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
package ec2rolecreds
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/internal/sdkuri"
|
||||
)
|
||||
|
||||
// ProviderName provides a name of EC2Role provider
|
||||
const ProviderName = "EC2RoleProvider"
|
||||
|
||||
// A EC2RoleProvider retrieves credentials from the EC2 service, and keeps track if
|
||||
// those credentials are expired.
|
||||
//
|
||||
// Example how to configure the EC2RoleProvider with custom http Client, Endpoint
|
||||
// or ExpiryWindow
|
||||
//
|
||||
// p := &ec2rolecreds.EC2RoleProvider{
|
||||
// // Pass in a custom timeout to be used when requesting
|
||||
// // IAM EC2 Role credentials.
|
||||
// Client: ec2metadata.New(sess, aws.Config{
|
||||
// HTTPClient: &http.Client{Timeout: 10 * time.Second},
|
||||
// }),
|
||||
//
|
||||
// // Do not use early expiry of credentials. If a non zero value is
|
||||
// // specified the credentials will be expired early
|
||||
// ExpiryWindow: 0,
|
||||
// }
|
||||
type EC2RoleProvider struct {
|
||||
credentials.Expiry
|
||||
|
||||
// Required EC2Metadata client to use when connecting to EC2 metadata service.
|
||||
Client *ec2metadata.EC2Metadata
|
||||
|
||||
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||
// the credentials actually expiring. This is beneficial so race conditions
|
||||
// with expiring credentials do not cause request to fail unexpectedly
|
||||
// due to ExpiredTokenException exceptions.
|
||||
//
|
||||
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||
// 10 seconds before the credentials are actually expired.
|
||||
//
|
||||
// If ExpiryWindow is 0 or less it will be ignored.
|
||||
ExpiryWindow time.Duration
|
||||
}
|
||||
|
||||
// NewCredentials returns a pointer to a new Credentials object wrapping
|
||||
// the EC2RoleProvider. Takes a ConfigProvider to create a EC2Metadata client.
|
||||
// The ConfigProvider is satisfied by the session.Session type.
|
||||
func NewCredentials(c client.ConfigProvider, options ...func(*EC2RoleProvider)) *credentials.Credentials {
|
||||
p := &EC2RoleProvider{
|
||||
Client: ec2metadata.New(c),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping
|
||||
// the EC2RoleProvider. Takes a EC2Metadata client to use when connecting to EC2
|
||||
// metadata service.
|
||||
func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*EC2RoleProvider)) *credentials.Credentials {
|
||||
p := &EC2RoleProvider{
|
||||
Client: client,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// Retrieve retrieves credentials from the EC2 service.
|
||||
// Error will be returned if the request fails, or unable to extract
|
||||
// the desired credentials.
|
||||
func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
|
||||
credsList, err := requestCredList(m.Client)
|
||||
if err != nil {
|
||||
return credentials.Value{ProviderName: ProviderName}, err
|
||||
}
|
||||
|
||||
if len(credsList) == 0 {
|
||||
return credentials.Value{ProviderName: ProviderName}, awserr.New("EmptyEC2RoleList", "empty EC2 Role list", nil)
|
||||
}
|
||||
credsName := credsList[0]
|
||||
|
||||
roleCreds, err := requestCred(m.Client, credsName)
|
||||
if err != nil {
|
||||
return credentials.Value{ProviderName: ProviderName}, err
|
||||
}
|
||||
|
||||
m.SetExpiration(roleCreds.Expiration, m.ExpiryWindow)
|
||||
|
||||
return credentials.Value{
|
||||
AccessKeyID: roleCreds.AccessKeyID,
|
||||
SecretAccessKey: roleCreds.SecretAccessKey,
|
||||
SessionToken: roleCreds.Token,
|
||||
ProviderName: ProviderName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// A ec2RoleCredRespBody provides the shape for unmarshaling credential
|
||||
// request responses.
|
||||
type ec2RoleCredRespBody struct {
|
||||
// Success State
|
||||
Expiration time.Time
|
||||
AccessKeyID string
|
||||
SecretAccessKey string
|
||||
Token string
|
||||
|
||||
// Error state
|
||||
Code string
|
||||
Message string
|
||||
}
|
||||
|
||||
const iamSecurityCredsPath = "iam/security-credentials/"
|
||||
|
||||
// requestCredList requests a list of credentials from the EC2 service.
|
||||
// If there are no credentials, or there is an error making or receiving the request
|
||||
func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
|
||||
resp, err := client.GetMetadata(iamSecurityCredsPath)
|
||||
if err != nil {
|
||||
return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err)
|
||||
}
|
||||
|
||||
credsList := []string{}
|
||||
s := bufio.NewScanner(strings.NewReader(resp))
|
||||
for s.Scan() {
|
||||
credsList = append(credsList, s.Text())
|
||||
}
|
||||
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, awserr.New("SerializationError", "failed to read EC2 instance role from metadata service", err)
|
||||
}
|
||||
|
||||
return credsList, nil
|
||||
}
|
||||
|
||||
// requestCred requests the credentials for a specific credentials from the EC2 service.
|
||||
//
|
||||
// If the credentials cannot be found, or there is an error reading the response
|
||||
// and error will be returned.
|
||||
func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
|
||||
resp, err := client.GetMetadata(sdkuri.PathJoin(iamSecurityCredsPath, credsName))
|
||||
if err != nil {
|
||||
return ec2RoleCredRespBody{},
|
||||
awserr.New("EC2RoleRequestError",
|
||||
fmt.Sprintf("failed to get %s EC2 instance role credentials", credsName),
|
||||
err)
|
||||
}
|
||||
|
||||
respCreds := ec2RoleCredRespBody{}
|
||||
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil {
|
||||
return ec2RoleCredRespBody{},
|
||||
awserr.New("SerializationError",
|
||||
fmt.Sprintf("failed to decode %s EC2 instance role credentials", credsName),
|
||||
err)
|
||||
}
|
||||
|
||||
if respCreds.Code != "Success" {
|
||||
// If an error code was returned something failed requesting the role.
|
||||
return ec2RoleCredRespBody{}, awserr.New(respCreds.Code, respCreds.Message, nil)
|
||||
}
|
||||
|
||||
return respCreds, nil
|
||||
}
|
||||
198
vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
generated
vendored
Normal file
198
vendor/github.com/aws/aws-sdk-go/aws/credentials/endpointcreds/provider.go
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
// Package endpointcreds provides support for retrieving credentials from an
|
||||
// arbitrary HTTP endpoint.
|
||||
//
|
||||
// The credentials endpoint Provider can receive both static and refreshable
|
||||
// credentials that will expire. Credentials are static when an "Expiration"
|
||||
// value is not provided in the endpoint's response.
|
||||
//
|
||||
// Static credentials will never expire once they have been retrieved. The format
|
||||
// of the static credentials response:
|
||||
// {
|
||||
// "AccessKeyId" : "MUA...",
|
||||
// "SecretAccessKey" : "/7PC5om....",
|
||||
// }
|
||||
//
|
||||
// Refreshable credentials will expire within the "ExpiryWindow" of the Expiration
|
||||
// value in the response. The format of the refreshable credentials response:
|
||||
// {
|
||||
// "AccessKeyId" : "MUA...",
|
||||
// "SecretAccessKey" : "/7PC5om....",
|
||||
// "Token" : "AQoDY....=",
|
||||
// "Expiration" : "2016-02-25T06:03:31Z"
|
||||
// }
|
||||
//
|
||||
// Errors should be returned in the following format and only returned with 400
|
||||
// or 500 HTTP status codes.
|
||||
// {
|
||||
// "code": "ErrorCode",
|
||||
// "message": "Helpful error message."
|
||||
// }
|
||||
package endpointcreds
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// ProviderName is the name of the credentials provider.
|
||||
const ProviderName = `CredentialsEndpointProvider`
|
||||
|
||||
// Provider satisfies the credentials.Provider interface, and is a client to
|
||||
// retrieve credentials from an arbitrary endpoint.
|
||||
type Provider struct {
|
||||
staticCreds bool
|
||||
credentials.Expiry
|
||||
|
||||
// Requires a AWS Client to make HTTP requests to the endpoint with.
|
||||
// the Endpoint the request will be made to is provided by the aws.Config's
|
||||
// Endpoint value.
|
||||
Client *client.Client
|
||||
|
||||
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||
// the credentials actually expiring. This is beneficial so race conditions
|
||||
// with expiring credentials do not cause request to fail unexpectedly
|
||||
// due to ExpiredTokenException exceptions.
|
||||
//
|
||||
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||
// 10 seconds before the credentials are actually expired.
|
||||
//
|
||||
// If ExpiryWindow is 0 or less it will be ignored.
|
||||
ExpiryWindow time.Duration
|
||||
|
||||
// Optional authorization token value if set will be used as the value of
|
||||
// the Authorization header of the endpoint credential request.
|
||||
AuthorizationToken string
|
||||
}
|
||||
|
||||
// NewProviderClient returns a credentials Provider for retrieving AWS credentials
|
||||
// from arbitrary endpoint.
|
||||
func NewProviderClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) credentials.Provider {
|
||||
p := &Provider{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: "CredentialsEndpoint",
|
||||
Endpoint: endpoint,
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
p.Client.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
||||
p.Client.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
p.Client.Handlers.Validate.Clear()
|
||||
p.Client.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// NewCredentialsClient returns a Credentials wrapper for retrieving credentials
|
||||
// from an arbitrary endpoint concurrently. The client will request the
|
||||
func NewCredentialsClient(cfg aws.Config, handlers request.Handlers, endpoint string, options ...func(*Provider)) *credentials.Credentials {
|
||||
return credentials.NewCredentials(NewProviderClient(cfg, handlers, endpoint, options...))
|
||||
}
|
||||
|
||||
// IsExpired returns true if the credentials retrieved are expired, or not yet
|
||||
// retrieved.
|
||||
func (p *Provider) IsExpired() bool {
|
||||
if p.staticCreds {
|
||||
return false
|
||||
}
|
||||
return p.Expiry.IsExpired()
|
||||
}
|
||||
|
||||
// Retrieve will attempt to request the credentials from the endpoint the Provider
|
||||
// was configured for. And error will be returned if the retrieval fails.
|
||||
func (p *Provider) Retrieve() (credentials.Value, error) {
|
||||
resp, err := p.getCredentials()
|
||||
if err != nil {
|
||||
return credentials.Value{ProviderName: ProviderName},
|
||||
awserr.New("CredentialsEndpointError", "failed to load credentials", err)
|
||||
}
|
||||
|
||||
if resp.Expiration != nil {
|
||||
p.SetExpiration(*resp.Expiration, p.ExpiryWindow)
|
||||
} else {
|
||||
p.staticCreds = true
|
||||
}
|
||||
|
||||
return credentials.Value{
|
||||
AccessKeyID: resp.AccessKeyID,
|
||||
SecretAccessKey: resp.SecretAccessKey,
|
||||
SessionToken: resp.Token,
|
||||
ProviderName: ProviderName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type getCredentialsOutput struct {
|
||||
Expiration *time.Time
|
||||
AccessKeyID string
|
||||
SecretAccessKey string
|
||||
Token string
|
||||
}
|
||||
|
||||
type errorOutput struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (p *Provider) getCredentials() (*getCredentialsOutput, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetCredentials",
|
||||
HTTPMethod: "GET",
|
||||
}
|
||||
|
||||
out := &getCredentialsOutput{}
|
||||
req := p.Client.NewRequest(op, nil, out)
|
||||
req.HTTPRequest.Header.Set("Accept", "application/json")
|
||||
if authToken := p.AuthorizationToken; len(authToken) != 0 {
|
||||
req.HTTPRequest.Header.Set("Authorization", authToken)
|
||||
}
|
||||
|
||||
return out, req.Send()
|
||||
}
|
||||
|
||||
func validateEndpointHandler(r *request.Request) {
|
||||
if len(r.ClientInfo.Endpoint) == 0 {
|
||||
r.Error = aws.ErrMissingEndpoint
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalHandler(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
|
||||
out := r.Data.(*getCredentialsOutput)
|
||||
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&out); err != nil {
|
||||
r.Error = awserr.New("SerializationError",
|
||||
"failed to decode endpoint credentials",
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalError(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
|
||||
var errOut errorOutput
|
||||
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&errOut); err != nil {
|
||||
r.Error = awserr.New("SerializationError",
|
||||
"failed to decode endpoint credentials",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
// Response body format is not consistent between metadata endpoints.
|
||||
// Grab the error message as a string and include that as the source error
|
||||
r.Error = awserr.New(errOut.Code, errOut.Message, nil)
|
||||
}
|
||||
78
vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go
generated
vendored
Normal file
78
vendor/github.com/aws/aws-sdk-go/aws/credentials/env_provider.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package credentials
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
// EnvProviderName provides a name of Env provider
|
||||
const EnvProviderName = "EnvProvider"
|
||||
|
||||
var (
|
||||
// ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be
|
||||
// found in the process's environment.
|
||||
//
|
||||
// @readonly
|
||||
ErrAccessKeyIDNotFound = awserr.New("EnvAccessKeyNotFound", "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment", nil)
|
||||
|
||||
// ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key
|
||||
// can't be found in the process's environment.
|
||||
//
|
||||
// @readonly
|
||||
ErrSecretAccessKeyNotFound = awserr.New("EnvSecretNotFound", "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment", nil)
|
||||
)
|
||||
|
||||
// A EnvProvider retrieves credentials from the environment variables of the
|
||||
// running process. Environment credentials never expire.
|
||||
//
|
||||
// Environment variables used:
|
||||
//
|
||||
// * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY
|
||||
//
|
||||
// * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY
|
||||
type EnvProvider struct {
|
||||
retrieved bool
|
||||
}
|
||||
|
||||
// NewEnvCredentials returns a pointer to a new Credentials object
|
||||
// wrapping the environment variable provider.
|
||||
func NewEnvCredentials() *Credentials {
|
||||
return NewCredentials(&EnvProvider{})
|
||||
}
|
||||
|
||||
// Retrieve retrieves the keys from the environment.
|
||||
func (e *EnvProvider) Retrieve() (Value, error) {
|
||||
e.retrieved = false
|
||||
|
||||
id := os.Getenv("AWS_ACCESS_KEY_ID")
|
||||
if id == "" {
|
||||
id = os.Getenv("AWS_ACCESS_KEY")
|
||||
}
|
||||
|
||||
secret := os.Getenv("AWS_SECRET_ACCESS_KEY")
|
||||
if secret == "" {
|
||||
secret = os.Getenv("AWS_SECRET_KEY")
|
||||
}
|
||||
|
||||
if id == "" {
|
||||
return Value{ProviderName: EnvProviderName}, ErrAccessKeyIDNotFound
|
||||
}
|
||||
|
||||
if secret == "" {
|
||||
return Value{ProviderName: EnvProviderName}, ErrSecretAccessKeyNotFound
|
||||
}
|
||||
|
||||
e.retrieved = true
|
||||
return Value{
|
||||
AccessKeyID: id,
|
||||
SecretAccessKey: secret,
|
||||
SessionToken: os.Getenv("AWS_SESSION_TOKEN"),
|
||||
ProviderName: EnvProviderName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// IsExpired returns if the credentials have been retrieved.
|
||||
func (e *EnvProvider) IsExpired() bool {
|
||||
return !e.retrieved
|
||||
}
|
||||
12
vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini
generated
vendored
Normal file
12
vendor/github.com/aws/aws-sdk-go/aws/credentials/example.ini
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
[default]
|
||||
aws_access_key_id = accessKey
|
||||
aws_secret_access_key = secret
|
||||
aws_session_token = token
|
||||
|
||||
[no_token]
|
||||
aws_access_key_id = accessKey
|
||||
aws_secret_access_key = secret
|
||||
|
||||
[with_colon]
|
||||
aws_access_key_id: accessKey
|
||||
aws_secret_access_key: secret
|
||||
150
vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
generated
vendored
Normal file
150
vendor/github.com/aws/aws-sdk-go/aws/credentials/shared_credentials_provider.go
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
package credentials
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/internal/ini"
|
||||
"github.com/aws/aws-sdk-go/internal/shareddefaults"
|
||||
)
|
||||
|
||||
// SharedCredsProviderName provides a name of SharedCreds provider
|
||||
const SharedCredsProviderName = "SharedCredentialsProvider"
|
||||
|
||||
var (
|
||||
// ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found.
|
||||
ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil)
|
||||
)
|
||||
|
||||
// A SharedCredentialsProvider retrieves credentials from the current user's home
|
||||
// directory, and keeps track if those credentials are expired.
|
||||
//
|
||||
// Profile ini file example: $HOME/.aws/credentials
|
||||
type SharedCredentialsProvider struct {
|
||||
// Path to the shared credentials file.
|
||||
//
|
||||
// If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the
|
||||
// env value is empty will default to current user's home directory.
|
||||
// Linux/OSX: "$HOME/.aws/credentials"
|
||||
// Windows: "%USERPROFILE%\.aws\credentials"
|
||||
Filename string
|
||||
|
||||
// AWS Profile to extract credentials from the shared credentials file. If empty
|
||||
// will default to environment variable "AWS_PROFILE" or "default" if
|
||||
// environment variable is also not set.
|
||||
Profile string
|
||||
|
||||
// retrieved states if the credentials have been successfully retrieved.
|
||||
retrieved bool
|
||||
}
|
||||
|
||||
// NewSharedCredentials returns a pointer to a new Credentials object
|
||||
// wrapping the Profile file provider.
|
||||
func NewSharedCredentials(filename, profile string) *Credentials {
|
||||
return NewCredentials(&SharedCredentialsProvider{
|
||||
Filename: filename,
|
||||
Profile: profile,
|
||||
})
|
||||
}
|
||||
|
||||
// Retrieve reads and extracts the shared credentials from the current
|
||||
// users home directory.
|
||||
func (p *SharedCredentialsProvider) Retrieve() (Value, error) {
|
||||
p.retrieved = false
|
||||
|
||||
filename, err := p.filename()
|
||||
if err != nil {
|
||||
return Value{ProviderName: SharedCredsProviderName}, err
|
||||
}
|
||||
|
||||
creds, err := loadProfile(filename, p.profile())
|
||||
if err != nil {
|
||||
return Value{ProviderName: SharedCredsProviderName}, err
|
||||
}
|
||||
|
||||
p.retrieved = true
|
||||
return creds, nil
|
||||
}
|
||||
|
||||
// IsExpired returns if the shared credentials have expired.
|
||||
func (p *SharedCredentialsProvider) IsExpired() bool {
|
||||
return !p.retrieved
|
||||
}
|
||||
|
||||
// loadProfiles loads from the file pointed to by shared credentials filename for profile.
|
||||
// The credentials retrieved from the profile will be returned or error. Error will be
|
||||
// returned if it fails to read from the file, or the data is invalid.
|
||||
func loadProfile(filename, profile string) (Value, error) {
|
||||
config, err := ini.OpenFile(filename)
|
||||
if err != nil {
|
||||
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to load shared credentials file", err)
|
||||
}
|
||||
|
||||
iniProfile, ok := config.GetSection(profile)
|
||||
if !ok {
|
||||
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to get profile", nil)
|
||||
}
|
||||
|
||||
id := iniProfile.String("aws_access_key_id")
|
||||
if len(id) == 0 {
|
||||
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsAccessKey",
|
||||
fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename),
|
||||
nil)
|
||||
}
|
||||
|
||||
secret := iniProfile.String("aws_secret_access_key")
|
||||
if len(secret) == 0 {
|
||||
return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsSecret",
|
||||
fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename),
|
||||
nil)
|
||||
}
|
||||
|
||||
// Default to empty string if not found
|
||||
token := iniProfile.String("aws_session_token")
|
||||
|
||||
return Value{
|
||||
AccessKeyID: id,
|
||||
SecretAccessKey: secret,
|
||||
SessionToken: token,
|
||||
ProviderName: SharedCredsProviderName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// filename returns the filename to use to read AWS shared credentials.
|
||||
//
|
||||
// Will return an error if the user's home directory path cannot be found.
|
||||
func (p *SharedCredentialsProvider) filename() (string, error) {
|
||||
if len(p.Filename) != 0 {
|
||||
return p.Filename, nil
|
||||
}
|
||||
|
||||
if p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); len(p.Filename) != 0 {
|
||||
return p.Filename, nil
|
||||
}
|
||||
|
||||
if home := shareddefaults.UserHomeDir(); len(home) == 0 {
|
||||
// Backwards compatibility of home directly not found error being returned.
|
||||
// This error is too verbose, failure when opening the file would of been
|
||||
// a better error to return.
|
||||
return "", ErrSharedCredentialsHomeNotFound
|
||||
}
|
||||
|
||||
p.Filename = shareddefaults.SharedCredentialsFilename()
|
||||
|
||||
return p.Filename, nil
|
||||
}
|
||||
|
||||
// profile returns the AWS shared credentials profile. If empty will read
|
||||
// environment variable "AWS_PROFILE". If that is not set profile will
|
||||
// return "default".
|
||||
func (p *SharedCredentialsProvider) profile() string {
|
||||
if p.Profile == "" {
|
||||
p.Profile = os.Getenv("AWS_PROFILE")
|
||||
}
|
||||
if p.Profile == "" {
|
||||
p.Profile = "default"
|
||||
}
|
||||
|
||||
return p.Profile
|
||||
}
|
||||
57
vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go
generated
vendored
Normal file
57
vendor/github.com/aws/aws-sdk-go/aws/credentials/static_provider.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package credentials
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
// StaticProviderName provides a name of Static provider
|
||||
const StaticProviderName = "StaticProvider"
|
||||
|
||||
var (
|
||||
// ErrStaticCredentialsEmpty is emitted when static credentials are empty.
|
||||
//
|
||||
// @readonly
|
||||
ErrStaticCredentialsEmpty = awserr.New("EmptyStaticCreds", "static credentials are empty", nil)
|
||||
)
|
||||
|
||||
// A StaticProvider is a set of credentials which are set programmatically,
|
||||
// and will never expire.
|
||||
type StaticProvider struct {
|
||||
Value
|
||||
}
|
||||
|
||||
// NewStaticCredentials returns a pointer to a new Credentials object
|
||||
// wrapping a static credentials value provider.
|
||||
func NewStaticCredentials(id, secret, token string) *Credentials {
|
||||
return NewCredentials(&StaticProvider{Value: Value{
|
||||
AccessKeyID: id,
|
||||
SecretAccessKey: secret,
|
||||
SessionToken: token,
|
||||
}})
|
||||
}
|
||||
|
||||
// NewStaticCredentialsFromCreds returns a pointer to a new Credentials object
|
||||
// wrapping the static credentials value provide. Same as NewStaticCredentials
|
||||
// but takes the creds Value instead of individual fields
|
||||
func NewStaticCredentialsFromCreds(creds Value) *Credentials {
|
||||
return NewCredentials(&StaticProvider{Value: creds})
|
||||
}
|
||||
|
||||
// Retrieve returns the credentials or error if the credentials are invalid.
|
||||
func (s *StaticProvider) Retrieve() (Value, error) {
|
||||
if s.AccessKeyID == "" || s.SecretAccessKey == "" {
|
||||
return Value{ProviderName: StaticProviderName}, ErrStaticCredentialsEmpty
|
||||
}
|
||||
|
||||
if len(s.Value.ProviderName) == 0 {
|
||||
s.Value.ProviderName = StaticProviderName
|
||||
}
|
||||
return s.Value, nil
|
||||
}
|
||||
|
||||
// IsExpired returns if the credentials are expired.
|
||||
//
|
||||
// For StaticProvider, the credentials never expired.
|
||||
func (s *StaticProvider) IsExpired() bool {
|
||||
return false
|
||||
}
|
||||
298
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
Normal file
298
vendor/github.com/aws/aws-sdk-go/aws/credentials/stscreds/assume_role_provider.go
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
Package stscreds are credential Providers to retrieve STS AWS credentials.
|
||||
|
||||
STS provides multiple ways to retrieve credentials which can be used when making
|
||||
future AWS service API operation calls.
|
||||
|
||||
The SDK will ensure that per instance of credentials.Credentials all requests
|
||||
to refresh the credentials will be synchronized. But, the SDK is unable to
|
||||
ensure synchronous usage of the AssumeRoleProvider if the value is shared
|
||||
between multiple Credentials, Sessions or service clients.
|
||||
|
||||
Assume Role
|
||||
|
||||
To assume an IAM role using STS with the SDK you can create a new Credentials
|
||||
with the SDKs's stscreds package.
|
||||
|
||||
// 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})
|
||||
|
||||
Assume Role with static MFA Token
|
||||
|
||||
To assume an IAM role with a MFA token you can either specify a MFA token code
|
||||
directly or provide a function to prompt the user each time the credentials
|
||||
need to refresh the role's credentials. Specifying the TokenCode should be used
|
||||
for short lived operations that will not need to be refreshed, and when you do
|
||||
not want to have direct control over the user provides their MFA token.
|
||||
|
||||
With TokenCode the AssumeRoleProvider will be not be able to refresh the role's
|
||||
credentials.
|
||||
|
||||
// Create the credentials from AssumeRoleProvider to assume the role
|
||||
// referenced by the "myRoleARN" ARN using the MFA token code provided.
|
||||
creds := stscreds.NewCredentials(sess, "myRoleArn", func(p *stscreds.AssumeRoleProvider) {
|
||||
p.SerialNumber = aws.String("myTokenSerialNumber")
|
||||
p.TokenCode = aws.String("00000000")
|
||||
})
|
||||
|
||||
// Create service client value configured for credentials
|
||||
// from assumed role.
|
||||
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||
|
||||
Assume Role with MFA Token Provider
|
||||
|
||||
To assume an IAM role with MFA for longer running tasks where the credentials
|
||||
may need to be refreshed setting the TokenProvider field of AssumeRoleProvider
|
||||
will allow the credential provider to prompt for new MFA token code when the
|
||||
role's credentials need to be refreshed.
|
||||
|
||||
The StdinTokenProvider function is available to prompt on stdin to retrieve
|
||||
the MFA token code from the user. You can also implement custom prompts by
|
||||
satisfing the TokenProvider function signature.
|
||||
|
||||
Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will
|
||||
have undesirable results as the StdinTokenProvider will not be synchronized. A
|
||||
single Credentials with an AssumeRoleProvider can be shared safely.
|
||||
|
||||
// Create the credentials from AssumeRoleProvider to assume the role
|
||||
// referenced by the "myRoleARN" ARN. Prompting for MFA token from stdin.
|
||||
creds := stscreds.NewCredentials(sess, "myRoleArn", func(p *stscreds.AssumeRoleProvider) {
|
||||
p.SerialNumber = aws.String("myTokenSerialNumber")
|
||||
p.TokenProvider = stscreds.StdinTokenProvider
|
||||
})
|
||||
|
||||
// Create service client value configured for credentials
|
||||
// from assumed role.
|
||||
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||
|
||||
*/
|
||||
package stscreds
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/service/sts"
|
||||
)
|
||||
|
||||
// StdinTokenProvider will prompt on stdout and read from stdin for a string value.
|
||||
// An error is returned if reading from stdin fails.
|
||||
//
|
||||
// Use this function go read MFA tokens from stdin. The function makes no attempt
|
||||
// to make atomic prompts from stdin across multiple gorouties.
|
||||
//
|
||||
// Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will
|
||||
// have undesirable results as the StdinTokenProvider will not be synchronized. A
|
||||
// single Credentials with an AssumeRoleProvider can be shared safely
|
||||
//
|
||||
// Will wait forever until something is provided on the stdin.
|
||||
func StdinTokenProvider() (string, error) {
|
||||
var v string
|
||||
fmt.Printf("Assume Role MFA token code: ")
|
||||
_, err := fmt.Scanln(&v)
|
||||
|
||||
return v, err
|
||||
}
|
||||
|
||||
// ProviderName provides a name of AssumeRole provider
|
||||
const ProviderName = "AssumeRoleProvider"
|
||||
|
||||
// AssumeRoler represents the minimal subset of the STS client API used by this provider.
|
||||
type AssumeRoler interface {
|
||||
AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
|
||||
}
|
||||
|
||||
// DefaultDuration is the default amount of time in minutes that the credentials
|
||||
// will be valid for.
|
||||
var DefaultDuration = time.Duration(15) * time.Minute
|
||||
|
||||
// AssumeRoleProvider retrieves temporary credentials from the STS service, and
|
||||
// keeps track of their expiration time.
|
||||
//
|
||||
// This credential provider will be used by the SDKs default credential change
|
||||
// when shared configuration is enabled, and the shared config or shared credentials
|
||||
// file configure assume role. See Session docs for how to do this.
|
||||
//
|
||||
// AssumeRoleProvider does not provide any synchronization and it is not safe
|
||||
// to share this value across multiple Credentials, Sessions, or service clients
|
||||
// without also sharing the same Credentials instance.
|
||||
type AssumeRoleProvider struct {
|
||||
credentials.Expiry
|
||||
|
||||
// STS client to make assume role request with.
|
||||
Client AssumeRoler
|
||||
|
||||
// Role to be assumed.
|
||||
RoleARN string
|
||||
|
||||
// Session name, if you wish to reuse the credentials elsewhere.
|
||||
RoleSessionName string
|
||||
|
||||
// Expiry duration of the STS credentials. Defaults to 15 minutes if not set.
|
||||
Duration time.Duration
|
||||
|
||||
// Optional ExternalID to pass along, defaults to nil if not set.
|
||||
ExternalID *string
|
||||
|
||||
// The policy plain text must be 2048 bytes or shorter. However, an internal
|
||||
// conversion compresses it into a packed binary format with a separate limit.
|
||||
// The PackedPolicySize response element indicates by percentage how close to
|
||||
// the upper size limit the policy is, with 100% equaling the maximum allowed
|
||||
// size.
|
||||
Policy *string
|
||||
|
||||
// The identification number of the MFA device that is associated with the user
|
||||
// who is making the AssumeRole call. Specify this value if the trust policy
|
||||
// of the role being assumed includes a condition that requires MFA authentication.
|
||||
// The value is either the serial number for a hardware device (such as GAHT12345678)
|
||||
// or an Amazon Resource Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user).
|
||||
SerialNumber *string
|
||||
|
||||
// The value provided by the MFA device, if the trust policy of the role being
|
||||
// assumed requires MFA (that is, if the policy includes a condition that tests
|
||||
// for MFA). If the role being assumed requires MFA and if the TokenCode value
|
||||
// is missing or expired, the AssumeRole call returns an "access denied" error.
|
||||
//
|
||||
// If SerialNumber is set and neither TokenCode nor TokenProvider are also
|
||||
// set an error will be returned.
|
||||
TokenCode *string
|
||||
|
||||
// Async method of providing MFA token code for assuming an IAM role with MFA.
|
||||
// The value returned by the function will be used as the TokenCode in the Retrieve
|
||||
// call. See StdinTokenProvider for a provider that prompts and reads from stdin.
|
||||
//
|
||||
// This token provider will be called when ever the assumed role's
|
||||
// credentials need to be refreshed when SerialNumber is also set and
|
||||
// TokenCode is not set.
|
||||
//
|
||||
// If both TokenCode and TokenProvider is set, TokenProvider will be used and
|
||||
// TokenCode is ignored.
|
||||
TokenProvider func() (string, error)
|
||||
|
||||
// ExpiryWindow will allow the credentials to trigger refreshing prior to
|
||||
// the credentials actually expiring. This is beneficial so race conditions
|
||||
// with expiring credentials do not cause request to fail unexpectedly
|
||||
// due to ExpiredTokenException exceptions.
|
||||
//
|
||||
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
|
||||
// 10 seconds before the credentials are actually expired.
|
||||
//
|
||||
// If ExpiryWindow is 0 or less it will be ignored.
|
||||
ExpiryWindow time.Duration
|
||||
}
|
||||
|
||||
// NewCredentials returns a pointer to a new Credentials object wrapping the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// role will be named after a nanosecond timestamp of this operation.
|
||||
//
|
||||
// Takes a Config provider to create the STS client. The ConfigProvider is
|
||||
// satisfied by the session.Session type.
|
||||
//
|
||||
// It is safe to share the returned Credentials with multiple Sessions and
|
||||
// service clients. All access to the credentials and refreshing them
|
||||
// will be synchronized.
|
||||
func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: sts.New(c),
|
||||
RoleARN: roleARN,
|
||||
Duration: DefaultDuration,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping the
|
||||
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
|
||||
// role will be named after a nanosecond timestamp of this operation.
|
||||
//
|
||||
// Takes an AssumeRoler which can be satisfied by the STS client.
|
||||
//
|
||||
// It is safe to share the returned Credentials with multiple Sessions and
|
||||
// service clients. All access to the credentials and refreshing them
|
||||
// will be synchronized.
|
||||
func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
|
||||
p := &AssumeRoleProvider{
|
||||
Client: svc,
|
||||
RoleARN: roleARN,
|
||||
Duration: DefaultDuration,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(p)
|
||||
}
|
||||
|
||||
return credentials.NewCredentials(p)
|
||||
}
|
||||
|
||||
// Retrieve generates a new set of temporary credentials using STS.
|
||||
func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
|
||||
|
||||
// Apply defaults where parameters are not set.
|
||||
if p.RoleSessionName == "" {
|
||||
// Try to work out a role name that will hopefully end up unique.
|
||||
p.RoleSessionName = fmt.Sprintf("%d", time.Now().UTC().UnixNano())
|
||||
}
|
||||
if p.Duration == 0 {
|
||||
// Expire as often as AWS permits.
|
||||
p.Duration = DefaultDuration
|
||||
}
|
||||
input := &sts.AssumeRoleInput{
|
||||
DurationSeconds: aws.Int64(int64(p.Duration / time.Second)),
|
||||
RoleArn: aws.String(p.RoleARN),
|
||||
RoleSessionName: aws.String(p.RoleSessionName),
|
||||
ExternalId: p.ExternalID,
|
||||
}
|
||||
if p.Policy != nil {
|
||||
input.Policy = p.Policy
|
||||
}
|
||||
if p.SerialNumber != nil {
|
||||
if p.TokenCode != nil {
|
||||
input.SerialNumber = p.SerialNumber
|
||||
input.TokenCode = p.TokenCode
|
||||
} else if p.TokenProvider != nil {
|
||||
input.SerialNumber = p.SerialNumber
|
||||
code, err := p.TokenProvider()
|
||||
if err != nil {
|
||||
return credentials.Value{ProviderName: ProviderName}, err
|
||||
}
|
||||
input.TokenCode = aws.String(code)
|
||||
} else {
|
||||
return credentials.Value{ProviderName: ProviderName},
|
||||
awserr.New("AssumeRoleTokenNotAvailable",
|
||||
"assume role with MFA enabled, but neither TokenCode nor TokenProvider are set", nil)
|
||||
}
|
||||
}
|
||||
|
||||
roleOutput, err := p.Client.AssumeRole(input)
|
||||
if err != nil {
|
||||
return credentials.Value{ProviderName: ProviderName}, err
|
||||
}
|
||||
|
||||
// We will proactively generate new credentials before they expire.
|
||||
p.SetExpiration(*roleOutput.Credentials.Expiration, p.ExpiryWindow)
|
||||
|
||||
return credentials.Value{
|
||||
AccessKeyID: *roleOutput.Credentials.AccessKeyId,
|
||||
SecretAccessKey: *roleOutput.Credentials.SecretAccessKey,
|
||||
SessionToken: *roleOutput.Credentials.SessionToken,
|
||||
ProviderName: ProviderName,
|
||||
}, nil
|
||||
}
|
||||
46
vendor/github.com/aws/aws-sdk-go/aws/csm/doc.go
generated
vendored
Normal file
46
vendor/github.com/aws/aws-sdk-go/aws/csm/doc.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// Package csm provides Client Side Monitoring (CSM) which enables sending metrics
|
||||
// via UDP connection. Using the Start function will enable the reporting of
|
||||
// metrics on a given port. If Start is called, with different parameters, again,
|
||||
// a panic will occur.
|
||||
//
|
||||
// Pause can be called to pause any metrics publishing on a given port. Sessions
|
||||
// that have had their handlers modified via InjectHandlers may still be used.
|
||||
// However, the handlers will act as a no-op meaning no metrics will be published.
|
||||
//
|
||||
// Example:
|
||||
// r, err := csm.Start("clientID", ":31000")
|
||||
// if err != nil {
|
||||
// panic(fmt.Errorf("failed starting CSM: %v", err))
|
||||
// }
|
||||
//
|
||||
// sess, err := session.NewSession(&aws.Config{})
|
||||
// if err != nil {
|
||||
// panic(fmt.Errorf("failed loading session: %v", err))
|
||||
// }
|
||||
//
|
||||
// r.InjectHandlers(&sess.Handlers)
|
||||
//
|
||||
// client := s3.New(sess)
|
||||
// resp, err := client.GetObject(&s3.GetObjectInput{
|
||||
// Bucket: aws.String("bucket"),
|
||||
// Key: aws.String("key"),
|
||||
// })
|
||||
//
|
||||
// // Will pause monitoring
|
||||
// r.Pause()
|
||||
// resp, err = client.GetObject(&s3.GetObjectInput{
|
||||
// Bucket: aws.String("bucket"),
|
||||
// Key: aws.String("key"),
|
||||
// })
|
||||
//
|
||||
// // Resume monitoring
|
||||
// r.Continue()
|
||||
//
|
||||
// Start returns a Reporter that is used to enable or disable monitoring. If
|
||||
// access to the Reporter is required later, calling Get will return the Reporter
|
||||
// singleton.
|
||||
//
|
||||
// Example:
|
||||
// r := csm.Get()
|
||||
// r.Continue()
|
||||
package csm
|
||||
67
vendor/github.com/aws/aws-sdk-go/aws/csm/enable.go
generated
vendored
Normal file
67
vendor/github.com/aws/aws-sdk-go/aws/csm/enable.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package csm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
lock sync.Mutex
|
||||
)
|
||||
|
||||
// Client side metric handler names
|
||||
const (
|
||||
APICallMetricHandlerName = "awscsm.SendAPICallMetric"
|
||||
APICallAttemptMetricHandlerName = "awscsm.SendAPICallAttemptMetric"
|
||||
)
|
||||
|
||||
// Start will start the a long running go routine to capture
|
||||
// client side metrics. Calling start multiple time will only
|
||||
// start the metric listener once and will panic if a different
|
||||
// client ID or port is passed in.
|
||||
//
|
||||
// Example:
|
||||
// r, err := csm.Start("clientID", "127.0.0.1:8094")
|
||||
// if err != nil {
|
||||
// panic(fmt.Errorf("expected no error, but received %v", err))
|
||||
// }
|
||||
// sess := session.NewSession()
|
||||
// r.InjectHandlers(sess.Handlers)
|
||||
//
|
||||
// svc := s3.New(sess)
|
||||
// out, err := svc.GetObject(&s3.GetObjectInput{
|
||||
// Bucket: aws.String("bucket"),
|
||||
// Key: aws.String("key"),
|
||||
// })
|
||||
func Start(clientID string, url string) (*Reporter, error) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if sender == nil {
|
||||
sender = newReporter(clientID, url)
|
||||
} else {
|
||||
if sender.clientID != clientID {
|
||||
panic(fmt.Errorf("inconsistent client IDs. %q was expected, but received %q", sender.clientID, clientID))
|
||||
}
|
||||
|
||||
if sender.url != url {
|
||||
panic(fmt.Errorf("inconsistent URLs. %q was expected, but received %q", sender.url, url))
|
||||
}
|
||||
}
|
||||
|
||||
if err := connect(url); err != nil {
|
||||
sender = nil
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sender, nil
|
||||
}
|
||||
|
||||
// Get will return a reporter if one exists, if one does not exist, nil will
|
||||
// be returned.
|
||||
func Get() *Reporter {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
return sender
|
||||
}
|
||||
53
vendor/github.com/aws/aws-sdk-go/aws/csm/metric.go
generated
vendored
Normal file
53
vendor/github.com/aws/aws-sdk-go/aws/csm/metric.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
package csm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type metricTime time.Time
|
||||
|
||||
func (t metricTime) MarshalJSON() ([]byte, error) {
|
||||
ns := time.Duration(time.Time(t).UnixNano())
|
||||
return []byte(strconv.FormatInt(int64(ns/time.Millisecond), 10)), nil
|
||||
}
|
||||
|
||||
type metric struct {
|
||||
ClientID *string `json:"ClientId,omitempty"`
|
||||
API *string `json:"Api,omitempty"`
|
||||
Service *string `json:"Service,omitempty"`
|
||||
Timestamp *metricTime `json:"Timestamp,omitempty"`
|
||||
Type *string `json:"Type,omitempty"`
|
||||
Version *int `json:"Version,omitempty"`
|
||||
|
||||
AttemptCount *int `json:"AttemptCount,omitempty"`
|
||||
Latency *int `json:"Latency,omitempty"`
|
||||
|
||||
Fqdn *string `json:"Fqdn,omitempty"`
|
||||
UserAgent *string `json:"UserAgent,omitempty"`
|
||||
AttemptLatency *int `json:"AttemptLatency,omitempty"`
|
||||
|
||||
SessionToken *string `json:"SessionToken,omitempty"`
|
||||
Region *string `json:"Region,omitempty"`
|
||||
AccessKey *string `json:"AccessKey,omitempty"`
|
||||
HTTPStatusCode *int `json:"HttpStatusCode,omitempty"`
|
||||
XAmzID2 *string `json:"XAmzId2,omitempty"`
|
||||
XAmzRequestID *string `json:"XAmznRequestId,omitempty"`
|
||||
|
||||
AWSException *string `json:"AwsException,omitempty"`
|
||||
AWSExceptionMessage *string `json:"AwsExceptionMessage,omitempty"`
|
||||
SDKException *string `json:"SdkException,omitempty"`
|
||||
SDKExceptionMessage *string `json:"SdkExceptionMessage,omitempty"`
|
||||
|
||||
DestinationIP *string `json:"DestinationIp,omitempty"`
|
||||
ConnectionReused *int `json:"ConnectionReused,omitempty"`
|
||||
|
||||
AcquireConnectionLatency *int `json:"AcquireConnectionLatency,omitempty"`
|
||||
ConnectLatency *int `json:"ConnectLatency,omitempty"`
|
||||
RequestLatency *int `json:"RequestLatency,omitempty"`
|
||||
DNSLatency *int `json:"DnsLatency,omitempty"`
|
||||
TCPLatency *int `json:"TcpLatency,omitempty"`
|
||||
SSLLatency *int `json:"SslLatency,omitempty"`
|
||||
|
||||
MaxRetriesExceeded *int `json:"MaxRetriesExceeded,omitempty"`
|
||||
}
|
||||
54
vendor/github.com/aws/aws-sdk-go/aws/csm/metric_chan.go
generated
vendored
Normal file
54
vendor/github.com/aws/aws-sdk-go/aws/csm/metric_chan.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
package csm
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
const (
|
||||
runningEnum = iota
|
||||
pausedEnum
|
||||
)
|
||||
|
||||
var (
|
||||
// MetricsChannelSize of metrics to hold in the channel
|
||||
MetricsChannelSize = 100
|
||||
)
|
||||
|
||||
type metricChan struct {
|
||||
ch chan metric
|
||||
paused int64
|
||||
}
|
||||
|
||||
func newMetricChan(size int) metricChan {
|
||||
return metricChan{
|
||||
ch: make(chan metric, size),
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *metricChan) Pause() {
|
||||
atomic.StoreInt64(&ch.paused, pausedEnum)
|
||||
}
|
||||
|
||||
func (ch *metricChan) Continue() {
|
||||
atomic.StoreInt64(&ch.paused, runningEnum)
|
||||
}
|
||||
|
||||
func (ch *metricChan) IsPaused() bool {
|
||||
v := atomic.LoadInt64(&ch.paused)
|
||||
return v == pausedEnum
|
||||
}
|
||||
|
||||
// Push will push metrics to the metric channel if the channel
|
||||
// is not paused
|
||||
func (ch *metricChan) Push(m metric) bool {
|
||||
if ch.IsPaused() {
|
||||
return false
|
||||
}
|
||||
|
||||
select {
|
||||
case ch.ch <- m:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
242
vendor/github.com/aws/aws-sdk-go/aws/csm/reporter.go
generated
vendored
Normal file
242
vendor/github.com/aws/aws-sdk-go/aws/csm/reporter.go
generated
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
package csm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultPort is used when no port is specified
|
||||
DefaultPort = "31000"
|
||||
)
|
||||
|
||||
// Reporter will gather metrics of API requests made and
|
||||
// send those metrics to the CSM endpoint.
|
||||
type Reporter struct {
|
||||
clientID string
|
||||
url string
|
||||
conn net.Conn
|
||||
metricsCh metricChan
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
var (
|
||||
sender *Reporter
|
||||
)
|
||||
|
||||
func connect(url string) error {
|
||||
const network = "udp"
|
||||
if err := sender.connect(network, url); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sender.done == nil {
|
||||
sender.done = make(chan struct{})
|
||||
go sender.start()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newReporter(clientID, url string) *Reporter {
|
||||
return &Reporter{
|
||||
clientID: clientID,
|
||||
url: url,
|
||||
metricsCh: newMetricChan(MetricsChannelSize),
|
||||
}
|
||||
}
|
||||
|
||||
func (rep *Reporter) sendAPICallAttemptMetric(r *request.Request) {
|
||||
if rep == nil {
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
creds, _ := r.Config.Credentials.Get()
|
||||
|
||||
m := metric{
|
||||
ClientID: aws.String(rep.clientID),
|
||||
API: aws.String(r.Operation.Name),
|
||||
Service: aws.String(r.ClientInfo.ServiceID),
|
||||
Timestamp: (*metricTime)(&now),
|
||||
UserAgent: aws.String(r.HTTPRequest.Header.Get("User-Agent")),
|
||||
Region: r.Config.Region,
|
||||
Type: aws.String("ApiCallAttempt"),
|
||||
Version: aws.Int(1),
|
||||
|
||||
XAmzRequestID: aws.String(r.RequestID),
|
||||
|
||||
AttemptCount: aws.Int(r.RetryCount + 1),
|
||||
AttemptLatency: aws.Int(int(now.Sub(r.AttemptTime).Nanoseconds() / int64(time.Millisecond))),
|
||||
AccessKey: aws.String(creds.AccessKeyID),
|
||||
}
|
||||
|
||||
if r.HTTPResponse != nil {
|
||||
m.HTTPStatusCode = aws.Int(r.HTTPResponse.StatusCode)
|
||||
}
|
||||
|
||||
if r.Error != nil {
|
||||
if awserr, ok := r.Error.(awserr.Error); ok {
|
||||
setError(&m, awserr)
|
||||
}
|
||||
}
|
||||
|
||||
rep.metricsCh.Push(m)
|
||||
}
|
||||
|
||||
func setError(m *metric, err awserr.Error) {
|
||||
msg := err.Error()
|
||||
code := err.Code()
|
||||
|
||||
switch code {
|
||||
case "RequestError",
|
||||
"SerializationError",
|
||||
request.CanceledErrorCode:
|
||||
m.SDKException = &code
|
||||
m.SDKExceptionMessage = &msg
|
||||
default:
|
||||
m.AWSException = &code
|
||||
m.AWSExceptionMessage = &msg
|
||||
}
|
||||
}
|
||||
|
||||
func (rep *Reporter) sendAPICallMetric(r *request.Request) {
|
||||
if rep == nil {
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
m := metric{
|
||||
ClientID: aws.String(rep.clientID),
|
||||
API: aws.String(r.Operation.Name),
|
||||
Service: aws.String(r.ClientInfo.ServiceID),
|
||||
Timestamp: (*metricTime)(&now),
|
||||
Type: aws.String("ApiCall"),
|
||||
AttemptCount: aws.Int(r.RetryCount + 1),
|
||||
Region: r.Config.Region,
|
||||
Latency: aws.Int(int(time.Now().Sub(r.Time) / time.Millisecond)),
|
||||
XAmzRequestID: aws.String(r.RequestID),
|
||||
MaxRetriesExceeded: aws.Int(boolIntValue(r.RetryCount >= r.MaxRetries())),
|
||||
}
|
||||
|
||||
// TODO: Probably want to figure something out for logging dropped
|
||||
// metrics
|
||||
rep.metricsCh.Push(m)
|
||||
}
|
||||
|
||||
func (rep *Reporter) connect(network, url string) error {
|
||||
if rep.conn != nil {
|
||||
rep.conn.Close()
|
||||
}
|
||||
|
||||
conn, err := net.Dial(network, url)
|
||||
if err != nil {
|
||||
return awserr.New("UDPError", "Could not connect", err)
|
||||
}
|
||||
|
||||
rep.conn = conn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rep *Reporter) close() {
|
||||
if rep.done != nil {
|
||||
close(rep.done)
|
||||
}
|
||||
|
||||
rep.metricsCh.Pause()
|
||||
}
|
||||
|
||||
func (rep *Reporter) start() {
|
||||
defer func() {
|
||||
rep.metricsCh.Pause()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-rep.done:
|
||||
rep.done = nil
|
||||
return
|
||||
case m := <-rep.metricsCh.ch:
|
||||
// TODO: What to do with this error? Probably should just log
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
rep.conn.Write(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pause will pause the metric channel preventing any new metrics from
|
||||
// being added.
|
||||
func (rep *Reporter) Pause() {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if rep == nil {
|
||||
return
|
||||
}
|
||||
|
||||
rep.close()
|
||||
}
|
||||
|
||||
// Continue will reopen the metric channel and allow for monitoring
|
||||
// to be resumed.
|
||||
func (rep *Reporter) Continue() {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
if rep == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !rep.metricsCh.IsPaused() {
|
||||
return
|
||||
}
|
||||
|
||||
rep.metricsCh.Continue()
|
||||
}
|
||||
|
||||
// InjectHandlers will will enable client side metrics and inject the proper
|
||||
// handlers to handle how metrics are sent.
|
||||
//
|
||||
// Example:
|
||||
// // Start must be called in order to inject the correct handlers
|
||||
// r, err := csm.Start("clientID", "127.0.0.1:8094")
|
||||
// if err != nil {
|
||||
// panic(fmt.Errorf("expected no error, but received %v", err))
|
||||
// }
|
||||
//
|
||||
// sess := session.NewSession()
|
||||
// r.InjectHandlers(&sess.Handlers)
|
||||
//
|
||||
// // create a new service client with our client side metric session
|
||||
// svc := s3.New(sess)
|
||||
func (rep *Reporter) InjectHandlers(handlers *request.Handlers) {
|
||||
if rep == nil {
|
||||
return
|
||||
}
|
||||
|
||||
apiCallHandler := request.NamedHandler{Name: APICallMetricHandlerName, Fn: rep.sendAPICallMetric}
|
||||
apiCallAttemptHandler := request.NamedHandler{Name: APICallAttemptMetricHandlerName, Fn: rep.sendAPICallAttemptMetric}
|
||||
|
||||
handlers.Complete.PushFrontNamed(apiCallHandler)
|
||||
handlers.Complete.PushFrontNamed(apiCallAttemptHandler)
|
||||
|
||||
handlers.AfterRetry.PushFrontNamed(apiCallAttemptHandler)
|
||||
}
|
||||
|
||||
// boolIntValue return 1 for true and 0 for false.
|
||||
func boolIntValue(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
207
vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go
generated
vendored
Normal file
207
vendor/github.com/aws/aws-sdk-go/aws/defaults/defaults.go
generated
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
// Package defaults is a collection of helpers to retrieve the SDK's default
|
||||
// configuration and handlers.
|
||||
//
|
||||
// Generally this package shouldn't be used directly, but session.Session
|
||||
// instead. This package is useful when you need to reset the defaults
|
||||
// of a session or service client to the SDK defaults before setting
|
||||
// additional parameters.
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/endpointcreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/shareddefaults"
|
||||
)
|
||||
|
||||
// A Defaults provides a collection of default values for SDK clients.
|
||||
type Defaults struct {
|
||||
Config *aws.Config
|
||||
Handlers request.Handlers
|
||||
}
|
||||
|
||||
// Get returns the SDK's default values with Config and handlers pre-configured.
|
||||
func Get() Defaults {
|
||||
cfg := Config()
|
||||
handlers := Handlers()
|
||||
cfg.Credentials = CredChain(cfg, handlers)
|
||||
|
||||
return Defaults{
|
||||
Config: cfg,
|
||||
Handlers: handlers,
|
||||
}
|
||||
}
|
||||
|
||||
// Config returns the default configuration without credentials.
|
||||
// To retrieve a config with credentials also included use
|
||||
// `defaults.Get().Config` instead.
|
||||
//
|
||||
// Generally you shouldn't need to use this method directly, but
|
||||
// is available if you need to reset the configuration of an
|
||||
// existing service client or session.
|
||||
func Config() *aws.Config {
|
||||
return aws.NewConfig().
|
||||
WithCredentials(credentials.AnonymousCredentials).
|
||||
WithRegion(os.Getenv("AWS_REGION")).
|
||||
WithHTTPClient(http.DefaultClient).
|
||||
WithMaxRetries(aws.UseServiceDefaultRetries).
|
||||
WithLogger(aws.NewDefaultLogger()).
|
||||
WithLogLevel(aws.LogOff).
|
||||
WithEndpointResolver(endpoints.DefaultResolver())
|
||||
}
|
||||
|
||||
// Handlers returns the default request handlers.
|
||||
//
|
||||
// Generally you shouldn't need to use this method directly, but
|
||||
// is available if you need to reset the request handlers of an
|
||||
// existing service client or session.
|
||||
func Handlers() request.Handlers {
|
||||
var handlers request.Handlers
|
||||
|
||||
handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
|
||||
handlers.Validate.AfterEachFn = request.HandlerListStopOnError
|
||||
handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler)
|
||||
handlers.Build.PushBackNamed(corehandlers.AddHostExecEnvUserAgentHander)
|
||||
handlers.Build.AfterEachFn = request.HandlerListStopOnError
|
||||
handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.ValidateReqSigHandler)
|
||||
handlers.Send.PushBackNamed(corehandlers.SendHandler)
|
||||
handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
|
||||
handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
|
||||
|
||||
return handlers
|
||||
}
|
||||
|
||||
// CredChain returns the default credential chain.
|
||||
//
|
||||
// Generally you shouldn't need to use this method directly, but
|
||||
// is available if you need to reset the credentials of an
|
||||
// existing service client or session's Config.
|
||||
func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials {
|
||||
return credentials.NewCredentials(&credentials.ChainProvider{
|
||||
VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
|
||||
Providers: CredProviders(cfg, handlers),
|
||||
})
|
||||
}
|
||||
|
||||
// CredProviders returns the slice of providers used in
|
||||
// the default credential chain.
|
||||
//
|
||||
// For applications that need to use some other provider (for example use
|
||||
// different environment variables for legacy reasons) but still fall back
|
||||
// on the default chain of providers. This allows that default chaint to be
|
||||
// automatically updated
|
||||
func CredProviders(cfg *aws.Config, handlers request.Handlers) []credentials.Provider {
|
||||
return []credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
RemoteCredProvider(*cfg, handlers),
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
httpProviderAuthorizationEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN"
|
||||
httpProviderEnvVar = "AWS_CONTAINER_CREDENTIALS_FULL_URI"
|
||||
)
|
||||
|
||||
// RemoteCredProvider returns a credentials provider for the default remote
|
||||
// endpoints such as EC2 or ECS Roles.
|
||||
func RemoteCredProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||
if u := os.Getenv(httpProviderEnvVar); len(u) > 0 {
|
||||
return localHTTPCredProvider(cfg, handlers, u)
|
||||
}
|
||||
|
||||
if uri := os.Getenv(shareddefaults.ECSCredsProviderEnvVar); len(uri) > 0 {
|
||||
u := fmt.Sprintf("%s%s", shareddefaults.ECSContainerCredentialsURI, uri)
|
||||
return httpCredProvider(cfg, handlers, u)
|
||||
}
|
||||
|
||||
return ec2RoleProvider(cfg, handlers)
|
||||
}
|
||||
|
||||
var lookupHostFn = net.LookupHost
|
||||
|
||||
func isLoopbackHost(host string) (bool, error) {
|
||||
ip := net.ParseIP(host)
|
||||
if ip != nil {
|
||||
return ip.IsLoopback(), nil
|
||||
}
|
||||
|
||||
// Host is not an ip, perform lookup
|
||||
addrs, err := lookupHostFn(host)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if !net.ParseIP(addr).IsLoopback() {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func localHTTPCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider {
|
||||
var errMsg string
|
||||
|
||||
parsed, err := url.Parse(u)
|
||||
if err != nil {
|
||||
errMsg = fmt.Sprintf("invalid URL, %v", err)
|
||||
} else {
|
||||
host := aws.URLHostname(parsed)
|
||||
if len(host) == 0 {
|
||||
errMsg = "unable to parse host from local HTTP cred provider URL"
|
||||
} else if isLoopback, loopbackErr := isLoopbackHost(host); loopbackErr != nil {
|
||||
errMsg = fmt.Sprintf("failed to resolve host %q, %v", host, loopbackErr)
|
||||
} else if !isLoopback {
|
||||
errMsg = fmt.Sprintf("invalid endpoint host, %q, only loopback hosts are allowed.", host)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errMsg) > 0 {
|
||||
if cfg.Logger != nil {
|
||||
cfg.Logger.Log("Ignoring, HTTP credential provider", errMsg, err)
|
||||
}
|
||||
return credentials.ErrorProvider{
|
||||
Err: awserr.New("CredentialsEndpointError", errMsg, err),
|
||||
ProviderName: endpointcreds.ProviderName,
|
||||
}
|
||||
}
|
||||
|
||||
return httpCredProvider(cfg, handlers, u)
|
||||
}
|
||||
|
||||
func httpCredProvider(cfg aws.Config, handlers request.Handlers, u string) credentials.Provider {
|
||||
return endpointcreds.NewProviderClient(cfg, handlers, u,
|
||||
func(p *endpointcreds.Provider) {
|
||||
p.ExpiryWindow = 5 * time.Minute
|
||||
p.AuthorizationToken = os.Getenv(httpProviderAuthorizationEnvVar)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func ec2RoleProvider(cfg aws.Config, handlers request.Handlers) credentials.Provider {
|
||||
resolver := cfg.EndpointResolver
|
||||
if resolver == nil {
|
||||
resolver = endpoints.DefaultResolver()
|
||||
}
|
||||
|
||||
e, _ := resolver.EndpointFor(endpoints.Ec2metadataServiceID, "")
|
||||
return &ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.NewClient(cfg, handlers, e.URL, e.SigningRegion),
|
||||
ExpiryWindow: 5 * time.Minute,
|
||||
}
|
||||
}
|
||||
27
vendor/github.com/aws/aws-sdk-go/aws/defaults/shared_config.go
generated
vendored
Normal file
27
vendor/github.com/aws/aws-sdk-go/aws/defaults/shared_config.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/internal/shareddefaults"
|
||||
)
|
||||
|
||||
// SharedCredentialsFilename returns the SDK's default file path
|
||||
// for the shared credentials file.
|
||||
//
|
||||
// Builds the shared config file path based on the OS's platform.
|
||||
//
|
||||
// - Linux/Unix: $HOME/.aws/credentials
|
||||
// - Windows: %USERPROFILE%\.aws\credentials
|
||||
func SharedCredentialsFilename() string {
|
||||
return shareddefaults.SharedCredentialsFilename()
|
||||
}
|
||||
|
||||
// SharedConfigFilename returns the SDK's default file path for
|
||||
// the shared config file.
|
||||
//
|
||||
// Builds the shared config file path based on the OS's platform.
|
||||
//
|
||||
// - Linux/Unix: $HOME/.aws/config
|
||||
// - Windows: %USERPROFILE%\.aws\config
|
||||
func SharedConfigFilename() string {
|
||||
return shareddefaults.SharedConfigFilename()
|
||||
}
|
||||
56
vendor/github.com/aws/aws-sdk-go/aws/doc.go
generated
vendored
Normal file
56
vendor/github.com/aws/aws-sdk-go/aws/doc.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Package aws provides the core SDK's utilities and shared types. Use this package's
|
||||
// utilities to simplify setting and reading API operations parameters.
|
||||
//
|
||||
// Value and Pointer Conversion Utilities
|
||||
//
|
||||
// This package includes a helper conversion utility for each scalar type the SDK's
|
||||
// API use. These utilities make getting a pointer of the scalar, and dereferencing
|
||||
// a pointer easier.
|
||||
//
|
||||
// Each conversion utility comes in two forms. Value to Pointer and Pointer to Value.
|
||||
// The Pointer to value will safely dereference the pointer and return its value.
|
||||
// If the pointer was nil, the scalar's zero value will be returned.
|
||||
//
|
||||
// The value to pointer functions will be named after the scalar type. So get a
|
||||
// *string from a string value use the "String" function. This makes it easy to
|
||||
// to get pointer of a literal string value, because getting the address of a
|
||||
// literal requires assigning the value to a variable first.
|
||||
//
|
||||
// var strPtr *string
|
||||
//
|
||||
// // Without the SDK's conversion functions
|
||||
// str := "my string"
|
||||
// strPtr = &str
|
||||
//
|
||||
// // With the SDK's conversion functions
|
||||
// strPtr = aws.String("my string")
|
||||
//
|
||||
// // Convert *string to string value
|
||||
// str = aws.StringValue(strPtr)
|
||||
//
|
||||
// In addition to scalars the aws package also includes conversion utilities for
|
||||
// map and slice for commonly types used in API parameters. The map and slice
|
||||
// conversion functions use similar naming pattern as the scalar conversion
|
||||
// functions.
|
||||
//
|
||||
// var strPtrs []*string
|
||||
// var strs []string = []string{"Go", "Gophers", "Go"}
|
||||
//
|
||||
// // Convert []string to []*string
|
||||
// strPtrs = aws.StringSlice(strs)
|
||||
//
|
||||
// // Convert []*string to []string
|
||||
// strs = aws.StringValueSlice(strPtrs)
|
||||
//
|
||||
// SDK Default HTTP Client
|
||||
//
|
||||
// The SDK will use the http.DefaultClient if a HTTP client is not provided to
|
||||
// the SDK's Session, or service client constructor. This means that if the
|
||||
// http.DefaultClient is modified by other components of your application the
|
||||
// modifications will be picked up by the SDK as well.
|
||||
//
|
||||
// In some cases this might be intended, but it is a better practice to create
|
||||
// a custom HTTP Client to share explicitly through your application. You can
|
||||
// configure the SDK to use the custom HTTP Client by setting the HTTPClient
|
||||
// value of the SDK's Config type when creating a Session or service client.
|
||||
package aws
|
||||
162
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go
generated
vendored
Normal file
162
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/api.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
package ec2metadata
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/internal/sdkuri"
|
||||
)
|
||||
|
||||
// GetMetadata uses the path provided to request information from the EC2
|
||||
// instance metdata service. The content will be returned as a string, or
|
||||
// error if the request failed.
|
||||
func (c *EC2Metadata) GetMetadata(p string) (string, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetMetadata",
|
||||
HTTPMethod: "GET",
|
||||
HTTPPath: sdkuri.PathJoin("/meta-data", p),
|
||||
}
|
||||
|
||||
output := &metadataOutput{}
|
||||
req := c.NewRequest(op, nil, output)
|
||||
|
||||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// GetUserData returns the userdata that was configured for the service. If
|
||||
// there is no user-data setup for the EC2 instance a "NotFoundError" error
|
||||
// code will be returned.
|
||||
func (c *EC2Metadata) GetUserData() (string, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetUserData",
|
||||
HTTPMethod: "GET",
|
||||
HTTPPath: "/user-data",
|
||||
}
|
||||
|
||||
output := &metadataOutput{}
|
||||
req := c.NewRequest(op, nil, output)
|
||||
req.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
|
||||
if r.HTTPResponse.StatusCode == http.StatusNotFound {
|
||||
r.Error = awserr.New("NotFoundError", "user-data not found", r.Error)
|
||||
}
|
||||
})
|
||||
|
||||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// GetDynamicData uses the path provided to request information from the EC2
|
||||
// instance metadata service for dynamic data. The content will be returned
|
||||
// as a string, or error if the request failed.
|
||||
func (c *EC2Metadata) GetDynamicData(p string) (string, error) {
|
||||
op := &request.Operation{
|
||||
Name: "GetDynamicData",
|
||||
HTTPMethod: "GET",
|
||||
HTTPPath: sdkuri.PathJoin("/dynamic", p),
|
||||
}
|
||||
|
||||
output := &metadataOutput{}
|
||||
req := c.NewRequest(op, nil, output)
|
||||
|
||||
return output.Content, req.Send()
|
||||
}
|
||||
|
||||
// GetInstanceIdentityDocument retrieves an identity document describing an
|
||||
// instance. Error is returned if the request fails or is unable to parse
|
||||
// the response.
|
||||
func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument, error) {
|
||||
resp, err := c.GetDynamicData("instance-identity/document")
|
||||
if err != nil {
|
||||
return EC2InstanceIdentityDocument{},
|
||||
awserr.New("EC2MetadataRequestError",
|
||||
"failed to get EC2 instance identity document", err)
|
||||
}
|
||||
|
||||
doc := EC2InstanceIdentityDocument{}
|
||||
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&doc); err != nil {
|
||||
return EC2InstanceIdentityDocument{},
|
||||
awserr.New("SerializationError",
|
||||
"failed to decode EC2 instance identity document", err)
|
||||
}
|
||||
|
||||
return doc, nil
|
||||
}
|
||||
|
||||
// IAMInfo retrieves IAM info from the metadata API
|
||||
func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) {
|
||||
resp, err := c.GetMetadata("iam/info")
|
||||
if err != nil {
|
||||
return EC2IAMInfo{},
|
||||
awserr.New("EC2MetadataRequestError",
|
||||
"failed to get EC2 IAM info", err)
|
||||
}
|
||||
|
||||
info := EC2IAMInfo{}
|
||||
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&info); err != nil {
|
||||
return EC2IAMInfo{},
|
||||
awserr.New("SerializationError",
|
||||
"failed to decode EC2 IAM info", err)
|
||||
}
|
||||
|
||||
if info.Code != "Success" {
|
||||
errMsg := fmt.Sprintf("failed to get EC2 IAM Info (%s)", info.Code)
|
||||
return EC2IAMInfo{},
|
||||
awserr.New("EC2MetadataError", errMsg, nil)
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// Region returns the region the instance is running in.
|
||||
func (c *EC2Metadata) Region() (string, error) {
|
||||
resp, err := c.GetMetadata("placement/availability-zone")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// returns region without the suffix. Eg: us-west-2a becomes us-west-2
|
||||
return resp[:len(resp)-1], nil
|
||||
}
|
||||
|
||||
// Available returns if the application has access to the EC2 Metadata service.
|
||||
// Can be used to determine if application is running within an EC2 Instance and
|
||||
// the metadata service is available.
|
||||
func (c *EC2Metadata) Available() bool {
|
||||
if _, err := c.GetMetadata("instance-id"); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// An EC2IAMInfo provides the shape for unmarshaling
|
||||
// an IAM info from the metadata API
|
||||
type EC2IAMInfo struct {
|
||||
Code string
|
||||
LastUpdated time.Time
|
||||
InstanceProfileArn string
|
||||
InstanceProfileID string
|
||||
}
|
||||
|
||||
// An EC2InstanceIdentityDocument provides the shape for unmarshaling
|
||||
// an instance identity document
|
||||
type EC2InstanceIdentityDocument struct {
|
||||
DevpayProductCodes []string `json:"devpayProductCodes"`
|
||||
AvailabilityZone string `json:"availabilityZone"`
|
||||
PrivateIP string `json:"privateIp"`
|
||||
Version string `json:"version"`
|
||||
Region string `json:"region"`
|
||||
InstanceID string `json:"instanceId"`
|
||||
BillingProducts []string `json:"billingProducts"`
|
||||
InstanceType string `json:"instanceType"`
|
||||
AccountID string `json:"accountId"`
|
||||
PendingTime time.Time `json:"pendingTime"`
|
||||
ImageID string `json:"imageId"`
|
||||
KernelID string `json:"kernelId"`
|
||||
RamdiskID string `json:"ramdiskId"`
|
||||
Architecture string `json:"architecture"`
|
||||
}
|
||||
149
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
generated
vendored
Normal file
149
vendor/github.com/aws/aws-sdk-go/aws/ec2metadata/service.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// Package ec2metadata provides the client for making API calls to the
|
||||
// EC2 Metadata service.
|
||||
//
|
||||
// This package's client can be disabled completely by setting the environment
|
||||
// variable "AWS_EC2_METADATA_DISABLED=true". This environment variable set to
|
||||
// true instructs the SDK to disable the EC2 Metadata client. The client cannot
|
||||
// be used while the environemnt variable is set to true, (case insensitive).
|
||||
package ec2metadata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
)
|
||||
|
||||
// ServiceName is the name of the service.
|
||||
const ServiceName = "ec2metadata"
|
||||
const disableServiceEnvVar = "AWS_EC2_METADATA_DISABLED"
|
||||
|
||||
// A EC2Metadata is an EC2 Metadata service Client.
|
||||
type EC2Metadata struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// New creates a new instance of the EC2Metadata client with a session.
|
||||
// This client is safe to use across multiple goroutines.
|
||||
//
|
||||
//
|
||||
// Example:
|
||||
// // Create a EC2Metadata client from just a session.
|
||||
// svc := ec2metadata.New(mySession)
|
||||
//
|
||||
// // Create a EC2Metadata client with additional configuration
|
||||
// svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody))
|
||||
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata {
|
||||
c := p.ClientConfig(ServiceName, cfgs...)
|
||||
return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
|
||||
}
|
||||
|
||||
// NewClient returns a new EC2Metadata client. Should be used to create
|
||||
// a client when not using a session. Generally using just New with a session
|
||||
// is preferred.
|
||||
//
|
||||
// If an unmodified HTTP client is provided from the stdlib default, or no client
|
||||
// the EC2RoleProvider's EC2Metadata HTTP client's timeout will be shortened.
|
||||
// To disable this set Config.EC2MetadataDisableTimeoutOverride to false. Enabled by default.
|
||||
func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string, opts ...func(*client.Client)) *EC2Metadata {
|
||||
if !aws.BoolValue(cfg.EC2MetadataDisableTimeoutOverride) && httpClientZero(cfg.HTTPClient) {
|
||||
// If the http client is unmodified and this feature is not disabled
|
||||
// set custom timeouts for EC2Metadata requests.
|
||||
cfg.HTTPClient = &http.Client{
|
||||
// use a shorter timeout than default because the metadata
|
||||
// service is local if it is running, and to fail faster
|
||||
// if not running on an ec2 instance.
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
svc := &EC2Metadata{
|
||||
Client: client.New(
|
||||
cfg,
|
||||
metadata.ClientInfo{
|
||||
ServiceName: ServiceName,
|
||||
ServiceID: ServiceName,
|
||||
Endpoint: endpoint,
|
||||
APIVersion: "latest",
|
||||
},
|
||||
handlers,
|
||||
),
|
||||
}
|
||||
|
||||
svc.Handlers.Unmarshal.PushBack(unmarshalHandler)
|
||||
svc.Handlers.UnmarshalError.PushBack(unmarshalError)
|
||||
svc.Handlers.Validate.Clear()
|
||||
svc.Handlers.Validate.PushBack(validateEndpointHandler)
|
||||
|
||||
// Disable the EC2 Metadata service if the environment variable is set.
|
||||
// This shortcirctes the service's functionality to always fail to send
|
||||
// requests.
|
||||
if strings.ToLower(os.Getenv(disableServiceEnvVar)) == "true" {
|
||||
svc.Handlers.Send.SwapNamed(request.NamedHandler{
|
||||
Name: corehandlers.SendHandler.Name,
|
||||
Fn: func(r *request.Request) {
|
||||
r.Error = awserr.New(
|
||||
request.CanceledErrorCode,
|
||||
"EC2 IMDS access disabled via "+disableServiceEnvVar+" env var",
|
||||
nil)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Add additional options to the service config
|
||||
for _, option := range opts {
|
||||
option(svc.Client)
|
||||
}
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
func httpClientZero(c *http.Client) bool {
|
||||
return c == nil || (c.Transport == nil && c.CheckRedirect == nil && c.Jar == nil && c.Timeout == 0)
|
||||
}
|
||||
|
||||
type metadataOutput struct {
|
||||
Content string
|
||||
}
|
||||
|
||||
func unmarshalHandler(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
b := &bytes.Buffer{}
|
||||
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
|
||||
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err)
|
||||
return
|
||||
}
|
||||
|
||||
if data, ok := r.Data.(*metadataOutput); ok {
|
||||
data.Content = b.String()
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshalError(r *request.Request) {
|
||||
defer r.HTTPResponse.Body.Close()
|
||||
b := &bytes.Buffer{}
|
||||
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
|
||||
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Response body format is not consistent between metadata endpoints.
|
||||
// Grab the error message as a string and include that as the source error
|
||||
r.Error = awserr.New("EC2MetadataError", "failed to make EC2Metadata request", errors.New(b.String()))
|
||||
}
|
||||
|
||||
func validateEndpointHandler(r *request.Request) {
|
||||
if r.ClientInfo.Endpoint == "" {
|
||||
r.Error = aws.ErrMissingEndpoint
|
||||
}
|
||||
}
|
||||
155
vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode.go
generated
vendored
Normal file
155
vendor/github.com/aws/aws-sdk-go/aws/endpoints/decode.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
type modelDefinition map[string]json.RawMessage
|
||||
|
||||
// A DecodeModelOptions are the options for how the endpoints model definition
|
||||
// are decoded.
|
||||
type DecodeModelOptions struct {
|
||||
SkipCustomizations bool
|
||||
}
|
||||
|
||||
// Set combines all of the option functions together.
|
||||
func (d *DecodeModelOptions) Set(optFns ...func(*DecodeModelOptions)) {
|
||||
for _, fn := range optFns {
|
||||
fn(d)
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeModel unmarshals a Regions and Endpoint model definition file into
|
||||
// a endpoint Resolver. If the file format is not supported, or an error occurs
|
||||
// when unmarshaling the model an error will be returned.
|
||||
//
|
||||
// Casting the return value of this func to a EnumPartitions will
|
||||
// allow you to get a list of the partitions in the order the endpoints
|
||||
// will be resolved in.
|
||||
//
|
||||
// resolver, err := endpoints.DecodeModel(reader)
|
||||
//
|
||||
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
|
||||
// for _, p := range partitions {
|
||||
// // ... inspect partitions
|
||||
// }
|
||||
func DecodeModel(r io.Reader, optFns ...func(*DecodeModelOptions)) (Resolver, error) {
|
||||
var opts DecodeModelOptions
|
||||
opts.Set(optFns...)
|
||||
|
||||
// Get the version of the partition file to determine what
|
||||
// unmarshaling model to use.
|
||||
modelDef := modelDefinition{}
|
||||
if err := json.NewDecoder(r).Decode(&modelDef); err != nil {
|
||||
return nil, newDecodeModelError("failed to decode endpoints model", err)
|
||||
}
|
||||
|
||||
var version string
|
||||
if b, ok := modelDef["version"]; ok {
|
||||
version = string(b)
|
||||
} else {
|
||||
return nil, newDecodeModelError("endpoints version not found in model", nil)
|
||||
}
|
||||
|
||||
if version == "3" {
|
||||
return decodeV3Endpoints(modelDef, opts)
|
||||
}
|
||||
|
||||
return nil, newDecodeModelError(
|
||||
fmt.Sprintf("endpoints version %s, not supported", version), nil)
|
||||
}
|
||||
|
||||
func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resolver, error) {
|
||||
b, ok := modelDef["partitions"]
|
||||
if !ok {
|
||||
return nil, newDecodeModelError("endpoints model missing partitions", nil)
|
||||
}
|
||||
|
||||
ps := partitions{}
|
||||
if err := json.Unmarshal(b, &ps); err != nil {
|
||||
return nil, newDecodeModelError("failed to decode endpoints model", err)
|
||||
}
|
||||
|
||||
if opts.SkipCustomizations {
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
// Customization
|
||||
for i := 0; i < len(ps); i++ {
|
||||
p := &ps[i]
|
||||
custAddEC2Metadata(p)
|
||||
custAddS3DualStack(p)
|
||||
custRmIotDataService(p)
|
||||
custFixAppAutoscalingChina(p)
|
||||
}
|
||||
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
func custAddS3DualStack(p *partition) {
|
||||
if p.ID != "aws" {
|
||||
return
|
||||
}
|
||||
|
||||
s, ok := p.Services["s3"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
s.Defaults.HasDualStack = boxedTrue
|
||||
s.Defaults.DualStackHostname = "{service}.dualstack.{region}.{dnsSuffix}"
|
||||
|
||||
p.Services["s3"] = s
|
||||
}
|
||||
|
||||
func custAddEC2Metadata(p *partition) {
|
||||
p.Services["ec2metadata"] = service{
|
||||
IsRegionalized: boxedFalse,
|
||||
PartitionEndpoint: "aws-global",
|
||||
Endpoints: endpoints{
|
||||
"aws-global": endpoint{
|
||||
Hostname: "169.254.169.254/latest",
|
||||
Protocols: []string{"http"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func custRmIotDataService(p *partition) {
|
||||
delete(p.Services, "data.iot")
|
||||
}
|
||||
|
||||
func custFixAppAutoscalingChina(p *partition) {
|
||||
if p.ID != "aws-cn" {
|
||||
return
|
||||
}
|
||||
|
||||
const serviceName = "application-autoscaling"
|
||||
s, ok := p.Services[serviceName]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
const expectHostname = `autoscaling.{region}.amazonaws.com`
|
||||
if e, a := s.Defaults.Hostname, expectHostname; e != a {
|
||||
fmt.Printf("custFixAppAutoscalingChina: ignoring customization, expected %s, got %s\n", e, a)
|
||||
return
|
||||
}
|
||||
|
||||
s.Defaults.Hostname = expectHostname + ".cn"
|
||||
p.Services[serviceName] = s
|
||||
}
|
||||
|
||||
type decodeModelError struct {
|
||||
awsError
|
||||
}
|
||||
|
||||
func newDecodeModelError(msg string, err error) decodeModelError {
|
||||
return decodeModelError{
|
||||
awsError: awserr.New("DecodeEndpointsModelError", msg, err),
|
||||
}
|
||||
}
|
||||
3372
vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
Normal file
3372
vendor/github.com/aws/aws-sdk-go/aws/endpoints/defaults.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
66
vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go
generated
vendored
Normal file
66
vendor/github.com/aws/aws-sdk-go/aws/endpoints/doc.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Package endpoints provides the types and functionality for defining regions
|
||||
// and endpoints, as well as querying those definitions.
|
||||
//
|
||||
// The SDK's Regions and Endpoints metadata is code generated into the endpoints
|
||||
// package, and is accessible via the DefaultResolver function. This function
|
||||
// returns a endpoint Resolver will search the metadata and build an associated
|
||||
// endpoint if one is found. The default resolver will search all partitions
|
||||
// known by the SDK. e.g AWS Standard (aws), AWS China (aws-cn), and
|
||||
// AWS GovCloud (US) (aws-us-gov).
|
||||
// .
|
||||
//
|
||||
// Enumerating Regions and Endpoint Metadata
|
||||
//
|
||||
// Casting the Resolver returned by DefaultResolver to a EnumPartitions interface
|
||||
// will allow you to get access to the list of underlying Partitions with the
|
||||
// Partitions method. This is helpful if you want to limit the SDK's endpoint
|
||||
// resolving to a single partition, or enumerate regions, services, and endpoints
|
||||
// in the partition.
|
||||
//
|
||||
// resolver := endpoints.DefaultResolver()
|
||||
// partitions := resolver.(endpoints.EnumPartitions).Partitions()
|
||||
//
|
||||
// for _, p := range partitions {
|
||||
// fmt.Println("Regions for", p.ID())
|
||||
// for id, _ := range p.Regions() {
|
||||
// fmt.Println("*", id)
|
||||
// }
|
||||
//
|
||||
// fmt.Println("Services for", p.ID())
|
||||
// for id, _ := range p.Services() {
|
||||
// fmt.Println("*", id)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Using Custom Endpoints
|
||||
//
|
||||
// The endpoints package also gives you the ability to use your own logic how
|
||||
// endpoints are resolved. This is a great way to define a custom endpoint
|
||||
// for select services, without passing that logic down through your code.
|
||||
//
|
||||
// If a type implements the Resolver interface it can be used to resolve
|
||||
// endpoints. To use this with the SDK's Session and Config set the value
|
||||
// of the type to the EndpointsResolver field of aws.Config when initializing
|
||||
// the session, or service client.
|
||||
//
|
||||
// In addition the ResolverFunc is a wrapper for a func matching the signature
|
||||
// of Resolver.EndpointFor, converting it to a type that satisfies the
|
||||
// Resolver interface.
|
||||
//
|
||||
//
|
||||
// myCustomResolver := func(service, region string, optFns ...func(*endpoints.Options)) (endpoints.ResolvedEndpoint, error) {
|
||||
// if service == endpoints.S3ServiceID {
|
||||
// return endpoints.ResolvedEndpoint{
|
||||
// URL: "s3.custom.endpoint.com",
|
||||
// SigningRegion: "custom-signing-region",
|
||||
// }, nil
|
||||
// }
|
||||
//
|
||||
// return endpoints.DefaultResolver().EndpointFor(service, region, optFns...)
|
||||
// }
|
||||
//
|
||||
// sess := session.Must(session.NewSession(&aws.Config{
|
||||
// Region: aws.String("us-west-2"),
|
||||
// EndpointResolver: endpoints.ResolverFunc(myCustomResolver),
|
||||
// }))
|
||||
package endpoints
|
||||
449
vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go
generated
vendored
Normal file
449
vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go
generated
vendored
Normal file
@@ -0,0 +1,449 @@
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
// Options provide the configuration needed to direct how the
|
||||
// endpoints will be resolved.
|
||||
type Options struct {
|
||||
// DisableSSL forces the endpoint to be resolved as HTTP.
|
||||
// instead of HTTPS if the service supports it.
|
||||
DisableSSL bool
|
||||
|
||||
// Sets the resolver to resolve the endpoint as a dualstack endpoint
|
||||
// for the service. If dualstack support for a service is not known and
|
||||
// StrictMatching is not enabled a dualstack endpoint for the service will
|
||||
// be returned. This endpoint may not be valid. If StrictMatching is
|
||||
// enabled only services that are known to support dualstack will return
|
||||
// dualstack endpoints.
|
||||
UseDualStack bool
|
||||
|
||||
// Enables strict matching of services and regions resolved endpoints.
|
||||
// If the partition doesn't enumerate the exact service and region an
|
||||
// error will be returned. This option will prevent returning endpoints
|
||||
// that look valid, but may not resolve to any real endpoint.
|
||||
StrictMatching bool
|
||||
|
||||
// Enables resolving a service endpoint based on the region provided if the
|
||||
// service does not exist. The service endpoint ID will be used as the service
|
||||
// domain name prefix. By default the endpoint resolver requires the service
|
||||
// to be known when resolving endpoints.
|
||||
//
|
||||
// If resolving an endpoint on the partition list the provided region will
|
||||
// be used to determine which partition's domain name pattern to the service
|
||||
// endpoint ID with. If both the service and region are unkonwn and resolving
|
||||
// the endpoint on partition list an UnknownEndpointError error will be returned.
|
||||
//
|
||||
// If resolving and endpoint on a partition specific resolver that partition's
|
||||
// domain name pattern will be used with the service endpoint ID. If both
|
||||
// region and service do not exist when resolving an endpoint on a specific
|
||||
// partition the partition's domain pattern will be used to combine the
|
||||
// endpoint and region together.
|
||||
//
|
||||
// This option is ignored if StrictMatching is enabled.
|
||||
ResolveUnknownService bool
|
||||
}
|
||||
|
||||
// Set combines all of the option functions together.
|
||||
func (o *Options) Set(optFns ...func(*Options)) {
|
||||
for _, fn := range optFns {
|
||||
fn(o)
|
||||
}
|
||||
}
|
||||
|
||||
// DisableSSLOption sets the DisableSSL options. Can be used as a functional
|
||||
// option when resolving endpoints.
|
||||
func DisableSSLOption(o *Options) {
|
||||
o.DisableSSL = true
|
||||
}
|
||||
|
||||
// UseDualStackOption sets the UseDualStack option. Can be used as a functional
|
||||
// option when resolving endpoints.
|
||||
func UseDualStackOption(o *Options) {
|
||||
o.UseDualStack = true
|
||||
}
|
||||
|
||||
// StrictMatchingOption sets the StrictMatching option. Can be used as a functional
|
||||
// option when resolving endpoints.
|
||||
func StrictMatchingOption(o *Options) {
|
||||
o.StrictMatching = true
|
||||
}
|
||||
|
||||
// ResolveUnknownServiceOption sets the ResolveUnknownService option. Can be used
|
||||
// as a functional option when resolving endpoints.
|
||||
func ResolveUnknownServiceOption(o *Options) {
|
||||
o.ResolveUnknownService = true
|
||||
}
|
||||
|
||||
// A Resolver provides the interface for functionality to resolve endpoints.
|
||||
// The build in Partition and DefaultResolver return value satisfy this interface.
|
||||
type Resolver interface {
|
||||
EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
|
||||
}
|
||||
|
||||
// ResolverFunc is a helper utility that wraps a function so it satisfies the
|
||||
// Resolver interface. This is useful when you want to add additional endpoint
|
||||
// resolving logic, or stub out specific endpoints with custom values.
|
||||
type ResolverFunc func(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
|
||||
|
||||
// EndpointFor wraps the ResolverFunc function to satisfy the Resolver interface.
|
||||
func (fn ResolverFunc) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return fn(service, region, opts...)
|
||||
}
|
||||
|
||||
var schemeRE = regexp.MustCompile("^([^:]+)://")
|
||||
|
||||
// AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no
|
||||
// scheme. If disableSSL is true HTTP will set HTTP instead of the default HTTPS.
|
||||
//
|
||||
// If disableSSL is set, it will only set the URL's scheme if the URL does not
|
||||
// contain a scheme.
|
||||
func AddScheme(endpoint string, disableSSL bool) string {
|
||||
if !schemeRE.MatchString(endpoint) {
|
||||
scheme := "https"
|
||||
if disableSSL {
|
||||
scheme = "http"
|
||||
}
|
||||
endpoint = fmt.Sprintf("%s://%s", scheme, endpoint)
|
||||
}
|
||||
|
||||
return endpoint
|
||||
}
|
||||
|
||||
// EnumPartitions a provides a way to retrieve the underlying partitions that
|
||||
// make up the SDK's default Resolver, or any resolver decoded from a model
|
||||
// file.
|
||||
//
|
||||
// Use this interface with DefaultResolver and DecodeModels to get the list of
|
||||
// Partitions.
|
||||
type EnumPartitions interface {
|
||||
Partitions() []Partition
|
||||
}
|
||||
|
||||
// RegionsForService returns a map of regions for the partition and service.
|
||||
// If either the partition or service does not exist false will be returned
|
||||
// as the second parameter.
|
||||
//
|
||||
// This example shows how to get the regions for DynamoDB in the AWS partition.
|
||||
// rs, exists := endpoints.RegionsForService(endpoints.DefaultPartitions(), endpoints.AwsPartitionID, endpoints.DynamodbServiceID)
|
||||
//
|
||||
// This is equivalent to using the partition directly.
|
||||
// rs := endpoints.AwsPartition().Services()[endpoints.DynamodbServiceID].Regions()
|
||||
func RegionsForService(ps []Partition, partitionID, serviceID string) (map[string]Region, bool) {
|
||||
for _, p := range ps {
|
||||
if p.ID() != partitionID {
|
||||
continue
|
||||
}
|
||||
if _, ok := p.p.Services[serviceID]; !ok {
|
||||
break
|
||||
}
|
||||
|
||||
s := Service{
|
||||
id: serviceID,
|
||||
p: p.p,
|
||||
}
|
||||
return s.Regions(), true
|
||||
}
|
||||
|
||||
return map[string]Region{}, false
|
||||
}
|
||||
|
||||
// PartitionForRegion returns the first partition which includes the region
|
||||
// passed in. This includes both known regions and regions which match
|
||||
// a pattern supported by the partition which may include regions that are
|
||||
// not explicitly known by the partition. Use the Regions method of the
|
||||
// returned Partition if explicit support is needed.
|
||||
func PartitionForRegion(ps []Partition, regionID string) (Partition, bool) {
|
||||
for _, p := range ps {
|
||||
if _, ok := p.p.Regions[regionID]; ok || p.p.RegionRegex.MatchString(regionID) {
|
||||
return p, true
|
||||
}
|
||||
}
|
||||
|
||||
return Partition{}, false
|
||||
}
|
||||
|
||||
// A Partition provides the ability to enumerate the partition's regions
|
||||
// and services.
|
||||
type Partition struct {
|
||||
id string
|
||||
p *partition
|
||||
}
|
||||
|
||||
// ID returns the identifier of the partition.
|
||||
func (p Partition) ID() string { return p.id }
|
||||
|
||||
// EndpointFor attempts to resolve the endpoint based on service and region.
|
||||
// See Options for information on configuring how the endpoint is resolved.
|
||||
//
|
||||
// If the service cannot be found in the metadata the UnknownServiceError
|
||||
// error will be returned. This validation will occur regardless if
|
||||
// StrictMatching is enabled. To enable resolving unknown services set the
|
||||
// "ResolveUnknownService" option to true. When StrictMatching is disabled
|
||||
// this option allows the partition resolver to resolve a endpoint based on
|
||||
// the service endpoint ID provided.
|
||||
//
|
||||
// When resolving endpoints you can choose to enable StrictMatching. This will
|
||||
// require the provided service and region to be known by the partition.
|
||||
// If the endpoint cannot be strictly resolved an error will be returned. This
|
||||
// mode is useful to ensure the endpoint resolved is valid. Without
|
||||
// StrictMatching enabled the endpoint returned my look valid but may not work.
|
||||
// StrictMatching requires the SDK to be updated if you want to take advantage
|
||||
// of new regions and services expansions.
|
||||
//
|
||||
// Errors that can be returned.
|
||||
// * UnknownServiceError
|
||||
// * UnknownEndpointError
|
||||
func (p Partition) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return p.p.EndpointFor(service, region, opts...)
|
||||
}
|
||||
|
||||
// Regions returns a map of Regions indexed by their ID. This is useful for
|
||||
// enumerating over the regions in a partition.
|
||||
func (p Partition) Regions() map[string]Region {
|
||||
rs := map[string]Region{}
|
||||
for id, r := range p.p.Regions {
|
||||
rs[id] = Region{
|
||||
id: id,
|
||||
desc: r.Description,
|
||||
p: p.p,
|
||||
}
|
||||
}
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
// Services returns a map of Service indexed by their ID. This is useful for
|
||||
// enumerating over the services in a partition.
|
||||
func (p Partition) Services() map[string]Service {
|
||||
ss := map[string]Service{}
|
||||
for id := range p.p.Services {
|
||||
ss[id] = Service{
|
||||
id: id,
|
||||
p: p.p,
|
||||
}
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
// A Region provides information about a region, and ability to resolve an
|
||||
// endpoint from the context of a region, given a service.
|
||||
type Region struct {
|
||||
id, desc string
|
||||
p *partition
|
||||
}
|
||||
|
||||
// ID returns the region's identifier.
|
||||
func (r Region) ID() string { return r.id }
|
||||
|
||||
// Description returns the region's description. The region description
|
||||
// is free text, it can be empty, and it may change between SDK releases.
|
||||
func (r Region) Description() string { return r.desc }
|
||||
|
||||
// ResolveEndpoint resolves an endpoint from the context of the region given
|
||||
// a service. See Partition.EndpointFor for usage and errors that can be returned.
|
||||
func (r Region) ResolveEndpoint(service string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return r.p.EndpointFor(service, r.id, opts...)
|
||||
}
|
||||
|
||||
// Services returns a list of all services that are known to be in this region.
|
||||
func (r Region) Services() map[string]Service {
|
||||
ss := map[string]Service{}
|
||||
for id, s := range r.p.Services {
|
||||
if _, ok := s.Endpoints[r.id]; ok {
|
||||
ss[id] = Service{
|
||||
id: id,
|
||||
p: r.p,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
// A Service provides information about a service, and ability to resolve an
|
||||
// endpoint from the context of a service, given a region.
|
||||
type Service struct {
|
||||
id string
|
||||
p *partition
|
||||
}
|
||||
|
||||
// ID returns the identifier for the service.
|
||||
func (s Service) ID() string { return s.id }
|
||||
|
||||
// ResolveEndpoint resolves an endpoint from the context of a service given
|
||||
// a region. See Partition.EndpointFor for usage and errors that can be returned.
|
||||
func (s Service) ResolveEndpoint(region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return s.p.EndpointFor(s.id, region, opts...)
|
||||
}
|
||||
|
||||
// Regions returns a map of Regions that the service is present in.
|
||||
//
|
||||
// A region is the AWS region the service exists in. Whereas a Endpoint is
|
||||
// an URL that can be resolved to a instance of a service.
|
||||
func (s Service) Regions() map[string]Region {
|
||||
rs := map[string]Region{}
|
||||
for id := range s.p.Services[s.id].Endpoints {
|
||||
if r, ok := s.p.Regions[id]; ok {
|
||||
rs[id] = Region{
|
||||
id: id,
|
||||
desc: r.Description,
|
||||
p: s.p,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
// Endpoints returns a map of Endpoints indexed by their ID for all known
|
||||
// endpoints for a service.
|
||||
//
|
||||
// A region is the AWS region the service exists in. Whereas a Endpoint is
|
||||
// an URL that can be resolved to a instance of a service.
|
||||
func (s Service) Endpoints() map[string]Endpoint {
|
||||
es := map[string]Endpoint{}
|
||||
for id := range s.p.Services[s.id].Endpoints {
|
||||
es[id] = Endpoint{
|
||||
id: id,
|
||||
serviceID: s.id,
|
||||
p: s.p,
|
||||
}
|
||||
}
|
||||
|
||||
return es
|
||||
}
|
||||
|
||||
// A Endpoint provides information about endpoints, and provides the ability
|
||||
// to resolve that endpoint for the service, and the region the endpoint
|
||||
// represents.
|
||||
type Endpoint struct {
|
||||
id string
|
||||
serviceID string
|
||||
p *partition
|
||||
}
|
||||
|
||||
// ID returns the identifier for an endpoint.
|
||||
func (e Endpoint) ID() string { return e.id }
|
||||
|
||||
// ServiceID returns the identifier the endpoint belongs to.
|
||||
func (e Endpoint) ServiceID() string { return e.serviceID }
|
||||
|
||||
// ResolveEndpoint resolves an endpoint from the context of a service and
|
||||
// region the endpoint represents. See Partition.EndpointFor for usage and
|
||||
// errors that can be returned.
|
||||
func (e Endpoint) ResolveEndpoint(opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
return e.p.EndpointFor(e.serviceID, e.id, opts...)
|
||||
}
|
||||
|
||||
// A ResolvedEndpoint is an endpoint that has been resolved based on a partition
|
||||
// service, and region.
|
||||
type ResolvedEndpoint struct {
|
||||
// The endpoint URL
|
||||
URL string
|
||||
|
||||
// The region that should be used for signing requests.
|
||||
SigningRegion string
|
||||
|
||||
// The service name that should be used for signing requests.
|
||||
SigningName string
|
||||
|
||||
// States that the signing name for this endpoint was derived from metadata
|
||||
// passed in, but was not explicitly modeled.
|
||||
SigningNameDerived bool
|
||||
|
||||
// The signing method that should be used for signing requests.
|
||||
SigningMethod string
|
||||
}
|
||||
|
||||
// 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 awserr.Error
|
||||
|
||||
// A EndpointNotFoundError is returned when in StrictMatching mode, and the
|
||||
// endpoint for the service and region cannot be found in any of the partitions.
|
||||
type EndpointNotFoundError struct {
|
||||
awsError
|
||||
Partition string
|
||||
Service string
|
||||
Region string
|
||||
}
|
||||
|
||||
// A UnknownServiceError is returned when the service does not resolve to an
|
||||
// endpoint. Includes a list of all known services for the partition. Returned
|
||||
// when a partition does not support the service.
|
||||
type UnknownServiceError struct {
|
||||
awsError
|
||||
Partition string
|
||||
Service string
|
||||
Known []string
|
||||
}
|
||||
|
||||
// NewUnknownServiceError builds and returns UnknownServiceError.
|
||||
func NewUnknownServiceError(p, s string, known []string) UnknownServiceError {
|
||||
return UnknownServiceError{
|
||||
awsError: awserr.New("UnknownServiceError",
|
||||
"could not resolve endpoint for unknown service", nil),
|
||||
Partition: p,
|
||||
Service: s,
|
||||
Known: known,
|
||||
}
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
func (e UnknownServiceError) Error() string {
|
||||
extra := fmt.Sprintf("partition: %q, service: %q",
|
||||
e.Partition, e.Service)
|
||||
if len(e.Known) > 0 {
|
||||
extra += fmt.Sprintf(", known: %v", e.Known)
|
||||
}
|
||||
return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
func (e UnknownServiceError) String() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// A UnknownEndpointError is returned when in StrictMatching mode and the
|
||||
// service is valid, but the region does not resolve to an endpoint. Includes
|
||||
// a list of all known endpoints for the service.
|
||||
type UnknownEndpointError struct {
|
||||
awsError
|
||||
Partition string
|
||||
Service string
|
||||
Region string
|
||||
Known []string
|
||||
}
|
||||
|
||||
// NewUnknownEndpointError builds and returns UnknownEndpointError.
|
||||
func NewUnknownEndpointError(p, s, r string, known []string) UnknownEndpointError {
|
||||
return UnknownEndpointError{
|
||||
awsError: awserr.New("UnknownEndpointError",
|
||||
"could not resolve endpoint", nil),
|
||||
Partition: p,
|
||||
Service: s,
|
||||
Region: r,
|
||||
Known: known,
|
||||
}
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
func (e UnknownEndpointError) Error() string {
|
||||
extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
|
||||
e.Partition, e.Service, e.Region)
|
||||
if len(e.Known) > 0 {
|
||||
extra += fmt.Sprintf(", known: %v", e.Known)
|
||||
}
|
||||
return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
|
||||
}
|
||||
|
||||
// String returns the string representation of the error.
|
||||
func (e UnknownEndpointError) String() string {
|
||||
return e.Error()
|
||||
}
|
||||
307
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go
generated
vendored
Normal file
307
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go
generated
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type partitions []partition
|
||||
|
||||
func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
|
||||
var opt Options
|
||||
opt.Set(opts...)
|
||||
|
||||
for i := 0; i < len(ps); i++ {
|
||||
if !ps[i].canResolveEndpoint(service, region, opt.StrictMatching) {
|
||||
continue
|
||||
}
|
||||
|
||||
return ps[i].EndpointFor(service, region, opts...)
|
||||
}
|
||||
|
||||
// If loose matching fallback to first partition format to use
|
||||
// when resolving the endpoint.
|
||||
if !opt.StrictMatching && len(ps) > 0 {
|
||||
return ps[0].EndpointFor(service, region, opts...)
|
||||
}
|
||||
|
||||
return ResolvedEndpoint{}, NewUnknownEndpointError("all partitions", service, region, []string{})
|
||||
}
|
||||
|
||||
// Partitions satisfies the EnumPartitions interface and returns a list
|
||||
// of Partitions representing each partition represented in the SDK's
|
||||
// endpoints model.
|
||||
func (ps partitions) Partitions() []Partition {
|
||||
parts := make([]Partition, 0, len(ps))
|
||||
for i := 0; i < len(ps); i++ {
|
||||
parts = append(parts, ps[i].Partition())
|
||||
}
|
||||
|
||||
return parts
|
||||
}
|
||||
|
||||
type partition struct {
|
||||
ID string `json:"partition"`
|
||||
Name string `json:"partitionName"`
|
||||
DNSSuffix string `json:"dnsSuffix"`
|
||||
RegionRegex regionRegex `json:"regionRegex"`
|
||||
Defaults endpoint `json:"defaults"`
|
||||
Regions regions `json:"regions"`
|
||||
Services services `json:"services"`
|
||||
}
|
||||
|
||||
func (p partition) Partition() Partition {
|
||||
return Partition{
|
||||
id: p.ID,
|
||||
p: &p,
|
||||
}
|
||||
}
|
||||
|
||||
func (p partition) canResolveEndpoint(service, region string, strictMatch bool) bool {
|
||||
s, hasService := p.Services[service]
|
||||
_, hasEndpoint := s.Endpoints[region]
|
||||
|
||||
if hasEndpoint && hasService {
|
||||
return true
|
||||
}
|
||||
|
||||
if strictMatch {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.RegionRegex.MatchString(region)
|
||||
}
|
||||
|
||||
func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) {
|
||||
var opt Options
|
||||
opt.Set(opts...)
|
||||
|
||||
s, hasService := p.Services[service]
|
||||
if !(hasService || opt.ResolveUnknownService) {
|
||||
// Only return error if the resolver will not fallback to creating
|
||||
// endpoint based on service endpoint ID passed in.
|
||||
return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services))
|
||||
}
|
||||
|
||||
e, hasEndpoint := s.endpointForRegion(region)
|
||||
if !hasEndpoint && opt.StrictMatching {
|
||||
return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints))
|
||||
}
|
||||
|
||||
defs := []endpoint{p.Defaults, s.Defaults}
|
||||
return e.resolve(service, region, p.DNSSuffix, defs, opt), nil
|
||||
}
|
||||
|
||||
func serviceList(ss services) []string {
|
||||
list := make([]string, 0, len(ss))
|
||||
for k := range ss {
|
||||
list = append(list, k)
|
||||
}
|
||||
return list
|
||||
}
|
||||
func endpointList(es endpoints) []string {
|
||||
list := make([]string, 0, len(es))
|
||||
for k := range es {
|
||||
list = append(list, k)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
type regionRegex struct {
|
||||
*regexp.Regexp
|
||||
}
|
||||
|
||||
func (rr *regionRegex) UnmarshalJSON(b []byte) (err error) {
|
||||
// Strip leading and trailing quotes
|
||||
regex, err := strconv.Unquote(string(b))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to strip quotes from regex, %v", err)
|
||||
}
|
||||
|
||||
rr.Regexp, err = regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to unmarshal region regex, %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type regions map[string]region
|
||||
|
||||
type region struct {
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type services map[string]service
|
||||
|
||||
type service struct {
|
||||
PartitionEndpoint string `json:"partitionEndpoint"`
|
||||
IsRegionalized boxedBool `json:"isRegionalized,omitempty"`
|
||||
Defaults endpoint `json:"defaults"`
|
||||
Endpoints endpoints `json:"endpoints"`
|
||||
}
|
||||
|
||||
func (s *service) endpointForRegion(region string) (endpoint, bool) {
|
||||
if s.IsRegionalized == boxedFalse {
|
||||
return s.Endpoints[s.PartitionEndpoint], region == s.PartitionEndpoint
|
||||
}
|
||||
|
||||
if e, ok := s.Endpoints[region]; ok {
|
||||
return e, true
|
||||
}
|
||||
|
||||
// Unable to find any matching endpoint, return
|
||||
// blank that will be used for generic endpoint creation.
|
||||
return endpoint{}, false
|
||||
}
|
||||
|
||||
type endpoints map[string]endpoint
|
||||
|
||||
type endpoint struct {
|
||||
Hostname string `json:"hostname"`
|
||||
Protocols []string `json:"protocols"`
|
||||
CredentialScope credentialScope `json:"credentialScope"`
|
||||
|
||||
// Custom fields not modeled
|
||||
HasDualStack boxedBool `json:"-"`
|
||||
DualStackHostname string `json:"-"`
|
||||
|
||||
// Signature Version not used
|
||||
SignatureVersions []string `json:"signatureVersions"`
|
||||
|
||||
// SSLCommonName not used.
|
||||
SSLCommonName string `json:"sslCommonName"`
|
||||
}
|
||||
|
||||
const (
|
||||
defaultProtocol = "https"
|
||||
defaultSigner = "v4"
|
||||
)
|
||||
|
||||
var (
|
||||
protocolPriority = []string{"https", "http"}
|
||||
signerPriority = []string{"v4", "v2"}
|
||||
)
|
||||
|
||||
func getByPriority(s []string, p []string, def string) string {
|
||||
if len(s) == 0 {
|
||||
return def
|
||||
}
|
||||
|
||||
for i := 0; i < len(p); i++ {
|
||||
for j := 0; j < len(s); j++ {
|
||||
if s[j] == p[i] {
|
||||
return s[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s[0]
|
||||
}
|
||||
|
||||
func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint {
|
||||
var merged endpoint
|
||||
for _, def := range defs {
|
||||
merged.mergeIn(def)
|
||||
}
|
||||
merged.mergeIn(e)
|
||||
e = merged
|
||||
|
||||
hostname := e.Hostname
|
||||
|
||||
// Offset the hostname for dualstack if enabled
|
||||
if opts.UseDualStack && e.HasDualStack == boxedTrue {
|
||||
hostname = e.DualStackHostname
|
||||
}
|
||||
|
||||
u := strings.Replace(hostname, "{service}", service, 1)
|
||||
u = strings.Replace(u, "{region}", region, 1)
|
||||
u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
|
||||
|
||||
scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
|
||||
u = fmt.Sprintf("%s://%s", scheme, u)
|
||||
|
||||
signingRegion := e.CredentialScope.Region
|
||||
if len(signingRegion) == 0 {
|
||||
signingRegion = region
|
||||
}
|
||||
|
||||
signingName := e.CredentialScope.Service
|
||||
var signingNameDerived bool
|
||||
if len(signingName) == 0 {
|
||||
signingName = service
|
||||
signingNameDerived = true
|
||||
}
|
||||
|
||||
return ResolvedEndpoint{
|
||||
URL: u,
|
||||
SigningRegion: signingRegion,
|
||||
SigningName: signingName,
|
||||
SigningNameDerived: signingNameDerived,
|
||||
SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
|
||||
}
|
||||
}
|
||||
|
||||
func getEndpointScheme(protocols []string, disableSSL bool) string {
|
||||
if disableSSL {
|
||||
return "http"
|
||||
}
|
||||
|
||||
return getByPriority(protocols, protocolPriority, defaultProtocol)
|
||||
}
|
||||
|
||||
func (e *endpoint) mergeIn(other endpoint) {
|
||||
if len(other.Hostname) > 0 {
|
||||
e.Hostname = other.Hostname
|
||||
}
|
||||
if len(other.Protocols) > 0 {
|
||||
e.Protocols = other.Protocols
|
||||
}
|
||||
if len(other.SignatureVersions) > 0 {
|
||||
e.SignatureVersions = other.SignatureVersions
|
||||
}
|
||||
if len(other.CredentialScope.Region) > 0 {
|
||||
e.CredentialScope.Region = other.CredentialScope.Region
|
||||
}
|
||||
if len(other.CredentialScope.Service) > 0 {
|
||||
e.CredentialScope.Service = other.CredentialScope.Service
|
||||
}
|
||||
if len(other.SSLCommonName) > 0 {
|
||||
e.SSLCommonName = other.SSLCommonName
|
||||
}
|
||||
if other.HasDualStack != boxedBoolUnset {
|
||||
e.HasDualStack = other.HasDualStack
|
||||
}
|
||||
if len(other.DualStackHostname) > 0 {
|
||||
e.DualStackHostname = other.DualStackHostname
|
||||
}
|
||||
}
|
||||
|
||||
type credentialScope struct {
|
||||
Region string `json:"region"`
|
||||
Service string `json:"service"`
|
||||
}
|
||||
|
||||
type boxedBool int
|
||||
|
||||
func (b *boxedBool) UnmarshalJSON(buf []byte) error {
|
||||
v, err := strconv.ParseBool(string(buf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v {
|
||||
*b = boxedTrue
|
||||
} else {
|
||||
*b = boxedFalse
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
boxedBoolUnset boxedBool = iota
|
||||
boxedFalse
|
||||
boxedTrue
|
||||
)
|
||||
337
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go
generated
vendored
Normal file
337
vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model_codegen.go
generated
vendored
Normal file
@@ -0,0 +1,337 @@
|
||||
// +build codegen
|
||||
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// A CodeGenOptions are the options for code generating the endpoints into
|
||||
// Go code from the endpoints model definition.
|
||||
type CodeGenOptions struct {
|
||||
// Options for how the model will be decoded.
|
||||
DecodeModelOptions DecodeModelOptions
|
||||
}
|
||||
|
||||
// Set combines all of the option functions together
|
||||
func (d *CodeGenOptions) Set(optFns ...func(*CodeGenOptions)) {
|
||||
for _, fn := range optFns {
|
||||
fn(d)
|
||||
}
|
||||
}
|
||||
|
||||
// CodeGenModel given a endpoints model file will decode it and attempt to
|
||||
// generate Go code from the model definition. Error will be returned if
|
||||
// the code is unable to be generated, or decoded.
|
||||
func CodeGenModel(modelFile io.Reader, outFile io.Writer, optFns ...func(*CodeGenOptions)) error {
|
||||
var opts CodeGenOptions
|
||||
opts.Set(optFns...)
|
||||
|
||||
resolver, err := DecodeModel(modelFile, func(d *DecodeModelOptions) {
|
||||
*d = opts.DecodeModelOptions
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl := template.Must(template.New("tmpl").Funcs(funcMap).Parse(v3Tmpl))
|
||||
if err := tmpl.ExecuteTemplate(outFile, "defaults", resolver); err != nil {
|
||||
return fmt.Errorf("failed to execute template, %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func toSymbol(v string) string {
|
||||
out := []rune{}
|
||||
for _, c := range strings.Title(v) {
|
||||
if !(unicode.IsNumber(c) || unicode.IsLetter(c)) {
|
||||
continue
|
||||
}
|
||||
|
||||
out = append(out, c)
|
||||
}
|
||||
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func quoteString(v string) string {
|
||||
return fmt.Sprintf("%q", v)
|
||||
}
|
||||
|
||||
func regionConstName(p, r string) string {
|
||||
return toSymbol(p) + toSymbol(r)
|
||||
}
|
||||
|
||||
func partitionGetter(id string) string {
|
||||
return fmt.Sprintf("%sPartition", toSymbol(id))
|
||||
}
|
||||
|
||||
func partitionVarName(id string) string {
|
||||
return fmt.Sprintf("%sPartition", strings.ToLower(toSymbol(id)))
|
||||
}
|
||||
|
||||
func listPartitionNames(ps partitions) string {
|
||||
names := []string{}
|
||||
switch len(ps) {
|
||||
case 1:
|
||||
return ps[0].Name
|
||||
case 2:
|
||||
return fmt.Sprintf("%s and %s", ps[0].Name, ps[1].Name)
|
||||
default:
|
||||
for i, p := range ps {
|
||||
if i == len(ps)-1 {
|
||||
names = append(names, "and "+p.Name)
|
||||
} else {
|
||||
names = append(names, p.Name)
|
||||
}
|
||||
}
|
||||
return strings.Join(names, ", ")
|
||||
}
|
||||
}
|
||||
|
||||
func boxedBoolIfSet(msg string, v boxedBool) string {
|
||||
switch v {
|
||||
case boxedTrue:
|
||||
return fmt.Sprintf(msg, "boxedTrue")
|
||||
case boxedFalse:
|
||||
return fmt.Sprintf(msg, "boxedFalse")
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func stringIfSet(msg, v string) string {
|
||||
if len(v) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return fmt.Sprintf(msg, v)
|
||||
}
|
||||
|
||||
func stringSliceIfSet(msg string, vs []string) string {
|
||||
if len(vs) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
names := []string{}
|
||||
for _, v := range vs {
|
||||
names = append(names, `"`+v+`"`)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(msg, strings.Join(names, ","))
|
||||
}
|
||||
|
||||
func endpointIsSet(v endpoint) bool {
|
||||
return !reflect.DeepEqual(v, endpoint{})
|
||||
}
|
||||
|
||||
func serviceSet(ps partitions) map[string]struct{} {
|
||||
set := map[string]struct{}{}
|
||||
for _, p := range ps {
|
||||
for id := range p.Services {
|
||||
set[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"ToSymbol": toSymbol,
|
||||
"QuoteString": quoteString,
|
||||
"RegionConst": regionConstName,
|
||||
"PartitionGetter": partitionGetter,
|
||||
"PartitionVarName": partitionVarName,
|
||||
"ListPartitionNames": listPartitionNames,
|
||||
"BoxedBoolIfSet": boxedBoolIfSet,
|
||||
"StringIfSet": stringIfSet,
|
||||
"StringSliceIfSet": stringSliceIfSet,
|
||||
"EndpointIsSet": endpointIsSet,
|
||||
"ServicesSet": serviceSet,
|
||||
}
|
||||
|
||||
const v3Tmpl = `
|
||||
{{ define "defaults" -}}
|
||||
// Code generated by aws/endpoints/v3model_codegen.go. DO NOT EDIT.
|
||||
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
{{ template "partition consts" . }}
|
||||
|
||||
{{ range $_, $partition := . }}
|
||||
{{ template "partition region consts" $partition }}
|
||||
{{ end }}
|
||||
|
||||
{{ template "service consts" . }}
|
||||
|
||||
{{ template "endpoint resolvers" . }}
|
||||
{{- end }}
|
||||
|
||||
{{ define "partition consts" }}
|
||||
// Partition identifiers
|
||||
const (
|
||||
{{ range $_, $p := . -}}
|
||||
{{ ToSymbol $p.ID }}PartitionID = {{ QuoteString $p.ID }} // {{ $p.Name }} partition.
|
||||
{{ end -}}
|
||||
)
|
||||
{{- end }}
|
||||
|
||||
{{ define "partition region consts" }}
|
||||
// {{ .Name }} partition's regions.
|
||||
const (
|
||||
{{ range $id, $region := .Regions -}}
|
||||
{{ ToSymbol $id }}RegionID = {{ QuoteString $id }} // {{ $region.Description }}.
|
||||
{{ end -}}
|
||||
)
|
||||
{{- end }}
|
||||
|
||||
{{ define "service consts" }}
|
||||
// Service identifiers
|
||||
const (
|
||||
{{ $serviceSet := ServicesSet . -}}
|
||||
{{ range $id, $_ := $serviceSet -}}
|
||||
{{ ToSymbol $id }}ServiceID = {{ QuoteString $id }} // {{ ToSymbol $id }}.
|
||||
{{ end -}}
|
||||
)
|
||||
{{- end }}
|
||||
|
||||
{{ define "endpoint resolvers" }}
|
||||
// DefaultResolver returns an Endpoint resolver that will be able
|
||||
// to resolve endpoints for: {{ ListPartitionNames . }}.
|
||||
//
|
||||
// Use DefaultPartitions() to get the list of the default partitions.
|
||||
func DefaultResolver() Resolver {
|
||||
return defaultPartitions
|
||||
}
|
||||
|
||||
// DefaultPartitions returns a list of the partitions the SDK is bundled
|
||||
// with. The available partitions are: {{ ListPartitionNames . }}.
|
||||
//
|
||||
// partitions := endpoints.DefaultPartitions
|
||||
// for _, p := range partitions {
|
||||
// // ... inspect partitions
|
||||
// }
|
||||
func DefaultPartitions() []Partition {
|
||||
return defaultPartitions.Partitions()
|
||||
}
|
||||
|
||||
var defaultPartitions = partitions{
|
||||
{{ range $_, $partition := . -}}
|
||||
{{ PartitionVarName $partition.ID }},
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
{{ range $_, $partition := . -}}
|
||||
{{ $name := PartitionGetter $partition.ID -}}
|
||||
// {{ $name }} returns the Resolver for {{ $partition.Name }}.
|
||||
func {{ $name }}() Partition {
|
||||
return {{ PartitionVarName $partition.ID }}.Partition()
|
||||
}
|
||||
var {{ PartitionVarName $partition.ID }} = {{ template "gocode Partition" $partition }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "default partitions" }}
|
||||
func DefaultPartitions() []Partition {
|
||||
return []partition{
|
||||
{{ range $_, $partition := . -}}
|
||||
// {{ ToSymbol $partition.ID}}Partition(),
|
||||
{{ end }}
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
{{ define "gocode Partition" -}}
|
||||
partition{
|
||||
{{ StringIfSet "ID: %q,\n" .ID -}}
|
||||
{{ StringIfSet "Name: %q,\n" .Name -}}
|
||||
{{ StringIfSet "DNSSuffix: %q,\n" .DNSSuffix -}}
|
||||
RegionRegex: {{ template "gocode RegionRegex" .RegionRegex }},
|
||||
{{ if EndpointIsSet .Defaults -}}
|
||||
Defaults: {{ template "gocode Endpoint" .Defaults }},
|
||||
{{- end }}
|
||||
Regions: {{ template "gocode Regions" .Regions }},
|
||||
Services: {{ template "gocode Services" .Services }},
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode RegionRegex" -}}
|
||||
regionRegex{
|
||||
Regexp: func() *regexp.Regexp{
|
||||
reg, _ := regexp.Compile({{ QuoteString .Regexp.String }})
|
||||
return reg
|
||||
}(),
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Regions" -}}
|
||||
regions{
|
||||
{{ range $id, $region := . -}}
|
||||
"{{ $id }}": {{ template "gocode Region" $region }},
|
||||
{{ end -}}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Region" -}}
|
||||
region{
|
||||
{{ StringIfSet "Description: %q,\n" .Description -}}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Services" -}}
|
||||
services{
|
||||
{{ range $id, $service := . -}}
|
||||
"{{ $id }}": {{ template "gocode Service" $service }},
|
||||
{{ end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Service" -}}
|
||||
service{
|
||||
{{ StringIfSet "PartitionEndpoint: %q,\n" .PartitionEndpoint -}}
|
||||
{{ BoxedBoolIfSet "IsRegionalized: %s,\n" .IsRegionalized -}}
|
||||
{{ if EndpointIsSet .Defaults -}}
|
||||
Defaults: {{ template "gocode Endpoint" .Defaults -}},
|
||||
{{- end }}
|
||||
{{ if .Endpoints -}}
|
||||
Endpoints: {{ template "gocode Endpoints" .Endpoints }},
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Endpoints" -}}
|
||||
endpoints{
|
||||
{{ range $id, $endpoint := . -}}
|
||||
"{{ $id }}": {{ template "gocode Endpoint" $endpoint }},
|
||||
{{ end }}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{ define "gocode Endpoint" -}}
|
||||
endpoint{
|
||||
{{ StringIfSet "Hostname: %q,\n" .Hostname -}}
|
||||
{{ StringIfSet "SSLCommonName: %q,\n" .SSLCommonName -}}
|
||||
{{ StringSliceIfSet "Protocols: []string{%s},\n" .Protocols -}}
|
||||
{{ StringSliceIfSet "SignatureVersions: []string{%s},\n" .SignatureVersions -}}
|
||||
{{ if or .CredentialScope.Region .CredentialScope.Service -}}
|
||||
CredentialScope: credentialScope{
|
||||
{{ StringIfSet "Region: %q,\n" .CredentialScope.Region -}}
|
||||
{{ StringIfSet "Service: %q,\n" .CredentialScope.Service -}}
|
||||
},
|
||||
{{- end }}
|
||||
{{ BoxedBoolIfSet "HasDualStack: %s,\n" .HasDualStack -}}
|
||||
{{ StringIfSet "DualStackHostname: %q,\n" .DualStackHostname -}}
|
||||
|
||||
}
|
||||
{{- end }}
|
||||
`
|
||||
17
vendor/github.com/aws/aws-sdk-go/aws/errors.go
generated
vendored
Normal file
17
vendor/github.com/aws/aws-sdk-go/aws/errors.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package aws
|
||||
|
||||
import "github.com/aws/aws-sdk-go/aws/awserr"
|
||||
|
||||
var (
|
||||
// ErrMissingRegion is an error that is returned if region configuration is
|
||||
// not found.
|
||||
//
|
||||
// @readonly
|
||||
ErrMissingRegion = awserr.New("MissingRegion", "could not find region configuration", nil)
|
||||
|
||||
// ErrMissingEndpoint is an error that is returned if an endpoint cannot be
|
||||
// resolved for a service.
|
||||
//
|
||||
// @readonly
|
||||
ErrMissingEndpoint = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user