Manage vendor (#557)
* feat: add dep configuration files. * chore: add vendor folder. * refactor: update Dockerfile. * review: remove git from Dockerfile. * review: remove RUN apk. * review: dep status. * feat: added .dockerignore
This commit is contained in:
parent
1b12c25e43
commit
6004e599ed
1217 changed files with 363499 additions and 11 deletions
9
.dockerignore
Normal file
9
.dockerignore
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.git
|
||||||
|
lego.exe
|
||||||
|
lego
|
||||||
|
.lego
|
||||||
|
.gitcookies
|
||||||
|
.idea
|
||||||
|
.vscode/
|
||||||
|
dist/
|
||||||
|
builds/
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,4 +6,3 @@ lego
|
||||||
.vscode/
|
.vscode/
|
||||||
dist/
|
dist/
|
||||||
builds/
|
builds/
|
||||||
vendor/
|
|
||||||
|
|
|
@ -12,12 +12,18 @@ env:
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && openssl aes-256-cbc -K $encrypted_26c593b079d9_key -iv $encrypted_26c593b079d9_iv -in .gitcookies.enc -out .gitcookies -d || true'
|
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && openssl aes-256-cbc -K $encrypted_26c593b079d9_key -iv $encrypted_26c593b079d9_iv -in .gitcookies.enc -out .gitcookies -d || true'
|
||||||
|
|
||||||
|
# Download and install dep
|
||||||
|
- curl -sI https://github.com/golang/dep/releases/latest | grep -Fi Location | tr -d '\r' | sed "s/tag/download/g" | awk -F " " '{ print $2 "/dep-linux-amd64"}' | wget --output-document=$GOPATH/bin/dep -i -
|
||||||
|
- chmod +x $GOPATH/bin/dep
|
||||||
|
|
||||||
# Install linters and misspell
|
# Install linters and misspell
|
||||||
- go get -u github.com/alecthomas/gometalinter
|
- go get -u github.com/alecthomas/gometalinter
|
||||||
- gometalinter --install
|
- gometalinter --install
|
||||||
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- go get -t ./...
|
- dep status -v
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
- provider: script
|
- provider: script
|
||||||
|
|
14
Dockerfile
14
Dockerfile
|
@ -1,16 +1,12 @@
|
||||||
FROM golang:alpine3.7 as builder
|
FROM golang:alpine3.7 as builder
|
||||||
|
|
||||||
ARG LEGO_VERSION=master
|
ARG LEGO_VERSION=dev
|
||||||
|
|
||||||
RUN apk update && \
|
WORKDIR /go/src/github.com/xenolf/lego
|
||||||
apk add --no-cache --virtual git && \
|
COPY . .
|
||||||
go get -u github.com/xenolf/lego && \
|
RUN go build -ldflags="-s -X main.version=${LEGO_VERSION}"
|
||||||
cd ${GOPATH}/src/github.com/xenolf/lego && \
|
|
||||||
git checkout ${LEGO_VERSION} && \
|
|
||||||
go build -o /usr/bin/lego .
|
|
||||||
|
|
||||||
FROM alpine:3.7
|
FROM alpine:3.7
|
||||||
RUN apk update && apk add --no-cache --virtual ca-certificates
|
RUN apk update && apk add --no-cache --virtual ca-certificates
|
||||||
COPY --from=builder /usr/bin/lego /usr/bin/lego
|
COPY --from=builder /go/src/github.com/xenolf/lego/lego /usr/bin/lego
|
||||||
|
|
||||||
ENTRYPOINT [ "/usr/bin/lego" ]
|
ENTRYPOINT [ "/usr/bin/lego" ]
|
||||||
|
|
368
Gopkg.lock
generated
Normal file
368
Gopkg.lock
generated
Normal file
|
@ -0,0 +1,368 @@
|
||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "cloud.google.com/go"
|
||||||
|
packages = ["compute/metadata"]
|
||||||
|
revision = "0fd7230b2a7505833d5f69b75cbd6c9582401479"
|
||||||
|
version = "v0.23.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/Azure/azure-sdk-for-go"
|
||||||
|
packages = [
|
||||||
|
"services/dns/mgmt/2017-09-01/dns",
|
||||||
|
"version"
|
||||||
|
]
|
||||||
|
revision = "4650843026a7fdec254a8d9cf893693a254edd0b"
|
||||||
|
version = "v16.2.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/Azure/go-autorest"
|
||||||
|
packages = [
|
||||||
|
"autorest",
|
||||||
|
"autorest/adal",
|
||||||
|
"autorest/azure",
|
||||||
|
"autorest/date",
|
||||||
|
"autorest/to"
|
||||||
|
]
|
||||||
|
revision = "aa2a4534ab680e938d933870f58f23f77e0e208e"
|
||||||
|
version = "v10.9.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/JamesClonk/vultr"
|
||||||
|
packages = ["lib"]
|
||||||
|
revision = "fa1c0367800db75e4d10d0ec90c49a8731670224"
|
||||||
|
version = "1.15.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/akamai/AkamaiOPEN-edgegrid-golang"
|
||||||
|
packages = [
|
||||||
|
"client-v1",
|
||||||
|
"configdns-v1",
|
||||||
|
"edgegrid",
|
||||||
|
"jsonhooks-v1"
|
||||||
|
]
|
||||||
|
revision = "196fbdab2db66d0e231cc363efb63454f55fed1c"
|
||||||
|
version = "v0.6.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
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/defaults",
|
||||||
|
"aws/ec2metadata",
|
||||||
|
"aws/endpoints",
|
||||||
|
"aws/request",
|
||||||
|
"aws/session",
|
||||||
|
"aws/signer/v4",
|
||||||
|
"internal/sdkio",
|
||||||
|
"internal/sdkrand",
|
||||||
|
"internal/shareddefaults",
|
||||||
|
"private/protocol",
|
||||||
|
"private/protocol/json/jsonutil",
|
||||||
|
"private/protocol/jsonrpc",
|
||||||
|
"private/protocol/query",
|
||||||
|
"private/protocol/query/queryutil",
|
||||||
|
"private/protocol/rest",
|
||||||
|
"private/protocol/restxml",
|
||||||
|
"private/protocol/xml/xmlutil",
|
||||||
|
"service/lightsail",
|
||||||
|
"service/route53",
|
||||||
|
"service/sts"
|
||||||
|
]
|
||||||
|
revision = "398d14696895d68a3409bb3ccb1cfe8abc2d4376"
|
||||||
|
version = "v1.13.57"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/davecgh/go-spew"
|
||||||
|
packages = ["spew"]
|
||||||
|
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||||
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/decker502/dnspod-go"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "83a3ba562b048c9fc88229408e593494b7774684"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/dgrijalva/jwt-go"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||||
|
version = "v3.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/dnsimple/dnsimple-go"
|
||||||
|
packages = ["dnsimple"]
|
||||||
|
revision = "bbe1a2c87affea187478e24d3aea3cac25f870b3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/edeckers/auroradnsclient"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"records",
|
||||||
|
"requests",
|
||||||
|
"requests/errors",
|
||||||
|
"tokens",
|
||||||
|
"zones"
|
||||||
|
]
|
||||||
|
revision = "1563e622aaca0a8bb895a448f31d4a430ab97586"
|
||||||
|
version = "v1.0.3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/exoscale/egoscale"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "caa6b3727b959d704dda224fb7a63fae3c14d8fb"
|
||||||
|
version = "v0.9.26"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/go-ini/ini"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "06f5f3d67269ccec1fe5fe4134ba6e982984f7f5"
|
||||||
|
version = "v1.37.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/golang/protobuf"
|
||||||
|
packages = ["proto"]
|
||||||
|
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
||||||
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/google/go-querystring"
|
||||||
|
packages = ["query"]
|
||||||
|
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/google/uuid"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "064e2069ce9c359c118179501254f67d7d37ba24"
|
||||||
|
version = "0.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/jinzhu/copier"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "7e38e58719c33e0d44d585c4ab477a30f8cb82dd"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/jmespath/go-jmespath"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "0b12d6b5"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/json-iterator/go"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "ca39e5af3ece67bbcda3d0f4f56a8e24d9f2dad4"
|
||||||
|
version = "1.1.3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/juju/ratelimit"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
|
||||||
|
version = "1.0.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/miekg/dns"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "e57bf427e68187a27e22adceac868350d7a7079b"
|
||||||
|
version = "v1.0.7"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/mitchellh/go-homedir"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/modern-go/concurrent"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
||||||
|
version = "1.0.3"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/modern-go/reflect2"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "1df9eeb2bb81f327b96228865c5687bc2194af3f"
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/namedotcom/go"
|
||||||
|
packages = ["namecom"]
|
||||||
|
revision = "08470befbe04613bd4b44cb6978b05d50294c4d4"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/ovh/go-ovh"
|
||||||
|
packages = ["ovh"]
|
||||||
|
revision = "91b7eb631d2eced3e706932a0b36ee8b5ee22e92"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/pkg/errors"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||||
|
version = "v0.8.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/pmezard/go-difflib"
|
||||||
|
packages = ["difflib"]
|
||||||
|
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/rainycape/memcache"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "1031fa0ce2f20c1c0e1e1b51951d8ea02c84fa05"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/sirupsen/logrus"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
||||||
|
version = "v1.0.5"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/stretchr/testify"
|
||||||
|
packages = [
|
||||||
|
"assert",
|
||||||
|
"require",
|
||||||
|
"suite"
|
||||||
|
]
|
||||||
|
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
||||||
|
version = "v1.2.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/timewasted/linode"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"dns"
|
||||||
|
]
|
||||||
|
revision = "37e84520dcf74488f67654f9c775b9752c232dc1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/urfave/cli"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
|
||||||
|
version = "v1.20.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/crypto"
|
||||||
|
packages = [
|
||||||
|
"ed25519",
|
||||||
|
"ed25519/internal/edwards25519",
|
||||||
|
"ocsp",
|
||||||
|
"ssh/terminal"
|
||||||
|
]
|
||||||
|
revision = "ab813273cd59e1333f7ae7bff5d027d4aadf528c"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
packages = [
|
||||||
|
"bpf",
|
||||||
|
"context",
|
||||||
|
"context/ctxhttp",
|
||||||
|
"internal/iana",
|
||||||
|
"internal/socket",
|
||||||
|
"ipv4",
|
||||||
|
"ipv6"
|
||||||
|
]
|
||||||
|
revision = "75944861c7512f64725d687546cfbc757626151f"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/oauth2"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"google",
|
||||||
|
"internal",
|
||||||
|
"jws",
|
||||||
|
"jwt"
|
||||||
|
]
|
||||||
|
revision = "ec22f46f877b4505e0117eeaab541714644fdd28"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/sys"
|
||||||
|
packages = [
|
||||||
|
"unix",
|
||||||
|
"windows"
|
||||||
|
]
|
||||||
|
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "google.golang.org/api"
|
||||||
|
packages = [
|
||||||
|
"dns/v1",
|
||||||
|
"gensupport",
|
||||||
|
"googleapi",
|
||||||
|
"googleapi/internal/uritemplates"
|
||||||
|
]
|
||||||
|
revision = "de943baf05a022a8f921b544b7827bacaba1aed5"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "google.golang.org/appengine"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"internal",
|
||||||
|
"internal/app_identity",
|
||||||
|
"internal/base",
|
||||||
|
"internal/datastore",
|
||||||
|
"internal/log",
|
||||||
|
"internal/modules",
|
||||||
|
"internal/remote_api",
|
||||||
|
"internal/urlfetch",
|
||||||
|
"urlfetch"
|
||||||
|
]
|
||||||
|
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "gopkg.in/ini.v1"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "06f5f3d67269ccec1fe5fe4134ba6e982984f7f5"
|
||||||
|
version = "v1.37.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "v2"
|
||||||
|
name = "gopkg.in/ns1/ns1-go.v2"
|
||||||
|
packages = [
|
||||||
|
"rest",
|
||||||
|
"rest/model/account",
|
||||||
|
"rest/model/data",
|
||||||
|
"rest/model/dns",
|
||||||
|
"rest/model/filter",
|
||||||
|
"rest/model/monitor"
|
||||||
|
]
|
||||||
|
revision = "a5bcac82d3f637d3928d30476610891935b2d691"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "gopkg.in/square/go-jose.v2"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"cipher",
|
||||||
|
"json"
|
||||||
|
]
|
||||||
|
revision = "76dd09796242edb5b897103a75df2645c028c960"
|
||||||
|
version = "v2.1.6"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
inputs-digest = "6b701827736620696c106773b62665f722b691a3025b851fe1a5d3c321d77d21"
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
74
Gopkg.toml
Normal file
74
Gopkg.toml
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
# Gopkg.toml example
|
||||||
|
#
|
||||||
|
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||||
|
# for detailed Gopkg.toml documentation.
|
||||||
|
#
|
||||||
|
# required = ["github.com/user/thing/cmd/thing"]
|
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project"
|
||||||
|
# version = "1.0.0"
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project2"
|
||||||
|
# branch = "dev"
|
||||||
|
# source = "github.com/myfork/project2"
|
||||||
|
#
|
||||||
|
# [[override]]
|
||||||
|
# name = "github.com/x/y"
|
||||||
|
# version = "2.4.0"
|
||||||
|
#
|
||||||
|
# [prune]
|
||||||
|
# non-go = false
|
||||||
|
# go-tests = true
|
||||||
|
# unused-packages = true
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/decker502/dnspod-go"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/dnsimple/dnsimple-go"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/namedotcom/go"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/ovh/go-ovh"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/rainycape/memcache"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/timewasted/linode"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/crypto"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/oauth2"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "google.golang.org/api"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "v2"
|
||||||
|
name = "gopkg.in/ns1/ns1-go.v2"
|
||||||
|
|
||||||
|
[prune]
|
||||||
|
non-go = true
|
||||||
|
go-tests = true
|
||||||
|
unused-packages = true
|
4
Makefile
4
Makefile
|
@ -10,6 +10,10 @@ clean:
|
||||||
build: clean
|
build: clean
|
||||||
go build
|
go build
|
||||||
|
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
dep ensure -v
|
||||||
|
|
||||||
test: clean
|
test: clean
|
||||||
go test -v -cover ./...
|
go test -v -cover ./...
|
||||||
|
|
||||||
|
|
15
vendor/cloud.google.com/go/AUTHORS
generated
vendored
Normal file
15
vendor/cloud.google.com/go/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# This is the official list of cloud authors for copyright purposes.
|
||||||
|
# This file is distinct from the CONTRIBUTORS files.
|
||||||
|
# See the latter for an explanation.
|
||||||
|
|
||||||
|
# Names should be added to this file as:
|
||||||
|
# Name or Organization <email address>
|
||||||
|
# The email address is not required for organizations.
|
||||||
|
|
||||||
|
Filippo Valsorda <hi@filippo.io>
|
||||||
|
Google Inc.
|
||||||
|
Ingo Oeser <nightlyone@googlemail.com>
|
||||||
|
Palm Stone Games, Inc.
|
||||||
|
Paweł Knap <pawelknap88@gmail.com>
|
||||||
|
Péter Szilágyi <peterke@gmail.com>
|
||||||
|
Tyler Treat <ttreat31@gmail.com>
|
40
vendor/cloud.google.com/go/CONTRIBUTORS
generated
vendored
Normal file
40
vendor/cloud.google.com/go/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# People who have agreed to one of the CLAs and can contribute patches.
|
||||||
|
# The AUTHORS file lists the copyright holders; this file
|
||||||
|
# lists people. For example, Google employees are listed here
|
||||||
|
# but not in AUTHORS, because Google holds the copyright.
|
||||||
|
#
|
||||||
|
# https://developers.google.com/open-source/cla/individual
|
||||||
|
# https://developers.google.com/open-source/cla/corporate
|
||||||
|
#
|
||||||
|
# Names should be added to this file as:
|
||||||
|
# Name <email address>
|
||||||
|
|
||||||
|
# Keep the list alphabetically sorted.
|
||||||
|
|
||||||
|
Alexis Hunt <lexer@google.com>
|
||||||
|
Andreas Litt <andreas.litt@gmail.com>
|
||||||
|
Andrew Gerrand <adg@golang.org>
|
||||||
|
Brad Fitzpatrick <bradfitz@golang.org>
|
||||||
|
Burcu Dogan <jbd@google.com>
|
||||||
|
Dave Day <djd@golang.org>
|
||||||
|
David Sansome <me@davidsansome.com>
|
||||||
|
David Symonds <dsymonds@golang.org>
|
||||||
|
Filippo Valsorda <hi@filippo.io>
|
||||||
|
Glenn Lewis <gmlewis@google.com>
|
||||||
|
Ingo Oeser <nightlyone@googlemail.com>
|
||||||
|
James Hall <james.hall@shopify.com>
|
||||||
|
Johan Euphrosine <proppy@google.com>
|
||||||
|
Jonathan Amsterdam <jba@google.com>
|
||||||
|
Kunpei Sakai <namusyaka@gmail.com>
|
||||||
|
Luna Duclos <luna.duclos@palmstonegames.com>
|
||||||
|
Magnus Hiie <magnus.hiie@gmail.com>
|
||||||
|
Mario Castro <mariocaster@gmail.com>
|
||||||
|
Michael McGreevy <mcgreevy@golang.org>
|
||||||
|
Omar Jarjur <ojarjur@google.com>
|
||||||
|
Paweł Knap <pawelknap88@gmail.com>
|
||||||
|
Péter Szilágyi <peterke@gmail.com>
|
||||||
|
Sarah Adams <shadams@google.com>
|
||||||
|
Thanatat Tamtan <acoshift@gmail.com>
|
||||||
|
Toby Burress <kurin@google.com>
|
||||||
|
Tuo Shan <shantuo@google.com>
|
||||||
|
Tyler Treat <ttreat31@gmail.com>
|
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
Normal file
202
vendor/cloud.google.com/go/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
437
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
437
vendor/cloud.google.com/go/compute/metadata/metadata.go
generated
vendored
Normal file
|
@ -0,0 +1,437 @@
|
||||||
|
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package metadata provides access to Google Compute Engine (GCE)
|
||||||
|
// metadata and API service accounts.
|
||||||
|
//
|
||||||
|
// This package is a wrapper around the GCE metadata service,
|
||||||
|
// as documented at https://developers.google.com/compute/docs/metadata.
|
||||||
|
package metadata // import "cloud.google.com/go/compute/metadata"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/net/context/ctxhttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// metadataIP is the documented metadata server IP address.
|
||||||
|
metadataIP = "169.254.169.254"
|
||||||
|
|
||||||
|
// metadataHostEnv is the environment variable specifying the
|
||||||
|
// GCE metadata hostname. If empty, the default value of
|
||||||
|
// metadataIP ("169.254.169.254") is used instead.
|
||||||
|
// This is variable name is not defined by any spec, as far as
|
||||||
|
// I know; it was made up for the Go package.
|
||||||
|
metadataHostEnv = "GCE_METADATA_HOST"
|
||||||
|
|
||||||
|
userAgent = "gcloud-golang/0.1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cachedValue struct {
|
||||||
|
k string
|
||||||
|
trim bool
|
||||||
|
mu sync.Mutex
|
||||||
|
v string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
projID = &cachedValue{k: "project/project-id", trim: true}
|
||||||
|
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
|
||||||
|
instID = &cachedValue{k: "instance/id", trim: true}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
metaClient = &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: (&net.Dialer{
|
||||||
|
Timeout: 2 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
}).Dial,
|
||||||
|
ResponseHeaderTimeout: 2 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
subscribeClient = &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Dial: (&net.Dialer{
|
||||||
|
Timeout: 2 * time.Second,
|
||||||
|
KeepAlive: 30 * time.Second,
|
||||||
|
}).Dial,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NotDefinedError is returned when requested metadata is not defined.
|
||||||
|
//
|
||||||
|
// The underlying string is the suffix after "/computeMetadata/v1/".
|
||||||
|
//
|
||||||
|
// This error is not returned if the value is defined to be the empty
|
||||||
|
// string.
|
||||||
|
type NotDefinedError string
|
||||||
|
|
||||||
|
func (suffix NotDefinedError) Error() string {
|
||||||
|
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a value from the metadata service.
|
||||||
|
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||||
|
//
|
||||||
|
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
||||||
|
// 169.254.169.254 will be used instead.
|
||||||
|
//
|
||||||
|
// If the requested metadata is not defined, the returned error will
|
||||||
|
// be of type NotDefinedError.
|
||||||
|
func Get(suffix string) (string, error) {
|
||||||
|
val, _, err := getETag(metaClient, suffix)
|
||||||
|
return val, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// getETag returns a value from the metadata service as well as the associated
|
||||||
|
// ETag using the provided client. This func is otherwise equivalent to Get.
|
||||||
|
func getETag(client *http.Client, suffix string) (value, etag string, err error) {
|
||||||
|
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
||||||
|
// a container, which is an important use-case for local testing of cloud
|
||||||
|
// deployments. To enable spoofing of the metadata service, the environment
|
||||||
|
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
||||||
|
// requests shall go.
|
||||||
|
host := os.Getenv(metadataHostEnv)
|
||||||
|
if host == "" {
|
||||||
|
// Using 169.254.169.254 instead of "metadata" here because Go
|
||||||
|
// binaries built with the "netgo" tag and without cgo won't
|
||||||
|
// know the search suffix for "metadata" is
|
||||||
|
// ".google.internal", and this IP address is documented as
|
||||||
|
// being stable anyway.
|
||||||
|
host = metadataIP
|
||||||
|
}
|
||||||
|
url := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||||
|
req, _ := http.NewRequest("GET", url, nil)
|
||||||
|
req.Header.Set("Metadata-Flavor", "Google")
|
||||||
|
req.Header.Set("User-Agent", userAgent)
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
if res.StatusCode == http.StatusNotFound {
|
||||||
|
return "", "", NotDefinedError(suffix)
|
||||||
|
}
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
|
||||||
|
}
|
||||||
|
all, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return string(all), res.Header.Get("Etag"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTrimmed(suffix string) (s string, err error) {
|
||||||
|
s, err = Get(suffix)
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedValue) get() (v string, err error) {
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.v != "" {
|
||||||
|
return c.v, nil
|
||||||
|
}
|
||||||
|
if c.trim {
|
||||||
|
v, err = getTrimmed(c.k)
|
||||||
|
} else {
|
||||||
|
v, err = Get(c.k)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
c.v = v
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
onGCEOnce sync.Once
|
||||||
|
onGCE bool
|
||||||
|
)
|
||||||
|
|
||||||
|
// OnGCE reports whether this process is running on Google Compute Engine.
|
||||||
|
func OnGCE() bool {
|
||||||
|
onGCEOnce.Do(initOnGCE)
|
||||||
|
return onGCE
|
||||||
|
}
|
||||||
|
|
||||||
|
func initOnGCE() {
|
||||||
|
onGCE = testOnGCE()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOnGCE() bool {
|
||||||
|
// The user explicitly said they're on GCE, so trust them.
|
||||||
|
if os.Getenv(metadataHostEnv) != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
resc := make(chan bool, 2)
|
||||||
|
|
||||||
|
// Try two strategies in parallel.
|
||||||
|
// See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194
|
||||||
|
go func() {
|
||||||
|
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
||||||
|
req.Header.Set("User-Agent", userAgent)
|
||||||
|
res, err := ctxhttp.Do(ctx, metaClient, req)
|
||||||
|
if err != nil {
|
||||||
|
resc <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
addrs, err := net.LookupHost("metadata.google.internal")
|
||||||
|
if err != nil || len(addrs) == 0 {
|
||||||
|
resc <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resc <- strsContains(addrs, metadataIP)
|
||||||
|
}()
|
||||||
|
|
||||||
|
tryHarder := systemInfoSuggestsGCE()
|
||||||
|
if tryHarder {
|
||||||
|
res := <-resc
|
||||||
|
if res {
|
||||||
|
// The first strategy succeeded, so let's use it.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Wait for either the DNS or metadata server probe to
|
||||||
|
// contradict the other one and say we are running on
|
||||||
|
// GCE. Give it a lot of time to do so, since the system
|
||||||
|
// info already suggests we're running on a GCE BIOS.
|
||||||
|
timer := time.NewTimer(5 * time.Second)
|
||||||
|
defer timer.Stop()
|
||||||
|
select {
|
||||||
|
case res = <-resc:
|
||||||
|
return res
|
||||||
|
case <-timer.C:
|
||||||
|
// Too slow. Who knows what this system is.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's no hint from the system info that we're running on
|
||||||
|
// GCE, so use the first probe's result as truth, whether it's
|
||||||
|
// true or false. The goal here is to optimize for speed for
|
||||||
|
// users who are NOT running on GCE. We can't assume that
|
||||||
|
// either a DNS lookup or an HTTP request to a blackholed IP
|
||||||
|
// address is fast. Worst case this should return when the
|
||||||
|
// metaClient's Transport.ResponseHeaderTimeout or
|
||||||
|
// Transport.Dial.Timeout fires (in two seconds).
|
||||||
|
return <-resc
|
||||||
|
}
|
||||||
|
|
||||||
|
// systemInfoSuggestsGCE reports whether the local system (without
|
||||||
|
// doing network requests) suggests that we're running on GCE. If this
|
||||||
|
// returns true, testOnGCE tries a bit harder to reach its metadata
|
||||||
|
// server.
|
||||||
|
func systemInfoSuggestsGCE() bool {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
// We don't have any non-Linux clues available, at least yet.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
|
||||||
|
name := strings.TrimSpace(string(slurp))
|
||||||
|
return name == "Google" || name == "Google Compute Engine"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe subscribes to a value from the metadata service.
|
||||||
|
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||||
|
// The suffix may contain query parameters.
|
||||||
|
//
|
||||||
|
// Subscribe calls fn with the latest metadata value indicated by the provided
|
||||||
|
// suffix. If the metadata value is deleted, fn is called with the empty string
|
||||||
|
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
|
||||||
|
// is deleted. Subscribe returns the error value returned from the last call to
|
||||||
|
// fn, which may be nil when ok == false.
|
||||||
|
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||||
|
const failedSubscribeSleep = time.Second * 5
|
||||||
|
|
||||||
|
// First check to see if the metadata value exists at all.
|
||||||
|
val, lastETag, err := getETag(subscribeClient, suffix)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fn(val, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := true
|
||||||
|
if strings.ContainsRune(suffix, '?') {
|
||||||
|
suffix += "&wait_for_change=true&last_etag="
|
||||||
|
} else {
|
||||||
|
suffix += "?wait_for_change=true&last_etag="
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
val, etag, err := getETag(subscribeClient, suffix+url.QueryEscape(lastETag))
|
||||||
|
if err != nil {
|
||||||
|
if _, deleted := err.(NotDefinedError); !deleted {
|
||||||
|
time.Sleep(failedSubscribeSleep)
|
||||||
|
continue // Retry on other errors.
|
||||||
|
}
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
lastETag = etag
|
||||||
|
|
||||||
|
if err := fn(val, ok); err != nil || !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectID returns the current instance's project ID string.
|
||||||
|
func ProjectID() (string, error) { return projID.get() }
|
||||||
|
|
||||||
|
// NumericProjectID returns the current instance's numeric project ID.
|
||||||
|
func NumericProjectID() (string, error) { return projNum.get() }
|
||||||
|
|
||||||
|
// InternalIP returns the instance's primary internal IP address.
|
||||||
|
func InternalIP() (string, error) {
|
||||||
|
return getTrimmed("instance/network-interfaces/0/ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalIP returns the instance's primary external (public) IP address.
|
||||||
|
func ExternalIP() (string, error) {
|
||||||
|
return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hostname returns the instance's hostname. This will be of the form
|
||||||
|
// "<instanceID>.c.<projID>.internal".
|
||||||
|
func Hostname() (string, error) {
|
||||||
|
return getTrimmed("instance/hostname")
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceTags returns the list of user-defined instance tags,
|
||||||
|
// assigned when initially creating a GCE instance.
|
||||||
|
func InstanceTags() ([]string, error) {
|
||||||
|
var s []string
|
||||||
|
j, err := Get("instance/tags")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceID returns the current VM's numeric instance ID.
|
||||||
|
func InstanceID() (string, error) {
|
||||||
|
return instID.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceName returns the current VM's instance ID string.
|
||||||
|
func InstanceName() (string, error) {
|
||||||
|
host, err := Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return strings.Split(host, ".")[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||||
|
func Zone() (string, error) {
|
||||||
|
zone, err := getTrimmed("instance/zone")
|
||||||
|
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return zone[strings.LastIndex(zone, "/")+1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributes returns the list of user-defined attributes,
|
||||||
|
// assigned when initially creating a GCE VM instance. The value of an
|
||||||
|
// attribute can be obtained with InstanceAttributeValue.
|
||||||
|
func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }
|
||||||
|
|
||||||
|
// ProjectAttributes returns the list of user-defined attributes
|
||||||
|
// applying to the project as a whole, not just this VM. The value of
|
||||||
|
// an attribute can be obtained with ProjectAttributeValue.
|
||||||
|
func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }
|
||||||
|
|
||||||
|
func lines(suffix string) ([]string, error) {
|
||||||
|
j, err := Get(suffix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s := strings.Split(strings.TrimSpace(j), "\n")
|
||||||
|
for i := range s {
|
||||||
|
s[i] = strings.TrimSpace(s[i])
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributeValue returns the value of the provided VM
|
||||||
|
// instance attribute.
|
||||||
|
//
|
||||||
|
// If the requested attribute is not defined, the returned error will
|
||||||
|
// be of type NotDefinedError.
|
||||||
|
//
|
||||||
|
// InstanceAttributeValue may return ("", nil) if the attribute was
|
||||||
|
// defined to be the empty string.
|
||||||
|
func InstanceAttributeValue(attr string) (string, error) {
|
||||||
|
return Get("instance/attributes/" + attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributeValue returns the value of the provided
|
||||||
|
// project attribute.
|
||||||
|
//
|
||||||
|
// If the requested attribute is not defined, the returned error will
|
||||||
|
// be of type NotDefinedError.
|
||||||
|
//
|
||||||
|
// ProjectAttributeValue may return ("", nil) if the attribute was
|
||||||
|
// defined to be the empty string.
|
||||||
|
func ProjectAttributeValue(attr string) (string, error) {
|
||||||
|
return Get("project/attributes/" + attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scopes returns the service account scopes for the given account.
|
||||||
|
// The account may be empty or the string "default" to use the instance's
|
||||||
|
// main account.
|
||||||
|
func Scopes(serviceAccount string) ([]string, error) {
|
||||||
|
if serviceAccount == "" {
|
||||||
|
serviceAccount = "default"
|
||||||
|
}
|
||||||
|
return lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
||||||
|
}
|
||||||
|
|
||||||
|
func strsContains(ss []string, s string) bool {
|
||||||
|
for _, v := range ss {
|
||||||
|
if v == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
202
vendor/github.com/Azure/azure-sdk-for-go/LICENSE
generated
vendored
Normal file
202
vendor/github.com/Azure/azure-sdk-for-go/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2016 Microsoft Corporation
|
||||||
|
|
||||||
|
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.
|
5
vendor/github.com/Azure/azure-sdk-for-go/NOTICE
generated
vendored
Normal file
5
vendor/github.com/Azure/azure-sdk-for-go/NOTICE
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Microsoft Azure-SDK-for-Go
|
||||||
|
Copyright 2014-2017 Microsoft
|
||||||
|
|
||||||
|
This product includes software developed at
|
||||||
|
the Microsoft Corporation (https://www.microsoft.com).
|
51
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/client.go
generated
vendored
Normal file
51
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/client.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// Package dns implements the Azure ARM Dns service API version 2017-09-01.
|
||||||
|
//
|
||||||
|
// The DNS Management Client.
|
||||||
|
package dns
|
||||||
|
|
||||||
|
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||||
|
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultBaseURI is the default URI used for the service Dns
|
||||||
|
DefaultBaseURI = "https://management.azure.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BaseClient is the base client for Dns.
|
||||||
|
type BaseClient struct {
|
||||||
|
autorest.Client
|
||||||
|
BaseURI string
|
||||||
|
SubscriptionID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates an instance of the BaseClient client.
|
||||||
|
func New(subscriptionID string) BaseClient {
|
||||||
|
return NewWithBaseURI(DefaultBaseURI, subscriptionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithBaseURI creates an instance of the BaseClient client.
|
||||||
|
func NewWithBaseURI(baseURI string, subscriptionID string) BaseClient {
|
||||||
|
return BaseClient{
|
||||||
|
Client: autorest.NewClientWithUserAgent(UserAgent()),
|
||||||
|
BaseURI: baseURI,
|
||||||
|
SubscriptionID: subscriptionID,
|
||||||
|
}
|
||||||
|
}
|
763
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/models.go
generated
vendored
Normal file
763
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/models.go
generated
vendored
Normal file
|
@ -0,0 +1,763 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||||
|
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
"github.com/Azure/go-autorest/autorest/azure"
|
||||||
|
"github.com/Azure/go-autorest/autorest/to"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RecordType enumerates the values for record type.
|
||||||
|
type RecordType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// A ...
|
||||||
|
A RecordType = "A"
|
||||||
|
// AAAA ...
|
||||||
|
AAAA RecordType = "AAAA"
|
||||||
|
// CAA ...
|
||||||
|
CAA RecordType = "CAA"
|
||||||
|
// CNAME ...
|
||||||
|
CNAME RecordType = "CNAME"
|
||||||
|
// MX ...
|
||||||
|
MX RecordType = "MX"
|
||||||
|
// NS ...
|
||||||
|
NS RecordType = "NS"
|
||||||
|
// PTR ...
|
||||||
|
PTR RecordType = "PTR"
|
||||||
|
// SOA ...
|
||||||
|
SOA RecordType = "SOA"
|
||||||
|
// SRV ...
|
||||||
|
SRV RecordType = "SRV"
|
||||||
|
// TXT ...
|
||||||
|
TXT RecordType = "TXT"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PossibleRecordTypeValues returns an array of possible values for the RecordType const type.
|
||||||
|
func PossibleRecordTypeValues() []RecordType {
|
||||||
|
return []RecordType{A, AAAA, CAA, CNAME, MX, NS, PTR, SOA, SRV, TXT}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AaaaRecord an AAAA record.
|
||||||
|
type AaaaRecord struct {
|
||||||
|
// Ipv6Address - The IPv6 address of this AAAA record.
|
||||||
|
Ipv6Address *string `json:"ipv6Address,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ARecord an A record.
|
||||||
|
type ARecord struct {
|
||||||
|
// Ipv4Address - The IPv4 address of this A record.
|
||||||
|
Ipv4Address *string `json:"ipv4Address,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaaRecord a CAA record.
|
||||||
|
type CaaRecord struct {
|
||||||
|
// Flags - The flags for this CAA record as an integer between 0 and 255.
|
||||||
|
Flags *int32 `json:"flags,omitempty"`
|
||||||
|
// Tag - The tag for this CAA record.
|
||||||
|
Tag *string `json:"tag,omitempty"`
|
||||||
|
// Value - The value for this CAA record.
|
||||||
|
Value *string `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloudError an error message
|
||||||
|
type CloudError struct {
|
||||||
|
// Error - The error message body
|
||||||
|
Error *CloudErrorBody `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloudErrorBody the body of an error message
|
||||||
|
type CloudErrorBody struct {
|
||||||
|
// Code - The error code
|
||||||
|
Code *string `json:"code,omitempty"`
|
||||||
|
// Message - A description of what caused the error
|
||||||
|
Message *string `json:"message,omitempty"`
|
||||||
|
// Target - The target resource of the error message
|
||||||
|
Target *string `json:"target,omitempty"`
|
||||||
|
// Details - Extra error information
|
||||||
|
Details *[]CloudErrorBody `json:"details,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CnameRecord a CNAME record.
|
||||||
|
type CnameRecord struct {
|
||||||
|
// Cname - The canonical name for this CNAME record.
|
||||||
|
Cname *string `json:"cname,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MxRecord an MX record.
|
||||||
|
type MxRecord struct {
|
||||||
|
// Preference - The preference value for this MX record.
|
||||||
|
Preference *int32 `json:"preference,omitempty"`
|
||||||
|
// Exchange - The domain name of the mail host for this MX record.
|
||||||
|
Exchange *string `json:"exchange,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NsRecord an NS record.
|
||||||
|
type NsRecord struct {
|
||||||
|
// Nsdname - The name server name for this NS record.
|
||||||
|
Nsdname *string `json:"nsdname,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PtrRecord a PTR record.
|
||||||
|
type PtrRecord struct {
|
||||||
|
// Ptrdname - The PTR target domain name for this PTR record.
|
||||||
|
Ptrdname *string `json:"ptrdname,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordSet describes a DNS record set (a collection of DNS records with the same name and type).
|
||||||
|
type RecordSet struct {
|
||||||
|
autorest.Response `json:"-"`
|
||||||
|
// ID - The ID of the record set.
|
||||||
|
ID *string `json:"id,omitempty"`
|
||||||
|
// Name - The name of the record set.
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
// Type - The type of the record set.
|
||||||
|
Type *string `json:"type,omitempty"`
|
||||||
|
// Etag - The etag of the record set.
|
||||||
|
Etag *string `json:"etag,omitempty"`
|
||||||
|
// RecordSetProperties - The properties of the record set.
|
||||||
|
*RecordSetProperties `json:"properties,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON is the custom marshaler for RecordSet.
|
||||||
|
func (rs RecordSet) MarshalJSON() ([]byte, error) {
|
||||||
|
objectMap := make(map[string]interface{})
|
||||||
|
if rs.ID != nil {
|
||||||
|
objectMap["id"] = rs.ID
|
||||||
|
}
|
||||||
|
if rs.Name != nil {
|
||||||
|
objectMap["name"] = rs.Name
|
||||||
|
}
|
||||||
|
if rs.Type != nil {
|
||||||
|
objectMap["type"] = rs.Type
|
||||||
|
}
|
||||||
|
if rs.Etag != nil {
|
||||||
|
objectMap["etag"] = rs.Etag
|
||||||
|
}
|
||||||
|
if rs.RecordSetProperties != nil {
|
||||||
|
objectMap["properties"] = rs.RecordSetProperties
|
||||||
|
}
|
||||||
|
return json.Marshal(objectMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON is the custom unmarshaler for RecordSet struct.
|
||||||
|
func (rs *RecordSet) UnmarshalJSON(body []byte) error {
|
||||||
|
var m map[string]*json.RawMessage
|
||||||
|
err := json.Unmarshal(body, &m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for k, v := range m {
|
||||||
|
switch k {
|
||||||
|
case "id":
|
||||||
|
if v != nil {
|
||||||
|
var ID string
|
||||||
|
err = json.Unmarshal(*v, &ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rs.ID = &ID
|
||||||
|
}
|
||||||
|
case "name":
|
||||||
|
if v != nil {
|
||||||
|
var name string
|
||||||
|
err = json.Unmarshal(*v, &name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rs.Name = &name
|
||||||
|
}
|
||||||
|
case "type":
|
||||||
|
if v != nil {
|
||||||
|
var typeVar string
|
||||||
|
err = json.Unmarshal(*v, &typeVar)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rs.Type = &typeVar
|
||||||
|
}
|
||||||
|
case "etag":
|
||||||
|
if v != nil {
|
||||||
|
var etag string
|
||||||
|
err = json.Unmarshal(*v, &etag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rs.Etag = &etag
|
||||||
|
}
|
||||||
|
case "properties":
|
||||||
|
if v != nil {
|
||||||
|
var recordSetProperties RecordSetProperties
|
||||||
|
err = json.Unmarshal(*v, &recordSetProperties)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rs.RecordSetProperties = &recordSetProperties
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordSetListResult the response to a record set List operation.
|
||||||
|
type RecordSetListResult struct {
|
||||||
|
autorest.Response `json:"-"`
|
||||||
|
// Value - Information about the record sets in the response.
|
||||||
|
Value *[]RecordSet `json:"value,omitempty"`
|
||||||
|
// NextLink - The continuation token for the next page of results.
|
||||||
|
NextLink *string `json:"nextLink,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordSetListResultIterator provides access to a complete listing of RecordSet values.
|
||||||
|
type RecordSetListResultIterator struct {
|
||||||
|
i int
|
||||||
|
page RecordSetListResultPage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next advances to the next value. If there was an error making
|
||||||
|
// the request the iterator does not advance and the error is returned.
|
||||||
|
func (iter *RecordSetListResultIterator) Next() error {
|
||||||
|
iter.i++
|
||||||
|
if iter.i < len(iter.page.Values()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := iter.page.Next()
|
||||||
|
if err != nil {
|
||||||
|
iter.i--
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iter.i = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotDone returns true if the enumeration should be started or is not yet complete.
|
||||||
|
func (iter RecordSetListResultIterator) NotDone() bool {
|
||||||
|
return iter.page.NotDone() && iter.i < len(iter.page.Values())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response returns the raw server response from the last page request.
|
||||||
|
func (iter RecordSetListResultIterator) Response() RecordSetListResult {
|
||||||
|
return iter.page.Response()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the current value or a zero-initialized value if the
|
||||||
|
// iterator has advanced beyond the end of the collection.
|
||||||
|
func (iter RecordSetListResultIterator) Value() RecordSet {
|
||||||
|
if !iter.page.NotDone() {
|
||||||
|
return RecordSet{}
|
||||||
|
}
|
||||||
|
return iter.page.Values()[iter.i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if the ListResult contains no values.
|
||||||
|
func (rslr RecordSetListResult) IsEmpty() bool {
|
||||||
|
return rslr.Value == nil || len(*rslr.Value) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// recordSetListResultPreparer prepares a request to retrieve the next set of results.
|
||||||
|
// It returns nil if no more results exist.
|
||||||
|
func (rslr RecordSetListResult) recordSetListResultPreparer() (*http.Request, error) {
|
||||||
|
if rslr.NextLink == nil || len(to.String(rslr.NextLink)) < 1 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return autorest.Prepare(&http.Request{},
|
||||||
|
autorest.AsJSON(),
|
||||||
|
autorest.AsGet(),
|
||||||
|
autorest.WithBaseURL(to.String(rslr.NextLink)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordSetListResultPage contains a page of RecordSet values.
|
||||||
|
type RecordSetListResultPage struct {
|
||||||
|
fn func(RecordSetListResult) (RecordSetListResult, error)
|
||||||
|
rslr RecordSetListResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next advances to the next page of values. If there was an error making
|
||||||
|
// the request the page does not advance and the error is returned.
|
||||||
|
func (page *RecordSetListResultPage) Next() error {
|
||||||
|
next, err := page.fn(page.rslr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
page.rslr = next
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotDone returns true if the page enumeration should be started or is not yet complete.
|
||||||
|
func (page RecordSetListResultPage) NotDone() bool {
|
||||||
|
return !page.rslr.IsEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response returns the raw server response from the last page request.
|
||||||
|
func (page RecordSetListResultPage) Response() RecordSetListResult {
|
||||||
|
return page.rslr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values returns the slice of values for the current page or nil if there are no values.
|
||||||
|
func (page RecordSetListResultPage) Values() []RecordSet {
|
||||||
|
if page.rslr.IsEmpty() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return *page.rslr.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordSetProperties represents the properties of the records in the record set.
|
||||||
|
type RecordSetProperties struct {
|
||||||
|
// Metadata - The metadata attached to the record set.
|
||||||
|
Metadata map[string]*string `json:"metadata"`
|
||||||
|
// TTL - The TTL (time-to-live) of the records in the record set.
|
||||||
|
TTL *int64 `json:"TTL,omitempty"`
|
||||||
|
// Fqdn - Fully qualified domain name of the record set.
|
||||||
|
Fqdn *string `json:"fqdn,omitempty"`
|
||||||
|
// ARecords - The list of A records in the record set.
|
||||||
|
ARecords *[]ARecord `json:"ARecords,omitempty"`
|
||||||
|
// AaaaRecords - The list of AAAA records in the record set.
|
||||||
|
AaaaRecords *[]AaaaRecord `json:"AAAARecords,omitempty"`
|
||||||
|
// MxRecords - The list of MX records in the record set.
|
||||||
|
MxRecords *[]MxRecord `json:"MXRecords,omitempty"`
|
||||||
|
// NsRecords - The list of NS records in the record set.
|
||||||
|
NsRecords *[]NsRecord `json:"NSRecords,omitempty"`
|
||||||
|
// PtrRecords - The list of PTR records in the record set.
|
||||||
|
PtrRecords *[]PtrRecord `json:"PTRRecords,omitempty"`
|
||||||
|
// SrvRecords - The list of SRV records in the record set.
|
||||||
|
SrvRecords *[]SrvRecord `json:"SRVRecords,omitempty"`
|
||||||
|
// TxtRecords - The list of TXT records in the record set.
|
||||||
|
TxtRecords *[]TxtRecord `json:"TXTRecords,omitempty"`
|
||||||
|
// CnameRecord - The CNAME record in the record set.
|
||||||
|
CnameRecord *CnameRecord `json:"CNAMERecord,omitempty"`
|
||||||
|
// SoaRecord - The SOA record in the record set.
|
||||||
|
SoaRecord *SoaRecord `json:"SOARecord,omitempty"`
|
||||||
|
// CaaRecords - The list of CAA records in the record set.
|
||||||
|
CaaRecords *[]CaaRecord `json:"caaRecords,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON is the custom marshaler for RecordSetProperties.
|
||||||
|
func (rsp RecordSetProperties) MarshalJSON() ([]byte, error) {
|
||||||
|
objectMap := make(map[string]interface{})
|
||||||
|
if rsp.Metadata != nil {
|
||||||
|
objectMap["metadata"] = rsp.Metadata
|
||||||
|
}
|
||||||
|
if rsp.TTL != nil {
|
||||||
|
objectMap["TTL"] = rsp.TTL
|
||||||
|
}
|
||||||
|
if rsp.Fqdn != nil {
|
||||||
|
objectMap["fqdn"] = rsp.Fqdn
|
||||||
|
}
|
||||||
|
if rsp.ARecords != nil {
|
||||||
|
objectMap["ARecords"] = rsp.ARecords
|
||||||
|
}
|
||||||
|
if rsp.AaaaRecords != nil {
|
||||||
|
objectMap["AAAARecords"] = rsp.AaaaRecords
|
||||||
|
}
|
||||||
|
if rsp.MxRecords != nil {
|
||||||
|
objectMap["MXRecords"] = rsp.MxRecords
|
||||||
|
}
|
||||||
|
if rsp.NsRecords != nil {
|
||||||
|
objectMap["NSRecords"] = rsp.NsRecords
|
||||||
|
}
|
||||||
|
if rsp.PtrRecords != nil {
|
||||||
|
objectMap["PTRRecords"] = rsp.PtrRecords
|
||||||
|
}
|
||||||
|
if rsp.SrvRecords != nil {
|
||||||
|
objectMap["SRVRecords"] = rsp.SrvRecords
|
||||||
|
}
|
||||||
|
if rsp.TxtRecords != nil {
|
||||||
|
objectMap["TXTRecords"] = rsp.TxtRecords
|
||||||
|
}
|
||||||
|
if rsp.CnameRecord != nil {
|
||||||
|
objectMap["CNAMERecord"] = rsp.CnameRecord
|
||||||
|
}
|
||||||
|
if rsp.SoaRecord != nil {
|
||||||
|
objectMap["SOARecord"] = rsp.SoaRecord
|
||||||
|
}
|
||||||
|
if rsp.CaaRecords != nil {
|
||||||
|
objectMap["caaRecords"] = rsp.CaaRecords
|
||||||
|
}
|
||||||
|
return json.Marshal(objectMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordSetUpdateParameters parameters supplied to update a record set.
|
||||||
|
type RecordSetUpdateParameters struct {
|
||||||
|
// RecordSet - Specifies information about the record set being updated.
|
||||||
|
RecordSet *RecordSet `json:"RecordSet,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resource common properties of an Azure Resource Manager resource
|
||||||
|
type Resource struct {
|
||||||
|
// ID - Resource ID.
|
||||||
|
ID *string `json:"id,omitempty"`
|
||||||
|
// Name - Resource name.
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
// Type - Resource type.
|
||||||
|
Type *string `json:"type,omitempty"`
|
||||||
|
// Location - Resource location.
|
||||||
|
Location *string `json:"location,omitempty"`
|
||||||
|
// Tags - Resource tags.
|
||||||
|
Tags map[string]*string `json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON is the custom marshaler for Resource.
|
||||||
|
func (r Resource) MarshalJSON() ([]byte, error) {
|
||||||
|
objectMap := make(map[string]interface{})
|
||||||
|
if r.ID != nil {
|
||||||
|
objectMap["id"] = r.ID
|
||||||
|
}
|
||||||
|
if r.Name != nil {
|
||||||
|
objectMap["name"] = r.Name
|
||||||
|
}
|
||||||
|
if r.Type != nil {
|
||||||
|
objectMap["type"] = r.Type
|
||||||
|
}
|
||||||
|
if r.Location != nil {
|
||||||
|
objectMap["location"] = r.Location
|
||||||
|
}
|
||||||
|
if r.Tags != nil {
|
||||||
|
objectMap["tags"] = r.Tags
|
||||||
|
}
|
||||||
|
return json.Marshal(objectMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SoaRecord an SOA record.
|
||||||
|
type SoaRecord struct {
|
||||||
|
// Host - The domain name of the authoritative name server for this SOA record.
|
||||||
|
Host *string `json:"host,omitempty"`
|
||||||
|
// Email - The email contact for this SOA record.
|
||||||
|
Email *string `json:"email,omitempty"`
|
||||||
|
// SerialNumber - The serial number for this SOA record.
|
||||||
|
SerialNumber *int64 `json:"serialNumber,omitempty"`
|
||||||
|
// RefreshTime - The refresh value for this SOA record.
|
||||||
|
RefreshTime *int64 `json:"refreshTime,omitempty"`
|
||||||
|
// RetryTime - The retry time for this SOA record.
|
||||||
|
RetryTime *int64 `json:"retryTime,omitempty"`
|
||||||
|
// ExpireTime - The expire time for this SOA record.
|
||||||
|
ExpireTime *int64 `json:"expireTime,omitempty"`
|
||||||
|
// MinimumTTL - The minimum value for this SOA record. By convention this is used to determine the negative caching duration.
|
||||||
|
MinimumTTL *int64 `json:"minimumTTL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SrvRecord an SRV record.
|
||||||
|
type SrvRecord struct {
|
||||||
|
// Priority - The priority value for this SRV record.
|
||||||
|
Priority *int32 `json:"priority,omitempty"`
|
||||||
|
// Weight - The weight value for this SRV record.
|
||||||
|
Weight *int32 `json:"weight,omitempty"`
|
||||||
|
// Port - The port value for this SRV record.
|
||||||
|
Port *int32 `json:"port,omitempty"`
|
||||||
|
// Target - The target domain name for this SRV record.
|
||||||
|
Target *string `json:"target,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubResource a reference to a another resource
|
||||||
|
type SubResource struct {
|
||||||
|
// ID - Resource Id.
|
||||||
|
ID *string `json:"id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TxtRecord a TXT record.
|
||||||
|
type TxtRecord struct {
|
||||||
|
// Value - The text value of this TXT record.
|
||||||
|
Value *[]string `json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zone describes a DNS zone.
|
||||||
|
type Zone struct {
|
||||||
|
autorest.Response `json:"-"`
|
||||||
|
// Etag - The etag of the zone.
|
||||||
|
Etag *string `json:"etag,omitempty"`
|
||||||
|
// ZoneProperties - The properties of the zone.
|
||||||
|
*ZoneProperties `json:"properties,omitempty"`
|
||||||
|
// ID - Resource ID.
|
||||||
|
ID *string `json:"id,omitempty"`
|
||||||
|
// Name - Resource name.
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
// Type - Resource type.
|
||||||
|
Type *string `json:"type,omitempty"`
|
||||||
|
// Location - Resource location.
|
||||||
|
Location *string `json:"location,omitempty"`
|
||||||
|
// Tags - Resource tags.
|
||||||
|
Tags map[string]*string `json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON is the custom marshaler for Zone.
|
||||||
|
func (z Zone) MarshalJSON() ([]byte, error) {
|
||||||
|
objectMap := make(map[string]interface{})
|
||||||
|
if z.Etag != nil {
|
||||||
|
objectMap["etag"] = z.Etag
|
||||||
|
}
|
||||||
|
if z.ZoneProperties != nil {
|
||||||
|
objectMap["properties"] = z.ZoneProperties
|
||||||
|
}
|
||||||
|
if z.ID != nil {
|
||||||
|
objectMap["id"] = z.ID
|
||||||
|
}
|
||||||
|
if z.Name != nil {
|
||||||
|
objectMap["name"] = z.Name
|
||||||
|
}
|
||||||
|
if z.Type != nil {
|
||||||
|
objectMap["type"] = z.Type
|
||||||
|
}
|
||||||
|
if z.Location != nil {
|
||||||
|
objectMap["location"] = z.Location
|
||||||
|
}
|
||||||
|
if z.Tags != nil {
|
||||||
|
objectMap["tags"] = z.Tags
|
||||||
|
}
|
||||||
|
return json.Marshal(objectMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON is the custom unmarshaler for Zone struct.
|
||||||
|
func (z *Zone) UnmarshalJSON(body []byte) error {
|
||||||
|
var m map[string]*json.RawMessage
|
||||||
|
err := json.Unmarshal(body, &m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for k, v := range m {
|
||||||
|
switch k {
|
||||||
|
case "etag":
|
||||||
|
if v != nil {
|
||||||
|
var etag string
|
||||||
|
err = json.Unmarshal(*v, &etag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
z.Etag = &etag
|
||||||
|
}
|
||||||
|
case "properties":
|
||||||
|
if v != nil {
|
||||||
|
var zoneProperties ZoneProperties
|
||||||
|
err = json.Unmarshal(*v, &zoneProperties)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
z.ZoneProperties = &zoneProperties
|
||||||
|
}
|
||||||
|
case "id":
|
||||||
|
if v != nil {
|
||||||
|
var ID string
|
||||||
|
err = json.Unmarshal(*v, &ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
z.ID = &ID
|
||||||
|
}
|
||||||
|
case "name":
|
||||||
|
if v != nil {
|
||||||
|
var name string
|
||||||
|
err = json.Unmarshal(*v, &name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
z.Name = &name
|
||||||
|
}
|
||||||
|
case "type":
|
||||||
|
if v != nil {
|
||||||
|
var typeVar string
|
||||||
|
err = json.Unmarshal(*v, &typeVar)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
z.Type = &typeVar
|
||||||
|
}
|
||||||
|
case "location":
|
||||||
|
if v != nil {
|
||||||
|
var location string
|
||||||
|
err = json.Unmarshal(*v, &location)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
z.Location = &location
|
||||||
|
}
|
||||||
|
case "tags":
|
||||||
|
if v != nil {
|
||||||
|
var tags map[string]*string
|
||||||
|
err = json.Unmarshal(*v, &tags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
z.Tags = tags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneListResult the response to a Zone List or ListAll operation.
|
||||||
|
type ZoneListResult struct {
|
||||||
|
autorest.Response `json:"-"`
|
||||||
|
// Value - Information about the DNS zones.
|
||||||
|
Value *[]Zone `json:"value,omitempty"`
|
||||||
|
// NextLink - The continuation token for the next page of results.
|
||||||
|
NextLink *string `json:"nextLink,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneListResultIterator provides access to a complete listing of Zone values.
|
||||||
|
type ZoneListResultIterator struct {
|
||||||
|
i int
|
||||||
|
page ZoneListResultPage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next advances to the next value. If there was an error making
|
||||||
|
// the request the iterator does not advance and the error is returned.
|
||||||
|
func (iter *ZoneListResultIterator) Next() error {
|
||||||
|
iter.i++
|
||||||
|
if iter.i < len(iter.page.Values()) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := iter.page.Next()
|
||||||
|
if err != nil {
|
||||||
|
iter.i--
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iter.i = 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotDone returns true if the enumeration should be started or is not yet complete.
|
||||||
|
func (iter ZoneListResultIterator) NotDone() bool {
|
||||||
|
return iter.page.NotDone() && iter.i < len(iter.page.Values())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response returns the raw server response from the last page request.
|
||||||
|
func (iter ZoneListResultIterator) Response() ZoneListResult {
|
||||||
|
return iter.page.Response()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns the current value or a zero-initialized value if the
|
||||||
|
// iterator has advanced beyond the end of the collection.
|
||||||
|
func (iter ZoneListResultIterator) Value() Zone {
|
||||||
|
if !iter.page.NotDone() {
|
||||||
|
return Zone{}
|
||||||
|
}
|
||||||
|
return iter.page.Values()[iter.i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if the ListResult contains no values.
|
||||||
|
func (zlr ZoneListResult) IsEmpty() bool {
|
||||||
|
return zlr.Value == nil || len(*zlr.Value) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// zoneListResultPreparer prepares a request to retrieve the next set of results.
|
||||||
|
// It returns nil if no more results exist.
|
||||||
|
func (zlr ZoneListResult) zoneListResultPreparer() (*http.Request, error) {
|
||||||
|
if zlr.NextLink == nil || len(to.String(zlr.NextLink)) < 1 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return autorest.Prepare(&http.Request{},
|
||||||
|
autorest.AsJSON(),
|
||||||
|
autorest.AsGet(),
|
||||||
|
autorest.WithBaseURL(to.String(zlr.NextLink)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneListResultPage contains a page of Zone values.
|
||||||
|
type ZoneListResultPage struct {
|
||||||
|
fn func(ZoneListResult) (ZoneListResult, error)
|
||||||
|
zlr ZoneListResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next advances to the next page of values. If there was an error making
|
||||||
|
// the request the page does not advance and the error is returned.
|
||||||
|
func (page *ZoneListResultPage) Next() error {
|
||||||
|
next, err := page.fn(page.zlr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
page.zlr = next
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotDone returns true if the page enumeration should be started or is not yet complete.
|
||||||
|
func (page ZoneListResultPage) NotDone() bool {
|
||||||
|
return !page.zlr.IsEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response returns the raw server response from the last page request.
|
||||||
|
func (page ZoneListResultPage) Response() ZoneListResult {
|
||||||
|
return page.zlr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values returns the slice of values for the current page or nil if there are no values.
|
||||||
|
func (page ZoneListResultPage) Values() []Zone {
|
||||||
|
if page.zlr.IsEmpty() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return *page.zlr.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneProperties represents the properties of the zone.
|
||||||
|
type ZoneProperties struct {
|
||||||
|
// MaxNumberOfRecordSets - The maximum number of record sets that can be created in this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
|
||||||
|
MaxNumberOfRecordSets *int64 `json:"maxNumberOfRecordSets,omitempty"`
|
||||||
|
// NumberOfRecordSets - The current number of record sets in this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
|
||||||
|
NumberOfRecordSets *int64 `json:"numberOfRecordSets,omitempty"`
|
||||||
|
// NameServers - The name servers for this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
|
||||||
|
NameServers *[]string `json:"nameServers,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZonesDeleteFuture an abstraction for monitoring and retrieving the results of a long-running operation.
|
||||||
|
type ZonesDeleteFuture struct {
|
||||||
|
azure.Future
|
||||||
|
req *http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result returns the result of the asynchronous operation.
|
||||||
|
// If the operation has not completed it will return an error.
|
||||||
|
func (future ZonesDeleteFuture) Result(client ZonesClient) (ar autorest.Response, err error) {
|
||||||
|
var done bool
|
||||||
|
done, err = future.Done(client)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesDeleteFuture", "Result", future.Response(), "Polling failure")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !done {
|
||||||
|
return ar, azure.NewAsyncOpIncompleteError("dns.ZonesDeleteFuture")
|
||||||
|
}
|
||||||
|
if future.PollingMethod() == azure.PollingLocation {
|
||||||
|
ar, err = client.DeleteResponder(future.Response())
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesDeleteFuture", "Result", future.Response(), "Failure responding to request")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req *http.Request
|
||||||
|
var resp *http.Response
|
||||||
|
if future.PollingURL() != "" {
|
||||||
|
req, err = http.NewRequest(http.MethodGet, future.PollingURL(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
req = autorest.ChangeToGet(future.req)
|
||||||
|
}
|
||||||
|
resp, err = autorest.SendWithSender(client, req,
|
||||||
|
autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...))
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesDeleteFuture", "Result", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ar, err = client.DeleteResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesDeleteFuture", "Result", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
567
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/recordsets.go
generated
vendored
Normal file
567
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/recordsets.go
generated
vendored
Normal file
|
@ -0,0 +1,567 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||||
|
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
"github.com/Azure/go-autorest/autorest/azure"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RecordSetsClient is the the DNS Management Client.
|
||||||
|
type RecordSetsClient struct {
|
||||||
|
BaseClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRecordSetsClient creates an instance of the RecordSetsClient client.
|
||||||
|
func NewRecordSetsClient(subscriptionID string) RecordSetsClient {
|
||||||
|
return NewRecordSetsClientWithBaseURI(DefaultBaseURI, subscriptionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRecordSetsClientWithBaseURI creates an instance of the RecordSetsClient client.
|
||||||
|
func NewRecordSetsClientWithBaseURI(baseURI string, subscriptionID string) RecordSetsClient {
|
||||||
|
return RecordSetsClient{NewWithBaseURI(baseURI, subscriptionID)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOrUpdate creates or updates a record set within a DNS zone.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// zoneName - the name of the DNS zone (without a terminating dot).
|
||||||
|
// relativeRecordSetName - the name of the record set, relative to the name of the zone.
|
||||||
|
// recordType - the type of DNS record in this record set. Record sets of type SOA can be updated but not
|
||||||
|
// created (they are created when the DNS zone is created).
|
||||||
|
// parameters - parameters supplied to the CreateOrUpdate operation.
|
||||||
|
// ifMatch - the etag of the record set. Omit this value to always overwrite the current record set. Specify
|
||||||
|
// the last-seen etag value to prevent accidentally overwritting any concurrent changes.
|
||||||
|
// ifNoneMatch - set to '*' to allow a new record set to be created, but to prevent updating an existing record
|
||||||
|
// set. Other values will be ignored.
|
||||||
|
func (client RecordSetsClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string, ifNoneMatch string) (result RecordSet, err error) {
|
||||||
|
req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, zoneName, relativeRecordSetName, recordType, parameters, ifMatch, ifNoneMatch)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "CreateOrUpdate", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.CreateOrUpdateSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "CreateOrUpdate", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = client.CreateOrUpdateResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "CreateOrUpdate", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOrUpdatePreparer prepares the CreateOrUpdate request.
|
||||||
|
func (client RecordSetsClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string, ifNoneMatch string) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"recordType": autorest.Encode("path", recordType),
|
||||||
|
"relativeRecordSetName": relativeRecordSetName,
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
"zoneName": autorest.Encode("path", zoneName),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsContentType("application/json; charset=utf-8"),
|
||||||
|
autorest.AsPut(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}/{recordType}/{relativeRecordSetName}", pathParameters),
|
||||||
|
autorest.WithJSON(parameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
if len(ifMatch) > 0 {
|
||||||
|
preparer = autorest.DecoratePreparer(preparer,
|
||||||
|
autorest.WithHeader("If-Match", autorest.String(ifMatch)))
|
||||||
|
}
|
||||||
|
if len(ifNoneMatch) > 0 {
|
||||||
|
preparer = autorest.DecoratePreparer(preparer,
|
||||||
|
autorest.WithHeader("If-None-Match", autorest.String(ifNoneMatch)))
|
||||||
|
}
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client RecordSetsClient) CreateOrUpdateSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client RecordSetsClient) CreateOrUpdateResponder(resp *http.Response) (result RecordSet, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
|
||||||
|
autorest.ByUnmarshallingJSON(&result),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes a record set from a DNS zone. This operation cannot be undone.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// zoneName - the name of the DNS zone (without a terminating dot).
|
||||||
|
// relativeRecordSetName - the name of the record set, relative to the name of the zone.
|
||||||
|
// recordType - the type of DNS record in this record set. Record sets of type SOA cannot be deleted (they are
|
||||||
|
// deleted when the DNS zone is deleted).
|
||||||
|
// ifMatch - the etag of the record set. Omit this value to always delete the current record set. Specify the
|
||||||
|
// last-seen etag value to prevent accidentally deleting any concurrent changes.
|
||||||
|
func (client RecordSetsClient) Delete(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, ifMatch string) (result autorest.Response, err error) {
|
||||||
|
req, err := client.DeletePreparer(ctx, resourceGroupName, zoneName, relativeRecordSetName, recordType, ifMatch)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "Delete", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.DeleteSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = resp
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "Delete", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = client.DeleteResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "Delete", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletePreparer prepares the Delete request.
|
||||||
|
func (client RecordSetsClient) DeletePreparer(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, ifMatch string) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"recordType": autorest.Encode("path", recordType),
|
||||||
|
"relativeRecordSetName": relativeRecordSetName,
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
"zoneName": autorest.Encode("path", zoneName),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsDelete(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}/{recordType}/{relativeRecordSetName}", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
if len(ifMatch) > 0 {
|
||||||
|
preparer = autorest.DecoratePreparer(preparer,
|
||||||
|
autorest.WithHeader("If-Match", autorest.String(ifMatch)))
|
||||||
|
}
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSender sends the Delete request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client RecordSetsClient) DeleteSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResponder handles the response to the Delete request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client RecordSetsClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = resp
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets a record set.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// zoneName - the name of the DNS zone (without a terminating dot).
|
||||||
|
// relativeRecordSetName - the name of the record set, relative to the name of the zone.
|
||||||
|
// recordType - the type of DNS record in this record set.
|
||||||
|
func (client RecordSetsClient) Get(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType) (result RecordSet, err error) {
|
||||||
|
req, err := client.GetPreparer(ctx, resourceGroupName, zoneName, relativeRecordSetName, recordType)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "Get", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.GetSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "Get", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = client.GetResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "Get", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPreparer prepares the Get request.
|
||||||
|
func (client RecordSetsClient) GetPreparer(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"recordType": autorest.Encode("path", recordType),
|
||||||
|
"relativeRecordSetName": relativeRecordSetName,
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
"zoneName": autorest.Encode("path", zoneName),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsGet(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}/{recordType}/{relativeRecordSetName}", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSender sends the Get request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client RecordSetsClient) GetSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResponder handles the response to the Get request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client RecordSetsClient) GetResponder(resp *http.Response) (result RecordSet, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
|
autorest.ByUnmarshallingJSON(&result),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByDNSZone lists all record sets in a DNS zone.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// zoneName - the name of the DNS zone (without a terminating dot).
|
||||||
|
// top - the maximum number of record sets to return. If not specified, returns up to 100 record sets.
|
||||||
|
// recordsetnamesuffix - the suffix label of the record set name that has to be used to filter the record set
|
||||||
|
// enumerations. If this parameter is specified, Enumeration will return only records that end with
|
||||||
|
// .<recordSetNameSuffix>
|
||||||
|
func (client RecordSetsClient) ListByDNSZone(ctx context.Context, resourceGroupName string, zoneName string, top *int32, recordsetnamesuffix string) (result RecordSetListResultPage, err error) {
|
||||||
|
result.fn = client.listByDNSZoneNextResults
|
||||||
|
req, err := client.ListByDNSZonePreparer(ctx, resourceGroupName, zoneName, top, recordsetnamesuffix)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByDNSZone", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.ListByDNSZoneSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.rslr.Response = autorest.Response{Response: resp}
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByDNSZone", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result.rslr, err = client.ListByDNSZoneResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByDNSZone", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByDNSZonePreparer prepares the ListByDNSZone request.
|
||||||
|
func (client RecordSetsClient) ListByDNSZonePreparer(ctx context.Context, resourceGroupName string, zoneName string, top *int32, recordsetnamesuffix string) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
"zoneName": autorest.Encode("path", zoneName),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
if top != nil {
|
||||||
|
queryParameters["$top"] = autorest.Encode("query", *top)
|
||||||
|
}
|
||||||
|
if len(recordsetnamesuffix) > 0 {
|
||||||
|
queryParameters["$recordsetnamesuffix"] = autorest.Encode("query", recordsetnamesuffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsGet(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}/recordsets", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByDNSZoneSender sends the ListByDNSZone request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client RecordSetsClient) ListByDNSZoneSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByDNSZoneResponder handles the response to the ListByDNSZone request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client RecordSetsClient) ListByDNSZoneResponder(resp *http.Response) (result RecordSetListResult, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
|
autorest.ByUnmarshallingJSON(&result),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// listByDNSZoneNextResults retrieves the next set of results, if any.
|
||||||
|
func (client RecordSetsClient) listByDNSZoneNextResults(lastResults RecordSetListResult) (result RecordSetListResult, err error) {
|
||||||
|
req, err := lastResults.recordSetListResultPreparer()
|
||||||
|
if err != nil {
|
||||||
|
return result, autorest.NewErrorWithError(err, "dns.RecordSetsClient", "listByDNSZoneNextResults", nil, "Failure preparing next results request")
|
||||||
|
}
|
||||||
|
if req == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, err := client.ListByDNSZoneSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return result, autorest.NewErrorWithError(err, "dns.RecordSetsClient", "listByDNSZoneNextResults", resp, "Failure sending next results request")
|
||||||
|
}
|
||||||
|
result, err = client.ListByDNSZoneResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "listByDNSZoneNextResults", resp, "Failure responding to next results request")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByDNSZoneComplete enumerates all values, automatically crossing page boundaries as required.
|
||||||
|
func (client RecordSetsClient) ListByDNSZoneComplete(ctx context.Context, resourceGroupName string, zoneName string, top *int32, recordsetnamesuffix string) (result RecordSetListResultIterator, err error) {
|
||||||
|
result.page, err = client.ListByDNSZone(ctx, resourceGroupName, zoneName, top, recordsetnamesuffix)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByType lists the record sets of a specified type in a DNS zone.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// zoneName - the name of the DNS zone (without a terminating dot).
|
||||||
|
// recordType - the type of record sets to enumerate.
|
||||||
|
// top - the maximum number of record sets to return. If not specified, returns up to 100 record sets.
|
||||||
|
// recordsetnamesuffix - the suffix label of the record set name that has to be used to filter the record set
|
||||||
|
// enumerations. If this parameter is specified, Enumeration will return only records that end with
|
||||||
|
// .<recordSetNameSuffix>
|
||||||
|
func (client RecordSetsClient) ListByType(ctx context.Context, resourceGroupName string, zoneName string, recordType RecordType, top *int32, recordsetnamesuffix string) (result RecordSetListResultPage, err error) {
|
||||||
|
result.fn = client.listByTypeNextResults
|
||||||
|
req, err := client.ListByTypePreparer(ctx, resourceGroupName, zoneName, recordType, top, recordsetnamesuffix)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByType", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.ListByTypeSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.rslr.Response = autorest.Response{Response: resp}
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByType", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result.rslr, err = client.ListByTypeResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByType", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByTypePreparer prepares the ListByType request.
|
||||||
|
func (client RecordSetsClient) ListByTypePreparer(ctx context.Context, resourceGroupName string, zoneName string, recordType RecordType, top *int32, recordsetnamesuffix string) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"recordType": autorest.Encode("path", recordType),
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
"zoneName": autorest.Encode("path", zoneName),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
if top != nil {
|
||||||
|
queryParameters["$top"] = autorest.Encode("query", *top)
|
||||||
|
}
|
||||||
|
if len(recordsetnamesuffix) > 0 {
|
||||||
|
queryParameters["$recordsetnamesuffix"] = autorest.Encode("query", recordsetnamesuffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsGet(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}/{recordType}", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByTypeSender sends the ListByType request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client RecordSetsClient) ListByTypeSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByTypeResponder handles the response to the ListByType request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client RecordSetsClient) ListByTypeResponder(resp *http.Response) (result RecordSetListResult, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
|
autorest.ByUnmarshallingJSON(&result),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// listByTypeNextResults retrieves the next set of results, if any.
|
||||||
|
func (client RecordSetsClient) listByTypeNextResults(lastResults RecordSetListResult) (result RecordSetListResult, err error) {
|
||||||
|
req, err := lastResults.recordSetListResultPreparer()
|
||||||
|
if err != nil {
|
||||||
|
return result, autorest.NewErrorWithError(err, "dns.RecordSetsClient", "listByTypeNextResults", nil, "Failure preparing next results request")
|
||||||
|
}
|
||||||
|
if req == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, err := client.ListByTypeSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return result, autorest.NewErrorWithError(err, "dns.RecordSetsClient", "listByTypeNextResults", resp, "Failure sending next results request")
|
||||||
|
}
|
||||||
|
result, err = client.ListByTypeResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "listByTypeNextResults", resp, "Failure responding to next results request")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByTypeComplete enumerates all values, automatically crossing page boundaries as required.
|
||||||
|
func (client RecordSetsClient) ListByTypeComplete(ctx context.Context, resourceGroupName string, zoneName string, recordType RecordType, top *int32, recordsetnamesuffix string) (result RecordSetListResultIterator, err error) {
|
||||||
|
result.page, err = client.ListByType(ctx, resourceGroupName, zoneName, recordType, top, recordsetnamesuffix)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates a record set within a DNS zone.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// zoneName - the name of the DNS zone (without a terminating dot).
|
||||||
|
// relativeRecordSetName - the name of the record set, relative to the name of the zone.
|
||||||
|
// recordType - the type of DNS record in this record set.
|
||||||
|
// parameters - parameters supplied to the Update operation.
|
||||||
|
// ifMatch - the etag of the record set. Omit this value to always overwrite the current record set. Specify
|
||||||
|
// the last-seen etag value to prevent accidentally overwritting concurrent changes.
|
||||||
|
func (client RecordSetsClient) Update(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string) (result RecordSet, err error) {
|
||||||
|
req, err := client.UpdatePreparer(ctx, resourceGroupName, zoneName, relativeRecordSetName, recordType, parameters, ifMatch)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "Update", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.UpdateSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "Update", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = client.UpdateResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "Update", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePreparer prepares the Update request.
|
||||||
|
func (client RecordSetsClient) UpdatePreparer(ctx context.Context, resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"recordType": autorest.Encode("path", recordType),
|
||||||
|
"relativeRecordSetName": relativeRecordSetName,
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
"zoneName": autorest.Encode("path", zoneName),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsContentType("application/json; charset=utf-8"),
|
||||||
|
autorest.AsPatch(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}/{recordType}/{relativeRecordSetName}", pathParameters),
|
||||||
|
autorest.WithJSON(parameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
if len(ifMatch) > 0 {
|
||||||
|
preparer = autorest.DecoratePreparer(preparer,
|
||||||
|
autorest.WithHeader("If-Match", autorest.String(ifMatch)))
|
||||||
|
}
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSender sends the Update request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client RecordSetsClient) UpdateSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResponder handles the response to the Update request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client RecordSetsClient) UpdateResponder(resp *http.Response) (result RecordSet, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
|
autorest.ByUnmarshallingJSON(&result),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return
|
||||||
|
}
|
30
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/version.go
generated
vendored
Normal file
30
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/version.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import "github.com/Azure/azure-sdk-for-go/version"
|
||||||
|
|
||||||
|
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||||
|
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
|
||||||
|
// UserAgent returns the UserAgent string to use when sending http.Requests.
|
||||||
|
func UserAgent() string {
|
||||||
|
return "Azure-SDK-For-Go/" + version.Number + " dns/2017-09-01"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns the semantic version (see http://semver.org) of the client.
|
||||||
|
func Version() string {
|
||||||
|
return version.Number
|
||||||
|
}
|
456
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/zones.go
generated
vendored
Normal file
456
vendor/github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns/zones.go
generated
vendored
Normal file
|
@ -0,0 +1,456 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||||
|
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
"github.com/Azure/go-autorest/autorest/azure"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ZonesClient is the the DNS Management Client.
|
||||||
|
type ZonesClient struct {
|
||||||
|
BaseClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewZonesClient creates an instance of the ZonesClient client.
|
||||||
|
func NewZonesClient(subscriptionID string) ZonesClient {
|
||||||
|
return NewZonesClientWithBaseURI(DefaultBaseURI, subscriptionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewZonesClientWithBaseURI creates an instance of the ZonesClient client.
|
||||||
|
func NewZonesClientWithBaseURI(baseURI string, subscriptionID string) ZonesClient {
|
||||||
|
return ZonesClient{NewWithBaseURI(baseURI, subscriptionID)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOrUpdate creates or updates a DNS zone. Does not modify DNS records within the zone.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// zoneName - the name of the DNS zone (without a terminating dot).
|
||||||
|
// parameters - parameters supplied to the CreateOrUpdate operation.
|
||||||
|
// ifMatch - the etag of the DNS zone. Omit this value to always overwrite the current zone. Specify the
|
||||||
|
// last-seen etag value to prevent accidentally overwritting any concurrent changes.
|
||||||
|
// ifNoneMatch - set to '*' to allow a new DNS zone to be created, but to prevent updating an existing zone.
|
||||||
|
// Other values will be ignored.
|
||||||
|
func (client ZonesClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, zoneName string, parameters Zone, ifMatch string, ifNoneMatch string) (result Zone, err error) {
|
||||||
|
req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, zoneName, parameters, ifMatch, ifNoneMatch)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "CreateOrUpdate", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.CreateOrUpdateSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "CreateOrUpdate", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = client.CreateOrUpdateResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "CreateOrUpdate", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOrUpdatePreparer prepares the CreateOrUpdate request.
|
||||||
|
func (client ZonesClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, zoneName string, parameters Zone, ifMatch string, ifNoneMatch string) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
"zoneName": autorest.Encode("path", zoneName),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsContentType("application/json; charset=utf-8"),
|
||||||
|
autorest.AsPut(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}", pathParameters),
|
||||||
|
autorest.WithJSON(parameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
if len(ifMatch) > 0 {
|
||||||
|
preparer = autorest.DecoratePreparer(preparer,
|
||||||
|
autorest.WithHeader("If-Match", autorest.String(ifMatch)))
|
||||||
|
}
|
||||||
|
if len(ifNoneMatch) > 0 {
|
||||||
|
preparer = autorest.DecoratePreparer(preparer,
|
||||||
|
autorest.WithHeader("If-None-Match", autorest.String(ifNoneMatch)))
|
||||||
|
}
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client ZonesClient) CreateOrUpdateSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client ZonesClient) CreateOrUpdateResponder(resp *http.Response) (result Zone, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated),
|
||||||
|
autorest.ByUnmarshallingJSON(&result),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes a DNS zone. WARNING: All DNS records in the zone will also be deleted. This operation cannot be
|
||||||
|
// undone.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// zoneName - the name of the DNS zone (without a terminating dot).
|
||||||
|
// ifMatch - the etag of the DNS zone. Omit this value to always delete the current zone. Specify the last-seen
|
||||||
|
// etag value to prevent accidentally deleting any concurrent changes.
|
||||||
|
func (client ZonesClient) Delete(ctx context.Context, resourceGroupName string, zoneName string, ifMatch string) (result ZonesDeleteFuture, err error) {
|
||||||
|
req, err := client.DeletePreparer(ctx, resourceGroupName, zoneName, ifMatch)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "Delete", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = client.DeleteSender(req)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "Delete", result.Response(), "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletePreparer prepares the Delete request.
|
||||||
|
func (client ZonesClient) DeletePreparer(ctx context.Context, resourceGroupName string, zoneName string, ifMatch string) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
"zoneName": autorest.Encode("path", zoneName),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsDelete(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
if len(ifMatch) > 0 {
|
||||||
|
preparer = autorest.DecoratePreparer(preparer,
|
||||||
|
autorest.WithHeader("If-Match", autorest.String(ifMatch)))
|
||||||
|
}
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSender sends the Delete request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client ZonesClient) DeleteSender(req *http.Request) (future ZonesDeleteFuture, err error) {
|
||||||
|
sender := autorest.DecorateSender(client, azure.DoRetryWithRegistration(client.Client))
|
||||||
|
future.Future = azure.NewFuture(req)
|
||||||
|
future.req = req
|
||||||
|
_, err = future.Done(sender)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = autorest.Respond(future.Response(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResponder handles the response to the Delete request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client ZonesClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = resp
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets a DNS zone. Retrieves the zone properties, but not the record sets within the zone.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// zoneName - the name of the DNS zone (without a terminating dot).
|
||||||
|
func (client ZonesClient) Get(ctx context.Context, resourceGroupName string, zoneName string) (result Zone, err error) {
|
||||||
|
req, err := client.GetPreparer(ctx, resourceGroupName, zoneName)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "Get", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.GetSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "Get", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err = client.GetResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "Get", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPreparer prepares the Get request.
|
||||||
|
func (client ZonesClient) GetPreparer(ctx context.Context, resourceGroupName string, zoneName string) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
"zoneName": autorest.Encode("path", zoneName),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsGet(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSender sends the Get request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client ZonesClient) GetSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResponder handles the response to the Get request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client ZonesClient) GetResponder(resp *http.Response) (result Zone, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
|
autorest.ByUnmarshallingJSON(&result),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// List lists the DNS zones in all resource groups in a subscription.
|
||||||
|
// Parameters:
|
||||||
|
// top - the maximum number of DNS zones to return. If not specified, returns up to 100 zones.
|
||||||
|
func (client ZonesClient) List(ctx context.Context, top *int32) (result ZoneListResultPage, err error) {
|
||||||
|
result.fn = client.listNextResults
|
||||||
|
req, err := client.ListPreparer(ctx, top)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "List", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.ListSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.zlr.Response = autorest.Response{Response: resp}
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "List", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result.zlr, err = client.ListResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "List", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPreparer prepares the List request.
|
||||||
|
func (client ZonesClient) ListPreparer(ctx context.Context, top *int32) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
if top != nil {
|
||||||
|
queryParameters["$top"] = autorest.Encode("query", *top)
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsGet(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.Network/dnszones", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSender sends the List request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client ZonesClient) ListSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListResponder handles the response to the List request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client ZonesClient) ListResponder(resp *http.Response) (result ZoneListResult, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
|
autorest.ByUnmarshallingJSON(&result),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// listNextResults retrieves the next set of results, if any.
|
||||||
|
func (client ZonesClient) listNextResults(lastResults ZoneListResult) (result ZoneListResult, err error) {
|
||||||
|
req, err := lastResults.zoneListResultPreparer()
|
||||||
|
if err != nil {
|
||||||
|
return result, autorest.NewErrorWithError(err, "dns.ZonesClient", "listNextResults", nil, "Failure preparing next results request")
|
||||||
|
}
|
||||||
|
if req == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, err := client.ListSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return result, autorest.NewErrorWithError(err, "dns.ZonesClient", "listNextResults", resp, "Failure sending next results request")
|
||||||
|
}
|
||||||
|
result, err = client.ListResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "listNextResults", resp, "Failure responding to next results request")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListComplete enumerates all values, automatically crossing page boundaries as required.
|
||||||
|
func (client ZonesClient) ListComplete(ctx context.Context, top *int32) (result ZoneListResultIterator, err error) {
|
||||||
|
result.page, err = client.List(ctx, top)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByResourceGroup lists the DNS zones within a resource group.
|
||||||
|
// Parameters:
|
||||||
|
// resourceGroupName - the name of the resource group.
|
||||||
|
// top - the maximum number of record sets to return. If not specified, returns up to 100 record sets.
|
||||||
|
func (client ZonesClient) ListByResourceGroup(ctx context.Context, resourceGroupName string, top *int32) (result ZoneListResultPage, err error) {
|
||||||
|
result.fn = client.listByResourceGroupNextResults
|
||||||
|
req, err := client.ListByResourceGroupPreparer(ctx, resourceGroupName, top)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "ListByResourceGroup", nil, "Failure preparing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.ListByResourceGroupSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.zlr.Response = autorest.Response{Response: resp}
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "ListByResourceGroup", resp, "Failure sending request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result.zlr, err = client.ListByResourceGroupResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "ListByResourceGroup", resp, "Failure responding to request")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByResourceGroupPreparer prepares the ListByResourceGroup request.
|
||||||
|
func (client ZonesClient) ListByResourceGroupPreparer(ctx context.Context, resourceGroupName string, top *int32) (*http.Request, error) {
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"resourceGroupName": autorest.Encode("path", resourceGroupName),
|
||||||
|
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2017-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
if top != nil {
|
||||||
|
queryParameters["$top"] = autorest.Encode("query", *top)
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsGet(),
|
||||||
|
autorest.WithBaseURL(client.BaseURI),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters))
|
||||||
|
return preparer.Prepare((&http.Request{}).WithContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByResourceGroupSender sends the ListByResourceGroup request. The method will close the
|
||||||
|
// http.Response Body if it receives an error.
|
||||||
|
func (client ZonesClient) ListByResourceGroupSender(req *http.Request) (*http.Response, error) {
|
||||||
|
return autorest.SendWithSender(client, req,
|
||||||
|
azure.DoRetryWithRegistration(client.Client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByResourceGroupResponder handles the response to the ListByResourceGroup request. The method always
|
||||||
|
// closes the http.Response Body.
|
||||||
|
func (client ZonesClient) ListByResourceGroupResponder(resp *http.Response) (result ZoneListResult, err error) {
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
client.ByInspecting(),
|
||||||
|
azure.WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
|
autorest.ByUnmarshallingJSON(&result),
|
||||||
|
autorest.ByClosing())
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// listByResourceGroupNextResults retrieves the next set of results, if any.
|
||||||
|
func (client ZonesClient) listByResourceGroupNextResults(lastResults ZoneListResult) (result ZoneListResult, err error) {
|
||||||
|
req, err := lastResults.zoneListResultPreparer()
|
||||||
|
if err != nil {
|
||||||
|
return result, autorest.NewErrorWithError(err, "dns.ZonesClient", "listByResourceGroupNextResults", nil, "Failure preparing next results request")
|
||||||
|
}
|
||||||
|
if req == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, err := client.ListByResourceGroupSender(req)
|
||||||
|
if err != nil {
|
||||||
|
result.Response = autorest.Response{Response: resp}
|
||||||
|
return result, autorest.NewErrorWithError(err, "dns.ZonesClient", "listByResourceGroupNextResults", resp, "Failure sending next results request")
|
||||||
|
}
|
||||||
|
result, err = client.ListByResourceGroupResponder(resp)
|
||||||
|
if err != nil {
|
||||||
|
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "listByResourceGroupNextResults", resp, "Failure responding to next results request")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByResourceGroupComplete enumerates all values, automatically crossing page boundaries as required.
|
||||||
|
func (client ZonesClient) ListByResourceGroupComplete(ctx context.Context, resourceGroupName string, top *int32) (result ZoneListResultIterator, err error) {
|
||||||
|
result.page, err = client.ListByResourceGroup(ctx, resourceGroupName, top)
|
||||||
|
return
|
||||||
|
}
|
21
vendor/github.com/Azure/azure-sdk-for-go/version/version.go
generated
vendored
Normal file
21
vendor/github.com/Azure/azure-sdk-for-go/version/version.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package version
|
||||||
|
|
||||||
|
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||||
|
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
|
||||||
|
// Number contains the semantic version of this SDK.
|
||||||
|
const Number = "v16.2.1"
|
191
vendor/github.com/Azure/go-autorest/LICENSE
generated
vendored
Normal file
191
vendor/github.com/Azure/go-autorest/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Copyright 2015 Microsoft Corporation
|
||||||
|
|
||||||
|
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.
|
81
vendor/github.com/Azure/go-autorest/autorest/adal/config.go
generated
vendored
Normal file
81
vendor/github.com/Azure/go-autorest/autorest/adal/config.go
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
package adal
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
activeDirectoryAPIVersion = "1.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OAuthConfig represents the endpoints needed
|
||||||
|
// in OAuth operations
|
||||||
|
type OAuthConfig struct {
|
||||||
|
AuthorityEndpoint url.URL
|
||||||
|
AuthorizeEndpoint url.URL
|
||||||
|
TokenEndpoint url.URL
|
||||||
|
DeviceCodeEndpoint url.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if the OAuthConfig object is zero-initialized.
|
||||||
|
func (oac OAuthConfig) IsZero() bool {
|
||||||
|
return oac == OAuthConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateStringParam(param, name string) error {
|
||||||
|
if len(param) == 0 {
|
||||||
|
return fmt.Errorf("parameter '" + name + "' cannot be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOAuthConfig returns an OAuthConfig with tenant specific urls
|
||||||
|
func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
|
||||||
|
if err := validateStringParam(activeDirectoryEndpoint, "activeDirectoryEndpoint"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// it's legal for tenantID to be empty so don't validate it
|
||||||
|
const activeDirectoryEndpointTemplate = "%s/oauth2/%s?api-version=%s"
|
||||||
|
u, err := url.Parse(activeDirectoryEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
authorityURL, err := u.Parse(tenantID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
authorizeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "authorize", activeDirectoryAPIVersion))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tokenURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "token", activeDirectoryAPIVersion))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
deviceCodeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "devicecode", activeDirectoryAPIVersion))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OAuthConfig{
|
||||||
|
AuthorityEndpoint: *authorityURL,
|
||||||
|
AuthorizeEndpoint: *authorizeURL,
|
||||||
|
TokenEndpoint: *tokenURL,
|
||||||
|
DeviceCodeEndpoint: *deviceCodeURL,
|
||||||
|
}, nil
|
||||||
|
}
|
242
vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken.go
generated
vendored
Normal file
242
vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken.go
generated
vendored
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
package adal
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is largely based on rjw57/oauth2device's code, with the follow differences:
|
||||||
|
* scope -> resource, and only allow a single one
|
||||||
|
* receive "Message" in the DeviceCode struct and show it to users as the prompt
|
||||||
|
* azure-xplat-cli has the following behavior that this emulates:
|
||||||
|
- does not send client_secret during the token exchange
|
||||||
|
- sends resource again in the token exchange request
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
logPrefix = "autorest/adal/devicetoken:"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrDeviceGeneric represents an unknown error from the token endpoint when using device flow
|
||||||
|
ErrDeviceGeneric = fmt.Errorf("%s Error while retrieving OAuth token: Unknown Error", logPrefix)
|
||||||
|
|
||||||
|
// ErrDeviceAccessDenied represents an access denied error from the token endpoint when using device flow
|
||||||
|
ErrDeviceAccessDenied = fmt.Errorf("%s Error while retrieving OAuth token: Access Denied", logPrefix)
|
||||||
|
|
||||||
|
// ErrDeviceAuthorizationPending represents the server waiting on the user to complete the device flow
|
||||||
|
ErrDeviceAuthorizationPending = fmt.Errorf("%s Error while retrieving OAuth token: Authorization Pending", logPrefix)
|
||||||
|
|
||||||
|
// ErrDeviceCodeExpired represents the server timing out and expiring the code during device flow
|
||||||
|
ErrDeviceCodeExpired = fmt.Errorf("%s Error while retrieving OAuth token: Code Expired", logPrefix)
|
||||||
|
|
||||||
|
// ErrDeviceSlowDown represents the service telling us we're polling too often during device flow
|
||||||
|
ErrDeviceSlowDown = fmt.Errorf("%s Error while retrieving OAuth token: Slow Down", logPrefix)
|
||||||
|
|
||||||
|
// ErrDeviceCodeEmpty represents an empty device code from the device endpoint while using device flow
|
||||||
|
ErrDeviceCodeEmpty = fmt.Errorf("%s Error while retrieving device code: Device Code Empty", logPrefix)
|
||||||
|
|
||||||
|
// ErrOAuthTokenEmpty represents an empty OAuth token from the token endpoint when using device flow
|
||||||
|
ErrOAuthTokenEmpty = fmt.Errorf("%s Error while retrieving OAuth token: Token Empty", logPrefix)
|
||||||
|
|
||||||
|
errCodeSendingFails = "Error occurred while sending request for Device Authorization Code"
|
||||||
|
errCodeHandlingFails = "Error occurred while handling response from the Device Endpoint"
|
||||||
|
errTokenSendingFails = "Error occurred while sending request with device code for a token"
|
||||||
|
errTokenHandlingFails = "Error occurred while handling response from the Token Endpoint (during device flow)"
|
||||||
|
errStatusNotOK = "Error HTTP status != 200"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeviceCode is the object returned by the device auth endpoint
|
||||||
|
// It contains information to instruct the user to complete the auth flow
|
||||||
|
type DeviceCode struct {
|
||||||
|
DeviceCode *string `json:"device_code,omitempty"`
|
||||||
|
UserCode *string `json:"user_code,omitempty"`
|
||||||
|
VerificationURL *string `json:"verification_url,omitempty"`
|
||||||
|
ExpiresIn *int64 `json:"expires_in,string,omitempty"`
|
||||||
|
Interval *int64 `json:"interval,string,omitempty"`
|
||||||
|
|
||||||
|
Message *string `json:"message"` // Azure specific
|
||||||
|
Resource string // store the following, stored when initiating, used when exchanging
|
||||||
|
OAuthConfig OAuthConfig
|
||||||
|
ClientID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenError is the object returned by the token exchange endpoint
|
||||||
|
// when something is amiss
|
||||||
|
type TokenError struct {
|
||||||
|
Error *string `json:"error,omitempty"`
|
||||||
|
ErrorCodes []int `json:"error_codes,omitempty"`
|
||||||
|
ErrorDescription *string `json:"error_description,omitempty"`
|
||||||
|
Timestamp *string `json:"timestamp,omitempty"`
|
||||||
|
TraceID *string `json:"trace_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeviceToken is the object return by the token exchange endpoint
|
||||||
|
// It can either look like a Token or an ErrorToken, so put both here
|
||||||
|
// and check for presence of "Error" to know if we are in error state
|
||||||
|
type deviceToken struct {
|
||||||
|
Token
|
||||||
|
TokenError
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitiateDeviceAuth initiates a device auth flow. It returns a DeviceCode
|
||||||
|
// that can be used with CheckForUserCompletion or WaitForUserCompletion.
|
||||||
|
func InitiateDeviceAuth(sender Sender, oauthConfig OAuthConfig, clientID, resource string) (*DeviceCode, error) {
|
||||||
|
v := url.Values{
|
||||||
|
"client_id": []string{clientID},
|
||||||
|
"resource": []string{resource},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := v.Encode()
|
||||||
|
body := ioutil.NopCloser(strings.NewReader(s))
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, oauthConfig.DeviceCodeEndpoint.String(), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeSendingFails, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
req.ContentLength = int64(len(s))
|
||||||
|
req.Header.Set(contentType, mimeTypeFormPost)
|
||||||
|
resp, err := sender.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeSendingFails, err.Error())
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
rb, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeHandlingFails, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeHandlingFails, errStatusNotOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(strings.Trim(string(rb), " ")) == 0 {
|
||||||
|
return nil, ErrDeviceCodeEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
var code DeviceCode
|
||||||
|
err = json.Unmarshal(rb, &code)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errCodeHandlingFails, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
code.ClientID = clientID
|
||||||
|
code.Resource = resource
|
||||||
|
code.OAuthConfig = oauthConfig
|
||||||
|
|
||||||
|
return &code, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckForUserCompletion takes a DeviceCode and checks with the Azure AD OAuth endpoint
|
||||||
|
// to see if the device flow has: been completed, timed out, or otherwise failed
|
||||||
|
func CheckForUserCompletion(sender Sender, code *DeviceCode) (*Token, error) {
|
||||||
|
v := url.Values{
|
||||||
|
"client_id": []string{code.ClientID},
|
||||||
|
"code": []string{*code.DeviceCode},
|
||||||
|
"grant_type": []string{OAuthGrantTypeDeviceCode},
|
||||||
|
"resource": []string{code.Resource},
|
||||||
|
}
|
||||||
|
|
||||||
|
s := v.Encode()
|
||||||
|
body := ioutil.NopCloser(strings.NewReader(s))
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, code.OAuthConfig.TokenEndpoint.String(), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenSendingFails, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
req.ContentLength = int64(len(s))
|
||||||
|
req.Header.Set(contentType, mimeTypeFormPost)
|
||||||
|
resp, err := sender.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenSendingFails, err.Error())
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
rb, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenHandlingFails, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK && len(strings.Trim(string(rb), " ")) == 0 {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenHandlingFails, errStatusNotOK)
|
||||||
|
}
|
||||||
|
if len(strings.Trim(string(rb), " ")) == 0 {
|
||||||
|
return nil, ErrOAuthTokenEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
var token deviceToken
|
||||||
|
err = json.Unmarshal(rb, &token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s %s: %s", logPrefix, errTokenHandlingFails, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.Error == nil {
|
||||||
|
return &token.Token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch *token.Error {
|
||||||
|
case "authorization_pending":
|
||||||
|
return nil, ErrDeviceAuthorizationPending
|
||||||
|
case "slow_down":
|
||||||
|
return nil, ErrDeviceSlowDown
|
||||||
|
case "access_denied":
|
||||||
|
return nil, ErrDeviceAccessDenied
|
||||||
|
case "code_expired":
|
||||||
|
return nil, ErrDeviceCodeExpired
|
||||||
|
default:
|
||||||
|
return nil, ErrDeviceGeneric
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForUserCompletion calls CheckForUserCompletion repeatedly until a token is granted or an error state occurs.
|
||||||
|
// This prevents the user from looping and checking against 'ErrDeviceAuthorizationPending'.
|
||||||
|
func WaitForUserCompletion(sender Sender, code *DeviceCode) (*Token, error) {
|
||||||
|
intervalDuration := time.Duration(*code.Interval) * time.Second
|
||||||
|
waitDuration := intervalDuration
|
||||||
|
|
||||||
|
for {
|
||||||
|
token, err := CheckForUserCompletion(sender, code)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch err {
|
||||||
|
case ErrDeviceSlowDown:
|
||||||
|
waitDuration += waitDuration
|
||||||
|
case ErrDeviceAuthorizationPending:
|
||||||
|
// noop
|
||||||
|
default: // everything else is "fatal" to us
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if waitDuration > (intervalDuration * 3) {
|
||||||
|
return nil, fmt.Errorf("%s Error waiting for user to complete device flow. Server told us to slow_down too much", logPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(waitDuration)
|
||||||
|
}
|
||||||
|
}
|
73
vendor/github.com/Azure/go-autorest/autorest/adal/persist.go
generated
vendored
Normal file
73
vendor/github.com/Azure/go-autorest/autorest/adal/persist.go
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package adal
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoadToken restores a Token object from a file located at 'path'.
|
||||||
|
func LoadToken(path string) (*Token, error) {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to open file (%s) while loading token: %v", path, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var token Token
|
||||||
|
|
||||||
|
dec := json.NewDecoder(file)
|
||||||
|
if err = dec.Decode(&token); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode contents of file (%s) into Token representation: %v", path, err)
|
||||||
|
}
|
||||||
|
return &token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveToken persists an oauth token at the given location on disk.
|
||||||
|
// It moves the new file into place so it can safely be used to replace an existing file
|
||||||
|
// that maybe accessed by multiple processes.
|
||||||
|
func SaveToken(path string, mode os.FileMode, token Token) error {
|
||||||
|
dir := filepath.Dir(path)
|
||||||
|
err := os.MkdirAll(dir, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create directory (%s) to store token in: %v", dir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newFile, err := ioutil.TempFile(dir, "token")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create the temp file to write the token: %v", err)
|
||||||
|
}
|
||||||
|
tempPath := newFile.Name()
|
||||||
|
|
||||||
|
if err := json.NewEncoder(newFile).Encode(token); err != nil {
|
||||||
|
return fmt.Errorf("failed to encode token to file (%s) while saving token: %v", tempPath, err)
|
||||||
|
}
|
||||||
|
if err := newFile.Close(); err != nil {
|
||||||
|
return fmt.Errorf("failed to close temp file %s: %v", tempPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atomic replace to avoid multi-writer file corruptions
|
||||||
|
if err := os.Rename(tempPath, path); err != nil {
|
||||||
|
return fmt.Errorf("failed to move temporary token to desired output location. src=%s dst=%s: %v", tempPath, path, err)
|
||||||
|
}
|
||||||
|
if err := os.Chmod(path, mode); err != nil {
|
||||||
|
return fmt.Errorf("failed to chmod the token file %s: %v", path, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
60
vendor/github.com/Azure/go-autorest/autorest/adal/sender.go
generated
vendored
Normal file
60
vendor/github.com/Azure/go-autorest/autorest/adal/sender.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package adal
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
contentType = "Content-Type"
|
||||||
|
mimeTypeFormPost = "application/x-www-form-urlencoded"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sender is the interface that wraps the Do method to send HTTP requests.
|
||||||
|
//
|
||||||
|
// The standard http.Client conforms to this interface.
|
||||||
|
type Sender interface {
|
||||||
|
Do(*http.Request) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SenderFunc is a method that implements the Sender interface.
|
||||||
|
type SenderFunc func(*http.Request) (*http.Response, error)
|
||||||
|
|
||||||
|
// Do implements the Sender interface on SenderFunc.
|
||||||
|
func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) {
|
||||||
|
return sf(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendDecorator takes and possibily decorates, by wrapping, a Sender. Decorators may affect the
|
||||||
|
// http.Request and pass it along or, first, pass the http.Request along then react to the
|
||||||
|
// http.Response result.
|
||||||
|
type SendDecorator func(Sender) Sender
|
||||||
|
|
||||||
|
// CreateSender creates, decorates, and returns, as a Sender, the default http.Client.
|
||||||
|
func CreateSender(decorators ...SendDecorator) Sender {
|
||||||
|
return DecorateSender(&http.Client{}, decorators...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecorateSender accepts a Sender and a, possibly empty, set of SendDecorators, which is applies to
|
||||||
|
// the Sender. Decorators are applied in the order received, but their affect upon the request
|
||||||
|
// depends on whether they are a pre-decorator (change the http.Request and then pass it along) or a
|
||||||
|
// post-decorator (pass the http.Request along and react to the results in http.Response).
|
||||||
|
func DecorateSender(s Sender, decorators ...SendDecorator) Sender {
|
||||||
|
for _, decorate := range decorators {
|
||||||
|
s = decorate(s)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
795
vendor/github.com/Azure/go-autorest/autorest/adal/token.go
generated
vendored
Normal file
795
vendor/github.com/Azure/go-autorest/autorest/adal/token.go
generated
vendored
Normal file
|
@ -0,0 +1,795 @@
|
||||||
|
package adal
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-autorest/autorest/date"
|
||||||
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultRefresh = 5 * time.Minute
|
||||||
|
|
||||||
|
// OAuthGrantTypeDeviceCode is the "grant_type" identifier used in device flow
|
||||||
|
OAuthGrantTypeDeviceCode = "device_code"
|
||||||
|
|
||||||
|
// OAuthGrantTypeClientCredentials is the "grant_type" identifier used in credential flows
|
||||||
|
OAuthGrantTypeClientCredentials = "client_credentials"
|
||||||
|
|
||||||
|
// OAuthGrantTypeUserPass is the "grant_type" identifier used in username and password auth flows
|
||||||
|
OAuthGrantTypeUserPass = "password"
|
||||||
|
|
||||||
|
// OAuthGrantTypeRefreshToken is the "grant_type" identifier used in refresh token flows
|
||||||
|
OAuthGrantTypeRefreshToken = "refresh_token"
|
||||||
|
|
||||||
|
// OAuthGrantTypeAuthorizationCode is the "grant_type" identifier used in authorization code flows
|
||||||
|
OAuthGrantTypeAuthorizationCode = "authorization_code"
|
||||||
|
|
||||||
|
// metadataHeader is the header required by MSI extension
|
||||||
|
metadataHeader = "Metadata"
|
||||||
|
|
||||||
|
// msiEndpoint is the well known endpoint for getting MSI authentications tokens
|
||||||
|
msiEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OAuthTokenProvider is an interface which should be implemented by an access token retriever
|
||||||
|
type OAuthTokenProvider interface {
|
||||||
|
OAuthToken() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenRefreshError is an interface used by errors returned during token refresh.
|
||||||
|
type TokenRefreshError interface {
|
||||||
|
error
|
||||||
|
Response() *http.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresher is an interface for token refresh functionality
|
||||||
|
type Refresher interface {
|
||||||
|
Refresh() error
|
||||||
|
RefreshExchange(resource string) error
|
||||||
|
EnsureFresh() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefresherWithContext is an interface for token refresh functionality
|
||||||
|
type RefresherWithContext interface {
|
||||||
|
RefreshWithContext(ctx context.Context) error
|
||||||
|
RefreshExchangeWithContext(ctx context.Context, resource string) error
|
||||||
|
EnsureFreshWithContext(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenRefreshCallback is the type representing callbacks that will be called after
|
||||||
|
// a successful token refresh
|
||||||
|
type TokenRefreshCallback func(Token) error
|
||||||
|
|
||||||
|
// Token encapsulates the access token used to authorize Azure requests.
|
||||||
|
type Token struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
|
||||||
|
ExpiresIn string `json:"expires_in"`
|
||||||
|
ExpiresOn string `json:"expires_on"`
|
||||||
|
NotBefore string `json:"not_before"`
|
||||||
|
|
||||||
|
Resource string `json:"resource"`
|
||||||
|
Type string `json:"token_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if the token object is zero-initialized.
|
||||||
|
func (t Token) IsZero() bool {
|
||||||
|
return t == Token{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expires returns the time.Time when the Token expires.
|
||||||
|
func (t Token) Expires() time.Time {
|
||||||
|
s, err := strconv.Atoi(t.ExpiresOn)
|
||||||
|
if err != nil {
|
||||||
|
s = -3600
|
||||||
|
}
|
||||||
|
|
||||||
|
expiration := date.NewUnixTimeFromSeconds(float64(s))
|
||||||
|
|
||||||
|
return time.Time(expiration).UTC()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsExpired returns true if the Token is expired, false otherwise.
|
||||||
|
func (t Token) IsExpired() bool {
|
||||||
|
return t.WillExpireIn(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WillExpireIn returns true if the Token will expire after the passed time.Duration interval
|
||||||
|
// from now, false otherwise.
|
||||||
|
func (t Token) WillExpireIn(d time.Duration) bool {
|
||||||
|
return !t.Expires().After(time.Now().Add(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
//OAuthToken return the current access token
|
||||||
|
func (t *Token) OAuthToken() string {
|
||||||
|
return t.AccessToken
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServicePrincipalNoSecret represents a secret type that contains no secret
|
||||||
|
// meaning it is not valid for fetching a fresh token. This is used by Manual
|
||||||
|
type ServicePrincipalNoSecret struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret
|
||||||
|
// It only returns an error for the ServicePrincipalNoSecret type
|
||||||
|
func (noSecret *ServicePrincipalNoSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||||
|
return fmt.Errorf("Manually created ServicePrincipalToken does not contain secret material to retrieve a new access token")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServicePrincipalSecret is an interface that allows various secret mechanism to fill the form
|
||||||
|
// that is submitted when acquiring an oAuth token.
|
||||||
|
type ServicePrincipalSecret interface {
|
||||||
|
SetAuthenticationValues(spt *ServicePrincipalToken, values *url.Values) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServicePrincipalTokenSecret implements ServicePrincipalSecret for client_secret type authorization.
|
||||||
|
type ServicePrincipalTokenSecret struct {
|
||||||
|
ClientSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||||
|
// It will populate the form submitted during oAuth Token Acquisition using the client_secret.
|
||||||
|
func (tokenSecret *ServicePrincipalTokenSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||||
|
v.Set("client_secret", tokenSecret.ClientSecret)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServicePrincipalCertificateSecret implements ServicePrincipalSecret for generic RSA cert auth with signed JWTs.
|
||||||
|
type ServicePrincipalCertificateSecret struct {
|
||||||
|
Certificate *x509.Certificate
|
||||||
|
PrivateKey *rsa.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServicePrincipalMSISecret implements ServicePrincipalSecret for machines running the MSI Extension.
|
||||||
|
type ServicePrincipalMSISecret struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServicePrincipalUsernamePasswordSecret implements ServicePrincipalSecret for username and password auth.
|
||||||
|
type ServicePrincipalUsernamePasswordSecret struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServicePrincipalAuthorizationCodeSecret implements ServicePrincipalSecret for authorization code auth.
|
||||||
|
type ServicePrincipalAuthorizationCodeSecret struct {
|
||||||
|
ClientSecret string
|
||||||
|
AuthorizationCode string
|
||||||
|
RedirectURI string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||||
|
func (secret *ServicePrincipalAuthorizationCodeSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||||
|
v.Set("code", secret.AuthorizationCode)
|
||||||
|
v.Set("client_secret", secret.ClientSecret)
|
||||||
|
v.Set("redirect_uri", secret.RedirectURI)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||||
|
func (secret *ServicePrincipalUsernamePasswordSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||||
|
v.Set("username", secret.Username)
|
||||||
|
v.Set("password", secret.Password)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||||
|
func (msiSecret *ServicePrincipalMSISecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignJwt returns the JWT signed with the certificate's private key.
|
||||||
|
func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalToken) (string, error) {
|
||||||
|
hasher := sha1.New()
|
||||||
|
_, err := hasher.Write(secret.Certificate.Raw)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
thumbprint := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
|
||||||
|
|
||||||
|
// The jti (JWT ID) claim provides a unique identifier for the JWT.
|
||||||
|
jti := make([]byte, 20)
|
||||||
|
_, err = rand.Read(jti)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := jwt.New(jwt.SigningMethodRS256)
|
||||||
|
token.Header["x5t"] = thumbprint
|
||||||
|
token.Claims = jwt.MapClaims{
|
||||||
|
"aud": spt.oauthConfig.TokenEndpoint.String(),
|
||||||
|
"iss": spt.clientID,
|
||||||
|
"sub": spt.clientID,
|
||||||
|
"jti": base64.URLEncoding.EncodeToString(jti),
|
||||||
|
"nbf": time.Now().Unix(),
|
||||||
|
"exp": time.Now().Add(time.Hour * 24).Unix(),
|
||||||
|
}
|
||||||
|
|
||||||
|
signedString, err := token.SignedString(secret.PrivateKey)
|
||||||
|
return signedString, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||||
|
// It will populate the form submitted during oAuth Token Acquisition using a JWT signed with a certificate.
|
||||||
|
func (secret *ServicePrincipalCertificateSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||||
|
jwt, err := secret.SignJwt(spt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Set("client_assertion", jwt)
|
||||||
|
v.Set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServicePrincipalToken encapsulates a Token created for a Service Principal.
|
||||||
|
type ServicePrincipalToken struct {
|
||||||
|
token Token
|
||||||
|
secret ServicePrincipalSecret
|
||||||
|
oauthConfig OAuthConfig
|
||||||
|
clientID string
|
||||||
|
resource string
|
||||||
|
autoRefresh bool
|
||||||
|
refreshLock *sync.RWMutex
|
||||||
|
refreshWithin time.Duration
|
||||||
|
sender Sender
|
||||||
|
|
||||||
|
refreshCallbacks []TokenRefreshCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateOAuthConfig(oac OAuthConfig) error {
|
||||||
|
if oac.IsZero() {
|
||||||
|
return fmt.Errorf("parameter 'oauthConfig' cannot be zero-initialized")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServicePrincipalTokenWithSecret create a ServicePrincipalToken using the supplied ServicePrincipalSecret implementation.
|
||||||
|
func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, resource string, secret ServicePrincipalSecret, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||||
|
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(id, "id"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(resource, "resource"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if secret == nil {
|
||||||
|
return nil, fmt.Errorf("parameter 'secret' cannot be nil")
|
||||||
|
}
|
||||||
|
spt := &ServicePrincipalToken{
|
||||||
|
oauthConfig: oauthConfig,
|
||||||
|
secret: secret,
|
||||||
|
clientID: id,
|
||||||
|
resource: resource,
|
||||||
|
autoRefresh: true,
|
||||||
|
refreshLock: &sync.RWMutex{},
|
||||||
|
refreshWithin: defaultRefresh,
|
||||||
|
sender: &http.Client{},
|
||||||
|
refreshCallbacks: callbacks,
|
||||||
|
}
|
||||||
|
return spt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServicePrincipalTokenFromManualToken creates a ServicePrincipalToken using the supplied token
|
||||||
|
func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID string, resource string, token Token, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||||
|
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(resource, "resource"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if token.IsZero() {
|
||||||
|
return nil, fmt.Errorf("parameter 'token' cannot be zero-initialized")
|
||||||
|
}
|
||||||
|
spt, err := NewServicePrincipalTokenWithSecret(
|
||||||
|
oauthConfig,
|
||||||
|
clientID,
|
||||||
|
resource,
|
||||||
|
&ServicePrincipalNoSecret{},
|
||||||
|
callbacks...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
spt.token = token
|
||||||
|
|
||||||
|
return spt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServicePrincipalToken creates a ServicePrincipalToken from the supplied Service Principal
|
||||||
|
// credentials scoped to the named resource.
|
||||||
|
func NewServicePrincipalToken(oauthConfig OAuthConfig, clientID string, secret string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||||
|
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(secret, "secret"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(resource, "resource"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewServicePrincipalTokenWithSecret(
|
||||||
|
oauthConfig,
|
||||||
|
clientID,
|
||||||
|
resource,
|
||||||
|
&ServicePrincipalTokenSecret{
|
||||||
|
ClientSecret: secret,
|
||||||
|
},
|
||||||
|
callbacks...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServicePrincipalTokenFromCertificate creates a ServicePrincipalToken from the supplied pkcs12 bytes.
|
||||||
|
func NewServicePrincipalTokenFromCertificate(oauthConfig OAuthConfig, clientID string, certificate *x509.Certificate, privateKey *rsa.PrivateKey, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||||
|
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(resource, "resource"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if certificate == nil {
|
||||||
|
return nil, fmt.Errorf("parameter 'certificate' cannot be nil")
|
||||||
|
}
|
||||||
|
if privateKey == nil {
|
||||||
|
return nil, fmt.Errorf("parameter 'privateKey' cannot be nil")
|
||||||
|
}
|
||||||
|
return NewServicePrincipalTokenWithSecret(
|
||||||
|
oauthConfig,
|
||||||
|
clientID,
|
||||||
|
resource,
|
||||||
|
&ServicePrincipalCertificateSecret{
|
||||||
|
PrivateKey: privateKey,
|
||||||
|
Certificate: certificate,
|
||||||
|
},
|
||||||
|
callbacks...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServicePrincipalTokenFromUsernamePassword creates a ServicePrincipalToken from the username and password.
|
||||||
|
func NewServicePrincipalTokenFromUsernamePassword(oauthConfig OAuthConfig, clientID string, username string, password string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||||
|
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(username, "username"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(password, "password"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(resource, "resource"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewServicePrincipalTokenWithSecret(
|
||||||
|
oauthConfig,
|
||||||
|
clientID,
|
||||||
|
resource,
|
||||||
|
&ServicePrincipalUsernamePasswordSecret{
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
},
|
||||||
|
callbacks...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServicePrincipalTokenFromAuthorizationCode creates a ServicePrincipalToken from the
|
||||||
|
func NewServicePrincipalTokenFromAuthorizationCode(oauthConfig OAuthConfig, clientID string, clientSecret string, authorizationCode string, redirectURI string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||||
|
|
||||||
|
if err := validateOAuthConfig(oauthConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(clientID, "clientID"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(clientSecret, "clientSecret"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(authorizationCode, "authorizationCode"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(redirectURI, "redirectURI"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(resource, "resource"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewServicePrincipalTokenWithSecret(
|
||||||
|
oauthConfig,
|
||||||
|
clientID,
|
||||||
|
resource,
|
||||||
|
&ServicePrincipalAuthorizationCodeSecret{
|
||||||
|
ClientSecret: clientSecret,
|
||||||
|
AuthorizationCode: authorizationCode,
|
||||||
|
RedirectURI: redirectURI,
|
||||||
|
},
|
||||||
|
callbacks...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMSIVMEndpoint gets the MSI endpoint on Virtual Machines.
|
||||||
|
func GetMSIVMEndpoint() (string, error) {
|
||||||
|
return msiEndpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension.
|
||||||
|
// It will use the system assigned identity when creating the token.
|
||||||
|
func NewServicePrincipalTokenFromMSI(msiEndpoint, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||||
|
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, callbacks...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServicePrincipalTokenFromMSIWithUserAssignedID creates a ServicePrincipalToken via the MSI VM Extension.
|
||||||
|
// It will use the specified user assigned identity when creating the token.
|
||||||
|
func NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, resource string, userAssignedID string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||||
|
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, &userAssignedID, callbacks...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedID *string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||||
|
if err := validateStringParam(msiEndpoint, "msiEndpoint"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateStringParam(resource, "resource"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if userAssignedID != nil {
|
||||||
|
if err := validateStringParam(*userAssignedID, "userAssignedID"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We set the oauth config token endpoint to be MSI's endpoint
|
||||||
|
msiEndpointURL, err := url.Parse(msiEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("resource", resource)
|
||||||
|
v.Set("api-version", "2018-02-01")
|
||||||
|
if userAssignedID != nil {
|
||||||
|
v.Set("client_id", *userAssignedID)
|
||||||
|
}
|
||||||
|
msiEndpointURL.RawQuery = v.Encode()
|
||||||
|
|
||||||
|
spt := &ServicePrincipalToken{
|
||||||
|
oauthConfig: OAuthConfig{
|
||||||
|
TokenEndpoint: *msiEndpointURL,
|
||||||
|
},
|
||||||
|
secret: &ServicePrincipalMSISecret{},
|
||||||
|
resource: resource,
|
||||||
|
autoRefresh: true,
|
||||||
|
refreshLock: &sync.RWMutex{},
|
||||||
|
refreshWithin: defaultRefresh,
|
||||||
|
sender: &http.Client{},
|
||||||
|
refreshCallbacks: callbacks,
|
||||||
|
}
|
||||||
|
|
||||||
|
if userAssignedID != nil {
|
||||||
|
spt.clientID = *userAssignedID
|
||||||
|
}
|
||||||
|
|
||||||
|
return spt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal type that implements TokenRefreshError
|
||||||
|
type tokenRefreshError struct {
|
||||||
|
message string
|
||||||
|
resp *http.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface which is part of the TokenRefreshError interface.
|
||||||
|
func (tre tokenRefreshError) Error() string {
|
||||||
|
return tre.message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response implements the TokenRefreshError interface, it returns the raw HTTP response from the refresh operation.
|
||||||
|
func (tre tokenRefreshError) Response() *http.Response {
|
||||||
|
return tre.resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTokenRefreshError(message string, resp *http.Response) TokenRefreshError {
|
||||||
|
return tokenRefreshError{message: message, resp: resp}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnsureFresh will refresh the token if it will expire within the refresh window (as set by
|
||||||
|
// RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use.
|
||||||
|
func (spt *ServicePrincipalToken) EnsureFresh() error {
|
||||||
|
return spt.EnsureFreshWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnsureFreshWithContext will refresh the token if it will expire within the refresh window (as set by
|
||||||
|
// RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use.
|
||||||
|
func (spt *ServicePrincipalToken) EnsureFreshWithContext(ctx context.Context) error {
|
||||||
|
if spt.autoRefresh && spt.token.WillExpireIn(spt.refreshWithin) {
|
||||||
|
// take the write lock then check to see if the token was already refreshed
|
||||||
|
spt.refreshLock.Lock()
|
||||||
|
defer spt.refreshLock.Unlock()
|
||||||
|
if spt.token.WillExpireIn(spt.refreshWithin) {
|
||||||
|
return spt.refreshInternal(ctx, spt.resource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvokeRefreshCallbacks calls any TokenRefreshCallbacks that were added to the SPT during initialization
|
||||||
|
func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error {
|
||||||
|
if spt.refreshCallbacks != nil {
|
||||||
|
for _, callback := range spt.refreshCallbacks {
|
||||||
|
err := callback(spt.token)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("adal: TokenRefreshCallback handler failed. Error = '%v'", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh obtains a fresh token for the Service Principal.
|
||||||
|
// This method is not safe for concurrent use and should be syncrhonized.
|
||||||
|
func (spt *ServicePrincipalToken) Refresh() error {
|
||||||
|
return spt.RefreshWithContext(context.Background())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshWithContext obtains a fresh token for the Service Principal.
|
||||||
|
// This method is not safe for concurrent use and should be syncrhonized.
|
||||||
|
func (spt *ServicePrincipalToken) RefreshWithContext(ctx context.Context) error {
|
||||||
|
spt.refreshLock.Lock()
|
||||||
|
defer spt.refreshLock.Unlock()
|
||||||
|
return spt.refreshInternal(ctx, spt.resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshExchange refreshes the token, but for a different resource.
|
||||||
|
// This method is not safe for concurrent use and should be syncrhonized.
|
||||||
|
func (spt *ServicePrincipalToken) RefreshExchange(resource string) error {
|
||||||
|
return spt.RefreshExchangeWithContext(context.Background(), resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshExchangeWithContext refreshes the token, but for a different resource.
|
||||||
|
// This method is not safe for concurrent use and should be syncrhonized.
|
||||||
|
func (spt *ServicePrincipalToken) RefreshExchangeWithContext(ctx context.Context, resource string) error {
|
||||||
|
spt.refreshLock.Lock()
|
||||||
|
defer spt.refreshLock.Unlock()
|
||||||
|
return spt.refreshInternal(ctx, resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (spt *ServicePrincipalToken) getGrantType() string {
|
||||||
|
switch spt.secret.(type) {
|
||||||
|
case *ServicePrincipalUsernamePasswordSecret:
|
||||||
|
return OAuthGrantTypeUserPass
|
||||||
|
case *ServicePrincipalAuthorizationCodeSecret:
|
||||||
|
return OAuthGrantTypeAuthorizationCode
|
||||||
|
default:
|
||||||
|
return OAuthGrantTypeClientCredentials
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isIMDS(u url.URL) bool {
|
||||||
|
imds, err := url.Parse(msiEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return u.Host == imds.Host && u.Path == imds.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource string) error {
|
||||||
|
req, err := http.NewRequest(http.MethodPost, spt.oauthConfig.TokenEndpoint.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("adal: Failed to build the refresh request. Error = '%v'", err)
|
||||||
|
}
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
if !isIMDS(spt.oauthConfig.TokenEndpoint) {
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("client_id", spt.clientID)
|
||||||
|
v.Set("resource", resource)
|
||||||
|
|
||||||
|
if spt.token.RefreshToken != "" {
|
||||||
|
v.Set("grant_type", OAuthGrantTypeRefreshToken)
|
||||||
|
v.Set("refresh_token", spt.token.RefreshToken)
|
||||||
|
} else {
|
||||||
|
v.Set("grant_type", spt.getGrantType())
|
||||||
|
err := spt.secret.SetAuthenticationValues(spt, &v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s := v.Encode()
|
||||||
|
body := ioutil.NopCloser(strings.NewReader(s))
|
||||||
|
req.ContentLength = int64(len(s))
|
||||||
|
req.Header.Set(contentType, mimeTypeFormPost)
|
||||||
|
req.Body = body
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := spt.secret.(*ServicePrincipalMSISecret); ok {
|
||||||
|
req.Method = http.MethodGet
|
||||||
|
req.Header.Set(metadataHeader, "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp *http.Response
|
||||||
|
if isIMDS(spt.oauthConfig.TokenEndpoint) {
|
||||||
|
resp, err = retry(spt.sender, req)
|
||||||
|
} else {
|
||||||
|
resp, err = spt.sender.Do(req)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return newTokenRefreshError(fmt.Sprintf("adal: Failed to execute the refresh request. Error = '%v'", err), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
rb, err := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
if err != nil {
|
||||||
|
return newTokenRefreshError(fmt.Sprintf("adal: Refresh request failed. Status Code = '%d'. Failed reading response body: %v", resp.StatusCode, err), resp)
|
||||||
|
}
|
||||||
|
return newTokenRefreshError(fmt.Sprintf("adal: Refresh request failed. Status Code = '%d'. Response body: %s", resp.StatusCode, string(rb)), resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for the following error cases don't return a TokenRefreshError. the operation succeeded
|
||||||
|
// but some transient failure happened during deserialization. by returning a generic error
|
||||||
|
// the retry logic will kick in (we don't retry on TokenRefreshError).
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("adal: Failed to read a new service principal token during refresh. Error = '%v'", err)
|
||||||
|
}
|
||||||
|
if len(strings.Trim(string(rb), " ")) == 0 {
|
||||||
|
return fmt.Errorf("adal: Empty service principal token received during refresh")
|
||||||
|
}
|
||||||
|
var token Token
|
||||||
|
err = json.Unmarshal(rb, &token)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("adal: Failed to unmarshal the service principal token during refresh. Error = '%v' JSON = '%s'", err, string(rb))
|
||||||
|
}
|
||||||
|
|
||||||
|
spt.token = token
|
||||||
|
|
||||||
|
return spt.InvokeRefreshCallbacks(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func retry(sender Sender, req *http.Request) (resp *http.Response, err error) {
|
||||||
|
retries := []int{
|
||||||
|
http.StatusRequestTimeout, // 408
|
||||||
|
http.StatusTooManyRequests, // 429
|
||||||
|
http.StatusInternalServerError, // 500
|
||||||
|
http.StatusBadGateway, // 502
|
||||||
|
http.StatusServiceUnavailable, // 503
|
||||||
|
http.StatusGatewayTimeout, // 504
|
||||||
|
}
|
||||||
|
// Extra retry status codes requered
|
||||||
|
retries = append(retries, http.StatusNotFound,
|
||||||
|
// all remaining 5xx
|
||||||
|
http.StatusNotImplemented,
|
||||||
|
http.StatusHTTPVersionNotSupported,
|
||||||
|
http.StatusVariantAlsoNegotiates,
|
||||||
|
http.StatusInsufficientStorage,
|
||||||
|
http.StatusLoopDetected,
|
||||||
|
http.StatusNotExtended,
|
||||||
|
http.StatusNetworkAuthenticationRequired)
|
||||||
|
|
||||||
|
attempt := 0
|
||||||
|
maxAttempts := 5
|
||||||
|
|
||||||
|
for attempt < maxAttempts {
|
||||||
|
resp, err = sender.Do(req)
|
||||||
|
// retry on temporary network errors, e.g. transient network failures.
|
||||||
|
if (err != nil && !isTemporaryNetworkError(err)) || (err != nil && resp == nil) || resp.StatusCode == http.StatusOK || !containsInt(retries, resp.StatusCode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !delay(resp, req.Context().Done()) {
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
attempt++
|
||||||
|
case <-req.Context().Done():
|
||||||
|
err = req.Context().Err()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTemporaryNetworkError(err error) bool {
|
||||||
|
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsInt(ints []int, n int) bool {
|
||||||
|
for _, i := range ints {
|
||||||
|
if i == n {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func delay(resp *http.Response, cancel <-chan struct{}) bool {
|
||||||
|
if resp == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After"))
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests && retryAfter > 0 {
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Duration(retryAfter) * time.Second):
|
||||||
|
return true
|
||||||
|
case <-cancel:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAutoRefresh enables or disables automatic refreshing of stale tokens.
|
||||||
|
func (spt *ServicePrincipalToken) SetAutoRefresh(autoRefresh bool) {
|
||||||
|
spt.autoRefresh = autoRefresh
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRefreshWithin sets the interval within which if the token will expire, EnsureFresh will
|
||||||
|
// refresh the token.
|
||||||
|
func (spt *ServicePrincipalToken) SetRefreshWithin(d time.Duration) {
|
||||||
|
spt.refreshWithin = d
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSender sets the http.Client used when obtaining the Service Principal token. An
|
||||||
|
// undecorated http.Client is used by default.
|
||||||
|
func (spt *ServicePrincipalToken) SetSender(s Sender) { spt.sender = s }
|
||||||
|
|
||||||
|
// OAuthToken implements the OAuthTokenProvider interface. It returns the current access token.
|
||||||
|
func (spt *ServicePrincipalToken) OAuthToken() string {
|
||||||
|
spt.refreshLock.RLock()
|
||||||
|
defer spt.refreshLock.RUnlock()
|
||||||
|
return spt.token.OAuthToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token returns a copy of the current token.
|
||||||
|
func (spt *ServicePrincipalToken) Token() Token {
|
||||||
|
spt.refreshLock.RLock()
|
||||||
|
defer spt.refreshLock.RUnlock()
|
||||||
|
return spt.token
|
||||||
|
}
|
259
vendor/github.com/Azure/go-autorest/autorest/authorization.go
generated
vendored
Normal file
259
vendor/github.com/Azure/go-autorest/autorest/authorization.go
generated
vendored
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Azure/go-autorest/autorest/adal"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
bearerChallengeHeader = "Www-Authenticate"
|
||||||
|
bearer = "Bearer"
|
||||||
|
tenantID = "tenantID"
|
||||||
|
apiKeyAuthorizerHeader = "Ocp-Apim-Subscription-Key"
|
||||||
|
bingAPISdkHeader = "X-BingApis-SDK-Client"
|
||||||
|
golangBingAPISdkHeaderValue = "Go-SDK"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Authorizer is the interface that provides a PrepareDecorator used to supply request
|
||||||
|
// authorization. Most often, the Authorizer decorator runs last so it has access to the full
|
||||||
|
// state of the formed HTTP request.
|
||||||
|
type Authorizer interface {
|
||||||
|
WithAuthorization() PrepareDecorator
|
||||||
|
}
|
||||||
|
|
||||||
|
// NullAuthorizer implements a default, "do nothing" Authorizer.
|
||||||
|
type NullAuthorizer struct{}
|
||||||
|
|
||||||
|
// WithAuthorization returns a PrepareDecorator that does nothing.
|
||||||
|
func (na NullAuthorizer) WithAuthorization() PrepareDecorator {
|
||||||
|
return WithNothing()
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIKeyAuthorizer implements API Key authorization.
|
||||||
|
type APIKeyAuthorizer struct {
|
||||||
|
headers map[string]interface{}
|
||||||
|
queryParameters map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAPIKeyAuthorizerWithHeaders creates an ApiKeyAuthorizer with headers.
|
||||||
|
func NewAPIKeyAuthorizerWithHeaders(headers map[string]interface{}) *APIKeyAuthorizer {
|
||||||
|
return NewAPIKeyAuthorizer(headers, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAPIKeyAuthorizerWithQueryParameters creates an ApiKeyAuthorizer with query parameters.
|
||||||
|
func NewAPIKeyAuthorizerWithQueryParameters(queryParameters map[string]interface{}) *APIKeyAuthorizer {
|
||||||
|
return NewAPIKeyAuthorizer(nil, queryParameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAPIKeyAuthorizer creates an ApiKeyAuthorizer with headers.
|
||||||
|
func NewAPIKeyAuthorizer(headers map[string]interface{}, queryParameters map[string]interface{}) *APIKeyAuthorizer {
|
||||||
|
return &APIKeyAuthorizer{headers: headers, queryParameters: queryParameters}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAuthorization returns a PrepareDecorator that adds an HTTP headers and Query Paramaters
|
||||||
|
func (aka *APIKeyAuthorizer) WithAuthorization() PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return DecoratePreparer(p, WithHeaders(aka.headers), WithQueryParameters(aka.queryParameters))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CognitiveServicesAuthorizer implements authorization for Cognitive Services.
|
||||||
|
type CognitiveServicesAuthorizer struct {
|
||||||
|
subscriptionKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCognitiveServicesAuthorizer is
|
||||||
|
func NewCognitiveServicesAuthorizer(subscriptionKey string) *CognitiveServicesAuthorizer {
|
||||||
|
return &CognitiveServicesAuthorizer{subscriptionKey: subscriptionKey}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAuthorization is
|
||||||
|
func (csa *CognitiveServicesAuthorizer) WithAuthorization() PrepareDecorator {
|
||||||
|
headers := make(map[string]interface{})
|
||||||
|
headers[apiKeyAuthorizerHeader] = csa.subscriptionKey
|
||||||
|
headers[bingAPISdkHeader] = golangBingAPISdkHeaderValue
|
||||||
|
|
||||||
|
return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
|
||||||
|
}
|
||||||
|
|
||||||
|
// BearerAuthorizer implements the bearer authorization
|
||||||
|
type BearerAuthorizer struct {
|
||||||
|
tokenProvider adal.OAuthTokenProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBearerAuthorizer crates a BearerAuthorizer using the given token provider
|
||||||
|
func NewBearerAuthorizer(tp adal.OAuthTokenProvider) *BearerAuthorizer {
|
||||||
|
return &BearerAuthorizer{tokenProvider: tp}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
|
||||||
|
// value is "Bearer " followed by the token.
|
||||||
|
//
|
||||||
|
// By default, the token will be automatically refreshed through the Refresher interface.
|
||||||
|
func (ba *BearerAuthorizer) WithAuthorization() PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
// the ordering is important here, prefer RefresherWithContext if available
|
||||||
|
if refresher, ok := ba.tokenProvider.(adal.RefresherWithContext); ok {
|
||||||
|
err = refresher.EnsureFreshWithContext(r.Context())
|
||||||
|
} else if refresher, ok := ba.tokenProvider.(adal.Refresher); ok {
|
||||||
|
err = refresher.EnsureFresh()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
var resp *http.Response
|
||||||
|
if tokError, ok := err.(adal.TokenRefreshError); ok {
|
||||||
|
resp = tokError.Response()
|
||||||
|
}
|
||||||
|
return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", resp,
|
||||||
|
"Failed to refresh the Token for request to %s", r.URL)
|
||||||
|
}
|
||||||
|
return Prepare(r, WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", ba.tokenProvider.OAuthToken())))
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BearerAuthorizerCallbackFunc is the authentication callback signature.
|
||||||
|
type BearerAuthorizerCallbackFunc func(tenantID, resource string) (*BearerAuthorizer, error)
|
||||||
|
|
||||||
|
// BearerAuthorizerCallback implements bearer authorization via a callback.
|
||||||
|
type BearerAuthorizerCallback struct {
|
||||||
|
sender Sender
|
||||||
|
callback BearerAuthorizerCallbackFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBearerAuthorizerCallback creates a bearer authorization callback. The callback
|
||||||
|
// is invoked when the HTTP request is submitted.
|
||||||
|
func NewBearerAuthorizerCallback(sender Sender, callback BearerAuthorizerCallbackFunc) *BearerAuthorizerCallback {
|
||||||
|
if sender == nil {
|
||||||
|
sender = &http.Client{}
|
||||||
|
}
|
||||||
|
return &BearerAuthorizerCallback{sender: sender, callback: callback}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose value
|
||||||
|
// is "Bearer " followed by the token. The BearerAuthorizer is obtained via a user-supplied callback.
|
||||||
|
//
|
||||||
|
// By default, the token will be automatically refreshed through the Refresher interface.
|
||||||
|
func (bacb *BearerAuthorizerCallback) WithAuthorization() PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
// make a copy of the request and remove the body as it's not
|
||||||
|
// required and avoids us having to create a copy of it.
|
||||||
|
rCopy := *r
|
||||||
|
removeRequestBody(&rCopy)
|
||||||
|
|
||||||
|
resp, err := bacb.sender.Do(&rCopy)
|
||||||
|
if err == nil && resp.StatusCode == 401 {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if hasBearerChallenge(resp) {
|
||||||
|
bc, err := newBearerChallenge(resp)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
if bacb.callback != nil {
|
||||||
|
ba, err := bacb.callback(bc.values[tenantID], bc.values["resource"])
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
return Prepare(r, ba.WithAuthorization())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the HTTP response contains a bearer challenge
|
||||||
|
func hasBearerChallenge(resp *http.Response) bool {
|
||||||
|
authHeader := resp.Header.Get(bearerChallengeHeader)
|
||||||
|
if len(authHeader) == 0 || strings.Index(authHeader, bearer) < 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type bearerChallenge struct {
|
||||||
|
values map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBearerChallenge(resp *http.Response) (bc bearerChallenge, err error) {
|
||||||
|
challenge := strings.TrimSpace(resp.Header.Get(bearerChallengeHeader))
|
||||||
|
trimmedChallenge := challenge[len(bearer)+1:]
|
||||||
|
|
||||||
|
// challenge is a set of key=value pairs that are comma delimited
|
||||||
|
pairs := strings.Split(trimmedChallenge, ",")
|
||||||
|
if len(pairs) < 1 {
|
||||||
|
err = fmt.Errorf("challenge '%s' contains no pairs", challenge)
|
||||||
|
return bc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bc.values = make(map[string]string)
|
||||||
|
for i := range pairs {
|
||||||
|
trimmedPair := strings.TrimSpace(pairs[i])
|
||||||
|
pair := strings.Split(trimmedPair, "=")
|
||||||
|
if len(pair) == 2 {
|
||||||
|
// remove the enclosing quotes
|
||||||
|
key := strings.Trim(pair[0], "\"")
|
||||||
|
value := strings.Trim(pair[1], "\"")
|
||||||
|
|
||||||
|
switch key {
|
||||||
|
case "authorization", "authorization_uri":
|
||||||
|
// strip the tenant ID from the authorization URL
|
||||||
|
asURL, err := url.Parse(value)
|
||||||
|
if err != nil {
|
||||||
|
return bc, err
|
||||||
|
}
|
||||||
|
bc.values[tenantID] = asURL.Path[1:]
|
||||||
|
default:
|
||||||
|
bc.values[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventGridKeyAuthorizer implements authorization for event grid using key authentication.
|
||||||
|
type EventGridKeyAuthorizer struct {
|
||||||
|
topicKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventGridKeyAuthorizer creates a new EventGridKeyAuthorizer
|
||||||
|
// with the specified topic key.
|
||||||
|
func NewEventGridKeyAuthorizer(topicKey string) EventGridKeyAuthorizer {
|
||||||
|
return EventGridKeyAuthorizer{topicKey: topicKey}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAuthorization returns a PrepareDecorator that adds the aeg-sas-key authentication header.
|
||||||
|
func (egta EventGridKeyAuthorizer) WithAuthorization() PrepareDecorator {
|
||||||
|
headers := map[string]interface{}{
|
||||||
|
"aeg-sas-key": egta.topicKey,
|
||||||
|
}
|
||||||
|
return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
|
||||||
|
}
|
150
vendor/github.com/Azure/go-autorest/autorest/autorest.go
generated
vendored
Normal file
150
vendor/github.com/Azure/go-autorest/autorest/autorest.go
generated
vendored
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
Package autorest implements an HTTP request pipeline suitable for use across multiple go-routines
|
||||||
|
and provides the shared routines relied on by AutoRest (see https://github.com/Azure/autorest/)
|
||||||
|
generated Go code.
|
||||||
|
|
||||||
|
The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending,
|
||||||
|
and Responding. A typical pattern is:
|
||||||
|
|
||||||
|
req, err := Prepare(&http.Request{},
|
||||||
|
token.WithAuthorization())
|
||||||
|
|
||||||
|
resp, err := Send(req,
|
||||||
|
WithLogging(logger),
|
||||||
|
DoErrorIfStatusCode(http.StatusInternalServerError),
|
||||||
|
DoCloseIfError(),
|
||||||
|
DoRetryForAttempts(5, time.Second))
|
||||||
|
|
||||||
|
err = Respond(resp,
|
||||||
|
ByDiscardingBody(),
|
||||||
|
ByClosing())
|
||||||
|
|
||||||
|
Each phase relies on decorators to modify and / or manage processing. Decorators may first modify
|
||||||
|
and then pass the data along, pass the data first and then modify the result, or wrap themselves
|
||||||
|
around passing the data (such as a logger might do). Decorators run in the order provided. For
|
||||||
|
example, the following:
|
||||||
|
|
||||||
|
req, err := Prepare(&http.Request{},
|
||||||
|
WithBaseURL("https://microsoft.com/"),
|
||||||
|
WithPath("a"),
|
||||||
|
WithPath("b"),
|
||||||
|
WithPath("c"))
|
||||||
|
|
||||||
|
will set the URL to:
|
||||||
|
|
||||||
|
https://microsoft.com/a/b/c
|
||||||
|
|
||||||
|
Preparers and Responders may be shared and re-used (assuming the underlying decorators support
|
||||||
|
sharing and re-use). Performant use is obtained by creating one or more Preparers and Responders
|
||||||
|
shared among multiple go-routines, and a single Sender shared among multiple sending go-routines,
|
||||||
|
all bound together by means of input / output channels.
|
||||||
|
|
||||||
|
Decorators hold their passed state within a closure (such as the path components in the example
|
||||||
|
above). Be careful to share Preparers and Responders only in a context where such held state
|
||||||
|
applies. For example, it may not make sense to share a Preparer that applies a query string from a
|
||||||
|
fixed set of values. Similarly, sharing a Responder that reads the response body into a passed
|
||||||
|
struct (e.g., ByUnmarshallingJson) is likely incorrect.
|
||||||
|
|
||||||
|
Lastly, the Swagger specification (https://swagger.io) that drives AutoRest
|
||||||
|
(https://github.com/Azure/autorest/) precisely defines two date forms: date and date-time. The
|
||||||
|
github.com/Azure/go-autorest/autorest/date package provides time.Time derivations to ensure
|
||||||
|
correct parsing and formatting.
|
||||||
|
|
||||||
|
Errors raised by autorest objects and methods will conform to the autorest.Error interface.
|
||||||
|
|
||||||
|
See the included examples for more detail. For details on the suggested use of this package by
|
||||||
|
generated clients, see the Client described below.
|
||||||
|
*/
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// HeaderLocation specifies the HTTP Location header.
|
||||||
|
HeaderLocation = "Location"
|
||||||
|
|
||||||
|
// HeaderRetryAfter specifies the HTTP Retry-After header.
|
||||||
|
HeaderRetryAfter = "Retry-After"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResponseHasStatusCode returns true if the status code in the HTTP Response is in the passed set
|
||||||
|
// and false otherwise.
|
||||||
|
func ResponseHasStatusCode(resp *http.Response, codes ...int) bool {
|
||||||
|
if resp == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return containsInt(codes, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLocation retrieves the URL from the Location header of the passed response.
|
||||||
|
func GetLocation(resp *http.Response) string {
|
||||||
|
return resp.Header.Get(HeaderLocation)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRetryAfter extracts the retry delay from the Retry-After header of the passed response. If
|
||||||
|
// the header is absent or is malformed, it will return the supplied default delay time.Duration.
|
||||||
|
func GetRetryAfter(resp *http.Response, defaultDelay time.Duration) time.Duration {
|
||||||
|
retry := resp.Header.Get(HeaderRetryAfter)
|
||||||
|
if retry == "" {
|
||||||
|
return defaultDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := time.ParseDuration(retry + "s")
|
||||||
|
if err != nil {
|
||||||
|
return defaultDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPollingRequest allocates and returns a new http.Request to poll for the passed response.
|
||||||
|
func NewPollingRequest(resp *http.Response, cancel <-chan struct{}) (*http.Request, error) {
|
||||||
|
location := GetLocation(resp)
|
||||||
|
if location == "" {
|
||||||
|
return nil, NewErrorWithResponse("autorest", "NewPollingRequest", resp, "Location header missing from response that requires polling")
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := Prepare(&http.Request{Cancel: cancel},
|
||||||
|
AsGet(),
|
||||||
|
WithBaseURL(location))
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewErrorWithError(err, "autorest", "NewPollingRequest", nil, "Failure creating poll request to %s", location)
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPollingRequestWithContext allocates and returns a new http.Request with the specified context to poll for the passed response.
|
||||||
|
func NewPollingRequestWithContext(ctx context.Context, resp *http.Response) (*http.Request, error) {
|
||||||
|
location := GetLocation(resp)
|
||||||
|
if location == "" {
|
||||||
|
return nil, NewErrorWithResponse("autorest", "NewPollingRequestWithContext", resp, "Location header missing from response that requires polling")
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := Prepare((&http.Request{}).WithContext(ctx),
|
||||||
|
AsGet(),
|
||||||
|
WithBaseURL(location))
|
||||||
|
if err != nil {
|
||||||
|
return nil, NewErrorWithError(err, "autorest", "NewPollingRequestWithContext", nil, "Failure creating poll request to %s", location)
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
910
vendor/github.com/Azure/go-autorest/autorest/azure/async.go
generated
vendored
Normal file
910
vendor/github.com/Azure/go-autorest/autorest/azure/async.go
generated
vendored
Normal file
|
@ -0,0 +1,910 @@
|
||||||
|
package azure
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
headerAsyncOperation = "Azure-AsyncOperation"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
operationInProgress string = "InProgress"
|
||||||
|
operationCanceled string = "Canceled"
|
||||||
|
operationFailed string = "Failed"
|
||||||
|
operationSucceeded string = "Succeeded"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pollingCodes = [...]int{http.StatusNoContent, http.StatusAccepted, http.StatusCreated, http.StatusOK}
|
||||||
|
|
||||||
|
// Future provides a mechanism to access the status and results of an asynchronous request.
|
||||||
|
// Since futures are stateful they should be passed by value to avoid race conditions.
|
||||||
|
type Future struct {
|
||||||
|
req *http.Request // legacy
|
||||||
|
pt pollingTracker
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFuture returns a new Future object initialized with the specified request.
|
||||||
|
// Deprecated: Please use NewFutureFromResponse instead.
|
||||||
|
func NewFuture(req *http.Request) Future {
|
||||||
|
return Future{req: req}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFutureFromResponse returns a new Future object initialized
|
||||||
|
// with the initial response from an asynchronous operation.
|
||||||
|
func NewFutureFromResponse(resp *http.Response) (Future, error) {
|
||||||
|
pt, err := createPollingTracker(resp)
|
||||||
|
if err != nil {
|
||||||
|
return Future{}, err
|
||||||
|
}
|
||||||
|
return Future{pt: pt}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response returns the last HTTP response.
|
||||||
|
func (f Future) Response() *http.Response {
|
||||||
|
if f.pt == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return f.pt.latestResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status returns the last status message of the operation.
|
||||||
|
func (f Future) Status() string {
|
||||||
|
if f.pt == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return f.pt.pollingStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PollingMethod returns the method used to monitor the status of the asynchronous operation.
|
||||||
|
func (f Future) PollingMethod() PollingMethodType {
|
||||||
|
if f.pt == nil {
|
||||||
|
return PollingUnknown
|
||||||
|
}
|
||||||
|
return f.pt.pollingMethod()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done queries the service to see if the operation has completed.
|
||||||
|
func (f *Future) Done(sender autorest.Sender) (bool, error) {
|
||||||
|
// support for legacy Future implementation
|
||||||
|
if f.req != nil {
|
||||||
|
resp, err := sender.Do(f.req)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
pt, err := createPollingTracker(resp)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
f.pt = pt
|
||||||
|
f.req = nil
|
||||||
|
}
|
||||||
|
// end legacy
|
||||||
|
if f.pt == nil {
|
||||||
|
return false, autorest.NewError("Future", "Done", "future is not initialized")
|
||||||
|
}
|
||||||
|
if f.pt.hasTerminated() {
|
||||||
|
return true, f.pt.pollingError()
|
||||||
|
}
|
||||||
|
if err := f.pt.pollForStatus(sender); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if err := f.pt.checkForErrors(); err != nil {
|
||||||
|
return f.pt.hasTerminated(), err
|
||||||
|
}
|
||||||
|
if err := f.pt.updatePollingState(f.pt.provisioningStateApplicable()); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if err := f.pt.updateHeaders(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return f.pt.hasTerminated(), f.pt.pollingError()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPollingDelay returns a duration the application should wait before checking
|
||||||
|
// the status of the asynchronous request and true; this value is returned from
|
||||||
|
// the service via the Retry-After response header. If the header wasn't returned
|
||||||
|
// then the function returns the zero-value time.Duration and false.
|
||||||
|
func (f Future) GetPollingDelay() (time.Duration, bool) {
|
||||||
|
if f.pt == nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
resp := f.pt.latestResponse()
|
||||||
|
if resp == nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
retry := resp.Header.Get(autorest.HeaderRetryAfter)
|
||||||
|
if retry == "" {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := time.ParseDuration(retry + "s")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return d, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForCompletion will return when one of the following conditions is met: the long
|
||||||
|
// running operation has completed, the provided context is cancelled, or the client's
|
||||||
|
// polling duration has been exceeded. It will retry failed polling attempts based on
|
||||||
|
// the retry value defined in the client up to the maximum retry attempts.
|
||||||
|
// Deprecated: Please use WaitForCompletionRef() instead.
|
||||||
|
func (f Future) WaitForCompletion(ctx context.Context, client autorest.Client) error {
|
||||||
|
return f.WaitForCompletionRef(ctx, client)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForCompletionRef will return when one of the following conditions is met: the long
|
||||||
|
// running operation has completed, the provided context is cancelled, or the client's
|
||||||
|
// polling duration has been exceeded. It will retry failed polling attempts based on
|
||||||
|
// the retry value defined in the client up to the maximum retry attempts.
|
||||||
|
func (f *Future) WaitForCompletionRef(ctx context.Context, client autorest.Client) error {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, client.PollingDuration)
|
||||||
|
defer cancel()
|
||||||
|
done, err := f.Done(client)
|
||||||
|
for attempts := 0; !done; done, err = f.Done(client) {
|
||||||
|
if attempts >= client.RetryAttempts {
|
||||||
|
return autorest.NewErrorWithError(err, "Future", "WaitForCompletion", f.pt.latestResponse(), "the number of retries has been exceeded")
|
||||||
|
}
|
||||||
|
// we want delayAttempt to be zero in the non-error case so
|
||||||
|
// that DelayForBackoff doesn't perform exponential back-off
|
||||||
|
var delayAttempt int
|
||||||
|
var delay time.Duration
|
||||||
|
if err == nil {
|
||||||
|
// check for Retry-After delay, if not present use the client's polling delay
|
||||||
|
var ok bool
|
||||||
|
delay, ok = f.GetPollingDelay()
|
||||||
|
if !ok {
|
||||||
|
delay = client.PollingDelay
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// there was an error polling for status so perform exponential
|
||||||
|
// back-off based on the number of attempts using the client's retry
|
||||||
|
// duration. update attempts after delayAttempt to avoid off-by-one.
|
||||||
|
delayAttempt = attempts
|
||||||
|
delay = client.RetryDuration
|
||||||
|
attempts++
|
||||||
|
}
|
||||||
|
// wait until the delay elapses or the context is cancelled
|
||||||
|
delayElapsed := autorest.DelayForBackoff(delay, delayAttempt, ctx.Done())
|
||||||
|
if !delayElapsed {
|
||||||
|
return autorest.NewErrorWithError(ctx.Err(), "Future", "WaitForCompletion", f.pt.latestResponse(), "context has been cancelled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
|
func (f Future) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(f.pt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (f *Future) UnmarshalJSON(data []byte) error {
|
||||||
|
// unmarshal into JSON object to determine the tracker type
|
||||||
|
obj := map[string]interface{}{}
|
||||||
|
err := json.Unmarshal(data, &obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if obj["method"] == nil {
|
||||||
|
return autorest.NewError("Future", "UnmarshalJSON", "missing 'method' property")
|
||||||
|
}
|
||||||
|
method := obj["method"].(string)
|
||||||
|
switch strings.ToUpper(method) {
|
||||||
|
case http.MethodDelete:
|
||||||
|
f.pt = &pollingTrackerDelete{}
|
||||||
|
case http.MethodPatch:
|
||||||
|
f.pt = &pollingTrackerPatch{}
|
||||||
|
case http.MethodPost:
|
||||||
|
f.pt = &pollingTrackerPost{}
|
||||||
|
case http.MethodPut:
|
||||||
|
f.pt = &pollingTrackerPut{}
|
||||||
|
default:
|
||||||
|
return autorest.NewError("Future", "UnmarshalJSON", "unsupoorted method '%s'", method)
|
||||||
|
}
|
||||||
|
// now unmarshal into the tracker
|
||||||
|
return json.Unmarshal(data, &f.pt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PollingURL returns the URL used for retrieving the status of the long-running operation.
|
||||||
|
func (f Future) PollingURL() string {
|
||||||
|
if f.pt == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return f.pt.pollingURL()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult should be called once polling has completed successfully.
|
||||||
|
// It makes the final GET call to retrieve the resultant payload.
|
||||||
|
func (f Future) GetResult(sender autorest.Sender) (*http.Response, error) {
|
||||||
|
if f.pt.finalGetURL() == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(http.MethodGet, f.pt.finalGetURL(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return sender.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
type pollingTracker interface {
|
||||||
|
// these methods can differ per tracker
|
||||||
|
|
||||||
|
// checks the response headers and status code to determine the polling mechanism
|
||||||
|
updateHeaders() error
|
||||||
|
|
||||||
|
// checks the response for tracker-specific error conditions
|
||||||
|
checkForErrors() error
|
||||||
|
|
||||||
|
// returns true if provisioning state should be checked
|
||||||
|
provisioningStateApplicable() bool
|
||||||
|
|
||||||
|
// methods common to all trackers
|
||||||
|
|
||||||
|
// initializes the tracker's internal state, call this when the tracker is created
|
||||||
|
initializeState() error
|
||||||
|
|
||||||
|
// makes an HTTP request to check the status of the LRO
|
||||||
|
pollForStatus(sender autorest.Sender) error
|
||||||
|
|
||||||
|
// updates internal tracker state, call this after each call to pollForStatus
|
||||||
|
updatePollingState(provStateApl bool) error
|
||||||
|
|
||||||
|
// returns the error response from the service, can be nil
|
||||||
|
pollingError() error
|
||||||
|
|
||||||
|
// returns the polling method being used
|
||||||
|
pollingMethod() PollingMethodType
|
||||||
|
|
||||||
|
// returns the state of the LRO as returned from the service
|
||||||
|
pollingStatus() string
|
||||||
|
|
||||||
|
// returns the URL used for polling status
|
||||||
|
pollingURL() string
|
||||||
|
|
||||||
|
// returns the URL used for the final GET to retrieve the resource
|
||||||
|
finalGetURL() string
|
||||||
|
|
||||||
|
// returns true if the LRO is in a terminal state
|
||||||
|
hasTerminated() bool
|
||||||
|
|
||||||
|
// returns true if the LRO is in a failed terminal state
|
||||||
|
hasFailed() bool
|
||||||
|
|
||||||
|
// returns true if the LRO is in a successful terminal state
|
||||||
|
hasSucceeded() bool
|
||||||
|
|
||||||
|
// returns the cached HTTP response after a call to pollForStatus(), can be nil
|
||||||
|
latestResponse() *http.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
type pollingTrackerBase struct {
|
||||||
|
// resp is the last response, either from the submission of the LRO or from polling
|
||||||
|
resp *http.Response
|
||||||
|
|
||||||
|
// method is the HTTP verb, this is needed for deserialization
|
||||||
|
Method string `json:"method"`
|
||||||
|
|
||||||
|
// rawBody is the raw JSON response body
|
||||||
|
rawBody map[string]interface{}
|
||||||
|
|
||||||
|
// denotes if polling is using async-operation or location header
|
||||||
|
Pm PollingMethodType `json:"pollingMethod"`
|
||||||
|
|
||||||
|
// the URL to poll for status
|
||||||
|
URI string `json:"pollingURI"`
|
||||||
|
|
||||||
|
// the state of the LRO as returned from the service
|
||||||
|
State string `json:"lroState"`
|
||||||
|
|
||||||
|
// the URL to GET for the final result
|
||||||
|
FinalGetURI string `json:"resultURI"`
|
||||||
|
|
||||||
|
// used to hold an error object returned from the service
|
||||||
|
Err *ServiceError `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *pollingTrackerBase) initializeState() error {
|
||||||
|
// determine the initial polling state based on response body and/or HTTP status
|
||||||
|
// code. this is applicable to the initial LRO response, not polling responses!
|
||||||
|
pt.Method = pt.resp.Request.Method
|
||||||
|
if err := pt.updateRawBody(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch pt.resp.StatusCode {
|
||||||
|
case http.StatusOK:
|
||||||
|
if ps := pt.getProvisioningState(); ps != nil {
|
||||||
|
pt.State = *ps
|
||||||
|
} else {
|
||||||
|
pt.State = operationSucceeded
|
||||||
|
}
|
||||||
|
case http.StatusCreated:
|
||||||
|
if ps := pt.getProvisioningState(); ps != nil {
|
||||||
|
pt.State = *ps
|
||||||
|
} else {
|
||||||
|
pt.State = operationInProgress
|
||||||
|
}
|
||||||
|
case http.StatusAccepted:
|
||||||
|
pt.State = operationInProgress
|
||||||
|
case http.StatusNoContent:
|
||||||
|
pt.State = operationSucceeded
|
||||||
|
default:
|
||||||
|
pt.State = operationFailed
|
||||||
|
pt.updateErrorFromResponse()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) getProvisioningState() *string {
|
||||||
|
if pt.rawBody != nil && pt.rawBody["properties"] != nil {
|
||||||
|
p := pt.rawBody["properties"].(map[string]interface{})
|
||||||
|
if ps := p["provisioningState"]; ps != nil {
|
||||||
|
s := ps.(string)
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *pollingTrackerBase) updateRawBody() error {
|
||||||
|
pt.rawBody = map[string]interface{}{}
|
||||||
|
if pt.resp.ContentLength != 0 {
|
||||||
|
defer pt.resp.Body.Close()
|
||||||
|
b, err := ioutil.ReadAll(pt.resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return autorest.NewErrorWithError(err, "pollingTrackerBase", "updateRawBody", nil, "failed to read response body")
|
||||||
|
}
|
||||||
|
// put the body back so it's available to other callers
|
||||||
|
pt.resp.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||||
|
if err = json.Unmarshal(b, &pt.rawBody); err != nil {
|
||||||
|
return autorest.NewErrorWithError(err, "pollingTrackerBase", "updateRawBody", nil, "failed to unmarshal response body")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *pollingTrackerBase) pollForStatus(sender autorest.Sender) error {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, pt.URI, nil)
|
||||||
|
if err != nil {
|
||||||
|
return autorest.NewErrorWithError(err, "pollingTrackerBase", "pollForStatus", nil, "failed to create HTTP request")
|
||||||
|
}
|
||||||
|
// attach the context from the original request if available (it will be absent for deserialized futures)
|
||||||
|
if pt.resp != nil {
|
||||||
|
req = req.WithContext(pt.resp.Request.Context())
|
||||||
|
}
|
||||||
|
pt.resp, err = sender.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return autorest.NewErrorWithError(err, "pollingTrackerBase", "pollForStatus", nil, "failed to send HTTP request")
|
||||||
|
}
|
||||||
|
if autorest.ResponseHasStatusCode(pt.resp, pollingCodes[:]...) {
|
||||||
|
// reset the service error on success case
|
||||||
|
pt.Err = nil
|
||||||
|
err = pt.updateRawBody()
|
||||||
|
} else {
|
||||||
|
// check response body for error content
|
||||||
|
pt.updateErrorFromResponse()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempts to unmarshal a ServiceError type from the response body.
|
||||||
|
// if that fails then make a best attempt at creating something meaningful.
|
||||||
|
func (pt *pollingTrackerBase) updateErrorFromResponse() {
|
||||||
|
var err error
|
||||||
|
if pt.resp.ContentLength != 0 {
|
||||||
|
type respErr struct {
|
||||||
|
ServiceError *ServiceError `json:"error"`
|
||||||
|
}
|
||||||
|
re := respErr{}
|
||||||
|
defer pt.resp.Body.Close()
|
||||||
|
var b []byte
|
||||||
|
b, err = ioutil.ReadAll(pt.resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
goto Default
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(b, &re); err != nil {
|
||||||
|
goto Default
|
||||||
|
}
|
||||||
|
// unmarshalling the error didn't yield anything, try unwrapped error
|
||||||
|
if re.ServiceError == nil {
|
||||||
|
err = json.Unmarshal(b, &re.ServiceError)
|
||||||
|
if err != nil {
|
||||||
|
goto Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if re.ServiceError != nil {
|
||||||
|
pt.Err = re.ServiceError
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Default:
|
||||||
|
se := &ServiceError{
|
||||||
|
Code: fmt.Sprintf("HTTP status code %v", pt.resp.StatusCode),
|
||||||
|
Message: pt.resp.Status,
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
se.InnerError = make(map[string]interface{})
|
||||||
|
se.InnerError["unmarshalError"] = err.Error()
|
||||||
|
}
|
||||||
|
pt.Err = se
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *pollingTrackerBase) updatePollingState(provStateApl bool) error {
|
||||||
|
if pt.Pm == PollingAsyncOperation && pt.rawBody["status"] != nil {
|
||||||
|
pt.State = pt.rawBody["status"].(string)
|
||||||
|
} else {
|
||||||
|
if pt.resp.StatusCode == http.StatusAccepted {
|
||||||
|
pt.State = operationInProgress
|
||||||
|
} else if provStateApl {
|
||||||
|
if ps := pt.getProvisioningState(); ps != nil {
|
||||||
|
pt.State = *ps
|
||||||
|
} else {
|
||||||
|
pt.State = operationSucceeded
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return autorest.NewError("pollingTrackerBase", "updatePollingState", "the response from the async operation has an invalid status code")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if the operation has failed update the error state
|
||||||
|
if pt.hasFailed() {
|
||||||
|
pt.updateErrorFromResponse()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) pollingError() error {
|
||||||
|
if pt.Err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return pt.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) pollingMethod() PollingMethodType {
|
||||||
|
return pt.Pm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) pollingStatus() string {
|
||||||
|
return pt.State
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) pollingURL() string {
|
||||||
|
return pt.URI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) finalGetURL() string {
|
||||||
|
return pt.FinalGetURI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) hasTerminated() bool {
|
||||||
|
return strings.EqualFold(pt.State, operationCanceled) || strings.EqualFold(pt.State, operationFailed) || strings.EqualFold(pt.State, operationSucceeded)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) hasFailed() bool {
|
||||||
|
return strings.EqualFold(pt.State, operationCanceled) || strings.EqualFold(pt.State, operationFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) hasSucceeded() bool {
|
||||||
|
return strings.EqualFold(pt.State, operationSucceeded)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerBase) latestResponse() *http.Response {
|
||||||
|
return pt.resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// error checking common to all trackers
|
||||||
|
func (pt pollingTrackerBase) baseCheckForErrors() error {
|
||||||
|
// for Azure-AsyncOperations the response body cannot be nil or empty
|
||||||
|
if pt.Pm == PollingAsyncOperation {
|
||||||
|
if pt.resp.Body == nil || pt.resp.ContentLength == 0 {
|
||||||
|
return autorest.NewError("pollingTrackerBase", "baseCheckForErrors", "for Azure-AsyncOperation response body cannot be nil")
|
||||||
|
}
|
||||||
|
if pt.rawBody["status"] == nil {
|
||||||
|
return autorest.NewError("pollingTrackerBase", "baseCheckForErrors", "missing status property in Azure-AsyncOperation response body")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE
|
||||||
|
|
||||||
|
type pollingTrackerDelete struct {
|
||||||
|
pollingTrackerBase
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *pollingTrackerDelete) updateHeaders() error {
|
||||||
|
// for 201 the Location header is required
|
||||||
|
if pt.resp.StatusCode == http.StatusCreated {
|
||||||
|
if lh, err := getURLFromLocationHeader(pt.resp); err != nil {
|
||||||
|
return err
|
||||||
|
} else if lh == "" {
|
||||||
|
return autorest.NewError("pollingTrackerDelete", "updateHeaders", "missing Location header in 201 response")
|
||||||
|
} else {
|
||||||
|
pt.URI = lh
|
||||||
|
}
|
||||||
|
pt.Pm = PollingLocation
|
||||||
|
pt.FinalGetURI = pt.URI
|
||||||
|
}
|
||||||
|
// for 202 prefer the Azure-AsyncOperation header but fall back to Location if necessary
|
||||||
|
if pt.resp.StatusCode == http.StatusAccepted {
|
||||||
|
ao, err := getURLFromAsyncOpHeader(pt.resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if ao != "" {
|
||||||
|
pt.URI = ao
|
||||||
|
pt.Pm = PollingAsyncOperation
|
||||||
|
}
|
||||||
|
// if the Location header is invalid and we already have a polling URL
|
||||||
|
// then we don't care if the Location header URL is malformed.
|
||||||
|
if lh, err := getURLFromLocationHeader(pt.resp); err != nil && pt.URI == "" {
|
||||||
|
return err
|
||||||
|
} else if lh != "" {
|
||||||
|
if ao == "" {
|
||||||
|
pt.URI = lh
|
||||||
|
pt.Pm = PollingLocation
|
||||||
|
}
|
||||||
|
// when both headers are returned we use the value in the Location header for the final GET
|
||||||
|
pt.FinalGetURI = lh
|
||||||
|
}
|
||||||
|
// make sure a polling URL was found
|
||||||
|
if pt.URI == "" {
|
||||||
|
return autorest.NewError("pollingTrackerPost", "updateHeaders", "didn't get any suitable polling URLs in 202 response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerDelete) checkForErrors() error {
|
||||||
|
return pt.baseCheckForErrors()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerDelete) provisioningStateApplicable() bool {
|
||||||
|
return pt.resp.StatusCode == http.StatusOK || pt.resp.StatusCode == http.StatusNoContent
|
||||||
|
}
|
||||||
|
|
||||||
|
// PATCH
|
||||||
|
|
||||||
|
type pollingTrackerPatch struct {
|
||||||
|
pollingTrackerBase
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *pollingTrackerPatch) updateHeaders() error {
|
||||||
|
// by default we can use the original URL for polling and final GET
|
||||||
|
if pt.URI == "" {
|
||||||
|
pt.URI = pt.resp.Request.URL.String()
|
||||||
|
}
|
||||||
|
if pt.FinalGetURI == "" {
|
||||||
|
pt.FinalGetURI = pt.resp.Request.URL.String()
|
||||||
|
}
|
||||||
|
if pt.Pm == PollingUnknown {
|
||||||
|
pt.Pm = PollingRequestURI
|
||||||
|
}
|
||||||
|
// for 201 it's permissible for no headers to be returned
|
||||||
|
if pt.resp.StatusCode == http.StatusCreated {
|
||||||
|
if ao, err := getURLFromAsyncOpHeader(pt.resp); err != nil {
|
||||||
|
return err
|
||||||
|
} else if ao != "" {
|
||||||
|
pt.URI = ao
|
||||||
|
pt.Pm = PollingAsyncOperation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for 202 prefer the Azure-AsyncOperation header but fall back to Location if necessary
|
||||||
|
// note the absense of the "final GET" mechanism for PATCH
|
||||||
|
if pt.resp.StatusCode == http.StatusAccepted {
|
||||||
|
ao, err := getURLFromAsyncOpHeader(pt.resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if ao != "" {
|
||||||
|
pt.URI = ao
|
||||||
|
pt.Pm = PollingAsyncOperation
|
||||||
|
}
|
||||||
|
if ao == "" {
|
||||||
|
if lh, err := getURLFromLocationHeader(pt.resp); err != nil {
|
||||||
|
return err
|
||||||
|
} else if lh == "" {
|
||||||
|
return autorest.NewError("pollingTrackerPatch", "updateHeaders", "didn't get any suitable polling URLs in 202 response")
|
||||||
|
} else {
|
||||||
|
pt.URI = lh
|
||||||
|
pt.Pm = PollingLocation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerPatch) checkForErrors() error {
|
||||||
|
return pt.baseCheckForErrors()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerPatch) provisioningStateApplicable() bool {
|
||||||
|
return pt.resp.StatusCode == http.StatusOK || pt.resp.StatusCode == http.StatusCreated
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST
|
||||||
|
|
||||||
|
type pollingTrackerPost struct {
|
||||||
|
pollingTrackerBase
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *pollingTrackerPost) updateHeaders() error {
|
||||||
|
// 201 requires Location header
|
||||||
|
if pt.resp.StatusCode == http.StatusCreated {
|
||||||
|
if lh, err := getURLFromLocationHeader(pt.resp); err != nil {
|
||||||
|
return err
|
||||||
|
} else if lh == "" {
|
||||||
|
return autorest.NewError("pollingTrackerPost", "updateHeaders", "missing Location header in 201 response")
|
||||||
|
} else {
|
||||||
|
pt.URI = lh
|
||||||
|
pt.FinalGetURI = lh
|
||||||
|
pt.Pm = PollingLocation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for 202 prefer the Azure-AsyncOperation header but fall back to Location if necessary
|
||||||
|
if pt.resp.StatusCode == http.StatusAccepted {
|
||||||
|
ao, err := getURLFromAsyncOpHeader(pt.resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if ao != "" {
|
||||||
|
pt.URI = ao
|
||||||
|
pt.Pm = PollingAsyncOperation
|
||||||
|
}
|
||||||
|
// if the Location header is invalid and we already have a polling URL
|
||||||
|
// then we don't care if the Location header URL is malformed.
|
||||||
|
if lh, err := getURLFromLocationHeader(pt.resp); err != nil && pt.URI == "" {
|
||||||
|
return err
|
||||||
|
} else if lh != "" {
|
||||||
|
if ao == "" {
|
||||||
|
pt.URI = lh
|
||||||
|
pt.Pm = PollingLocation
|
||||||
|
}
|
||||||
|
// when both headers are returned we use the value in the Location header for the final GET
|
||||||
|
pt.FinalGetURI = lh
|
||||||
|
}
|
||||||
|
// make sure a polling URL was found
|
||||||
|
if pt.URI == "" {
|
||||||
|
return autorest.NewError("pollingTrackerPost", "updateHeaders", "didn't get any suitable polling URLs in 202 response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerPost) checkForErrors() error {
|
||||||
|
return pt.baseCheckForErrors()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerPost) provisioningStateApplicable() bool {
|
||||||
|
return pt.resp.StatusCode == http.StatusOK || pt.resp.StatusCode == http.StatusNoContent
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT
|
||||||
|
|
||||||
|
type pollingTrackerPut struct {
|
||||||
|
pollingTrackerBase
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *pollingTrackerPut) updateHeaders() error {
|
||||||
|
// by default we can use the original URL for polling and final GET
|
||||||
|
if pt.URI == "" {
|
||||||
|
pt.URI = pt.resp.Request.URL.String()
|
||||||
|
}
|
||||||
|
if pt.FinalGetURI == "" {
|
||||||
|
pt.FinalGetURI = pt.resp.Request.URL.String()
|
||||||
|
}
|
||||||
|
if pt.Pm == PollingUnknown {
|
||||||
|
pt.Pm = PollingRequestURI
|
||||||
|
}
|
||||||
|
// for 201 it's permissible for no headers to be returned
|
||||||
|
if pt.resp.StatusCode == http.StatusCreated {
|
||||||
|
if ao, err := getURLFromAsyncOpHeader(pt.resp); err != nil {
|
||||||
|
return err
|
||||||
|
} else if ao != "" {
|
||||||
|
pt.URI = ao
|
||||||
|
pt.Pm = PollingAsyncOperation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for 202 prefer the Azure-AsyncOperation header but fall back to Location if necessary
|
||||||
|
if pt.resp.StatusCode == http.StatusAccepted {
|
||||||
|
ao, err := getURLFromAsyncOpHeader(pt.resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if ao != "" {
|
||||||
|
pt.URI = ao
|
||||||
|
pt.Pm = PollingAsyncOperation
|
||||||
|
}
|
||||||
|
// if the Location header is invalid and we already have a polling URL
|
||||||
|
// then we don't care if the Location header URL is malformed.
|
||||||
|
if lh, err := getURLFromLocationHeader(pt.resp); err != nil && pt.URI == "" {
|
||||||
|
return err
|
||||||
|
} else if lh != "" {
|
||||||
|
if ao == "" {
|
||||||
|
pt.URI = lh
|
||||||
|
pt.Pm = PollingLocation
|
||||||
|
}
|
||||||
|
// when both headers are returned we use the value in the Location header for the final GET
|
||||||
|
pt.FinalGetURI = lh
|
||||||
|
}
|
||||||
|
// make sure a polling URL was found
|
||||||
|
if pt.URI == "" {
|
||||||
|
return autorest.NewError("pollingTrackerPut", "updateHeaders", "didn't get any suitable polling URLs in 202 response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerPut) checkForErrors() error {
|
||||||
|
err := pt.baseCheckForErrors()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// if there are no LRO headers then the body cannot be empty
|
||||||
|
ao, err := getURLFromAsyncOpHeader(pt.resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
lh, err := getURLFromLocationHeader(pt.resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if ao == "" && lh == "" && len(pt.rawBody) == 0 {
|
||||||
|
return autorest.NewError("pollingTrackerPut", "checkForErrors", "the response did not contain a body")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt pollingTrackerPut) provisioningStateApplicable() bool {
|
||||||
|
return pt.resp.StatusCode == http.StatusOK || pt.resp.StatusCode == http.StatusCreated
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a polling tracker based on the verb of the original request
|
||||||
|
func createPollingTracker(resp *http.Response) (pollingTracker, error) {
|
||||||
|
var pt pollingTracker
|
||||||
|
switch strings.ToUpper(resp.Request.Method) {
|
||||||
|
case http.MethodDelete:
|
||||||
|
pt = &pollingTrackerDelete{pollingTrackerBase: pollingTrackerBase{resp: resp}}
|
||||||
|
case http.MethodPatch:
|
||||||
|
pt = &pollingTrackerPatch{pollingTrackerBase: pollingTrackerBase{resp: resp}}
|
||||||
|
case http.MethodPost:
|
||||||
|
pt = &pollingTrackerPost{pollingTrackerBase: pollingTrackerBase{resp: resp}}
|
||||||
|
case http.MethodPut:
|
||||||
|
pt = &pollingTrackerPut{pollingTrackerBase: pollingTrackerBase{resp: resp}}
|
||||||
|
default:
|
||||||
|
return nil, autorest.NewError("azure", "createPollingTracker", "unsupported HTTP method %s", resp.Request.Method)
|
||||||
|
}
|
||||||
|
if err := pt.initializeState(); err != nil {
|
||||||
|
return pt, err
|
||||||
|
}
|
||||||
|
// this initializes the polling header values, we do this during creation in case the
|
||||||
|
// initial response send us invalid values; this way the API call will return a non-nil
|
||||||
|
// error (not doing this means the error shows up in Future.Done)
|
||||||
|
return pt, pt.updateHeaders()
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets the polling URL from the Azure-AsyncOperation header.
|
||||||
|
// ensures the URL is well-formed and absolute.
|
||||||
|
func getURLFromAsyncOpHeader(resp *http.Response) (string, error) {
|
||||||
|
s := resp.Header.Get(http.CanonicalHeaderKey(headerAsyncOperation))
|
||||||
|
if s == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if !isValidURL(s) {
|
||||||
|
return "", autorest.NewError("azure", "getURLFromAsyncOpHeader", "invalid polling URL '%s'", s)
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets the polling URL from the Location header.
|
||||||
|
// ensures the URL is well-formed and absolute.
|
||||||
|
func getURLFromLocationHeader(resp *http.Response) (string, error) {
|
||||||
|
s := resp.Header.Get(http.CanonicalHeaderKey(autorest.HeaderLocation))
|
||||||
|
if s == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if !isValidURL(s) {
|
||||||
|
return "", autorest.NewError("azure", "getURLFromLocationHeader", "invalid polling URL '%s'", s)
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify that the URL is valid and absolute
|
||||||
|
func isValidURL(s string) bool {
|
||||||
|
u, err := url.Parse(s)
|
||||||
|
return err == nil && u.IsAbs()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoPollForAsynchronous returns a SendDecorator that polls if the http.Response is for an Azure
|
||||||
|
// long-running operation. It will delay between requests for the duration specified in the
|
||||||
|
// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled via
|
||||||
|
// the context associated with the http.Request.
|
||||||
|
// Deprecated: Prefer using Futures to allow for non-blocking async operations.
|
||||||
|
func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator {
|
||||||
|
return func(s autorest.Sender) autorest.Sender {
|
||||||
|
return autorest.SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
|
resp, err := s.Do(r)
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
if !autorest.ResponseHasStatusCode(resp, pollingCodes[:]...) {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
future, err := NewFutureFromResponse(resp)
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
// retry until either the LRO completes or we receive an error
|
||||||
|
var done bool
|
||||||
|
for done, err = future.Done(s); !done && err == nil; done, err = future.Done(s) {
|
||||||
|
// check for Retry-After delay, if not present use the specified polling delay
|
||||||
|
if pd, ok := future.GetPollingDelay(); ok {
|
||||||
|
delay = pd
|
||||||
|
}
|
||||||
|
// wait until the delay elapses or the context is cancelled
|
||||||
|
if delayElapsed := autorest.DelayForBackoff(delay, 0, r.Context().Done()); !delayElapsed {
|
||||||
|
return future.Response(),
|
||||||
|
autorest.NewErrorWithError(r.Context().Err(), "azure", "DoPollForAsynchronous", future.Response(), "context has been cancelled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return future.Response(), err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PollingMethodType defines a type used for enumerating polling mechanisms.
|
||||||
|
type PollingMethodType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PollingAsyncOperation indicates the polling method uses the Azure-AsyncOperation header.
|
||||||
|
PollingAsyncOperation PollingMethodType = "AsyncOperation"
|
||||||
|
|
||||||
|
// PollingLocation indicates the polling method uses the Location header.
|
||||||
|
PollingLocation PollingMethodType = "Location"
|
||||||
|
|
||||||
|
// PollingRequestURI indicates the polling method uses the original request URI.
|
||||||
|
PollingRequestURI PollingMethodType = "RequestURI"
|
||||||
|
|
||||||
|
// PollingUnknown indicates an unknown polling method and is the default value.
|
||||||
|
PollingUnknown PollingMethodType = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
// AsyncOpIncompleteError is the type that's returned from a future that has not completed.
|
||||||
|
type AsyncOpIncompleteError struct {
|
||||||
|
// FutureType is the name of the type composed of a azure.Future.
|
||||||
|
FutureType string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns an error message including the originating type name of the error.
|
||||||
|
func (e AsyncOpIncompleteError) Error() string {
|
||||||
|
return fmt.Sprintf("%s: asynchronous operation has not completed", e.FutureType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAsyncOpIncompleteError creates a new AsyncOpIncompleteError with the specified parameters.
|
||||||
|
func NewAsyncOpIncompleteError(futureType string) AsyncOpIncompleteError {
|
||||||
|
return AsyncOpIncompleteError{
|
||||||
|
FutureType: futureType,
|
||||||
|
}
|
||||||
|
}
|
301
vendor/github.com/Azure/go-autorest/autorest/azure/azure.go
generated
vendored
Normal file
301
vendor/github.com/Azure/go-autorest/autorest/azure/azure.go
generated
vendored
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
// Package azure provides Azure-specific implementations used with AutoRest.
|
||||||
|
// See the included examples for more detail.
|
||||||
|
package azure
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// HeaderClientID is the Azure extension header to set a user-specified request ID.
|
||||||
|
HeaderClientID = "x-ms-client-request-id"
|
||||||
|
|
||||||
|
// HeaderReturnClientID is the Azure extension header to set if the user-specified request ID
|
||||||
|
// should be included in the response.
|
||||||
|
HeaderReturnClientID = "x-ms-return-client-request-id"
|
||||||
|
|
||||||
|
// HeaderRequestID is the Azure extension header of the service generated request ID returned
|
||||||
|
// in the response.
|
||||||
|
HeaderRequestID = "x-ms-request-id"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServiceError encapsulates the error response from an Azure service.
|
||||||
|
// It adhears to the OData v4 specification for error responses.
|
||||||
|
type ServiceError struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Target *string `json:"target"`
|
||||||
|
Details []map[string]interface{} `json:"details"`
|
||||||
|
InnerError map[string]interface{} `json:"innererror"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (se ServiceError) Error() string {
|
||||||
|
result := fmt.Sprintf("Code=%q Message=%q", se.Code, se.Message)
|
||||||
|
|
||||||
|
if se.Target != nil {
|
||||||
|
result += fmt.Sprintf(" Target=%q", *se.Target)
|
||||||
|
}
|
||||||
|
|
||||||
|
if se.Details != nil {
|
||||||
|
d, err := json.Marshal(se.Details)
|
||||||
|
if err != nil {
|
||||||
|
result += fmt.Sprintf(" Details=%v", se.Details)
|
||||||
|
}
|
||||||
|
result += fmt.Sprintf(" Details=%v", string(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
if se.InnerError != nil {
|
||||||
|
d, err := json.Marshal(se.InnerError)
|
||||||
|
if err != nil {
|
||||||
|
result += fmt.Sprintf(" InnerError=%v", se.InnerError)
|
||||||
|
}
|
||||||
|
result += fmt.Sprintf(" InnerError=%v", string(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface for the ServiceError type.
|
||||||
|
func (se *ServiceError) UnmarshalJSON(b []byte) error {
|
||||||
|
// per the OData v4 spec the details field must be an array of JSON objects.
|
||||||
|
// unfortunately not all services adhear to the spec and just return a single
|
||||||
|
// object instead of an array with one object. so we have to perform some
|
||||||
|
// shenanigans to accommodate both cases.
|
||||||
|
// http://docs.oasis-open.org/odata/odata-json-format/v4.0/os/odata-json-format-v4.0-os.html#_Toc372793091
|
||||||
|
|
||||||
|
type serviceError1 struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Target *string `json:"target"`
|
||||||
|
Details []map[string]interface{} `json:"details"`
|
||||||
|
InnerError map[string]interface{} `json:"innererror"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type serviceError2 struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Target *string `json:"target"`
|
||||||
|
Details map[string]interface{} `json:"details"`
|
||||||
|
InnerError map[string]interface{} `json:"innererror"`
|
||||||
|
}
|
||||||
|
|
||||||
|
se1 := serviceError1{}
|
||||||
|
err := json.Unmarshal(b, &se1)
|
||||||
|
if err == nil {
|
||||||
|
se.populate(se1.Code, se1.Message, se1.Target, se1.Details, se1.InnerError)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
se2 := serviceError2{}
|
||||||
|
err = json.Unmarshal(b, &se2)
|
||||||
|
if err == nil {
|
||||||
|
se.populate(se2.Code, se2.Message, se2.Target, nil, se2.InnerError)
|
||||||
|
se.Details = append(se.Details, se2.Details)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (se *ServiceError) populate(code, message string, target *string, details []map[string]interface{}, inner map[string]interface{}) {
|
||||||
|
se.Code = code
|
||||||
|
se.Message = message
|
||||||
|
se.Target = target
|
||||||
|
se.Details = details
|
||||||
|
se.InnerError = inner
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestError describes an error response returned by Azure service.
|
||||||
|
type RequestError struct {
|
||||||
|
autorest.DetailedError
|
||||||
|
|
||||||
|
// The error returned by the Azure service.
|
||||||
|
ServiceError *ServiceError `json:"error"`
|
||||||
|
|
||||||
|
// The request id (from the x-ms-request-id-header) of the request.
|
||||||
|
RequestID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns a human-friendly error message from service error.
|
||||||
|
func (e RequestError) Error() string {
|
||||||
|
return fmt.Sprintf("autorest/azure: Service returned an error. Status=%v %v",
|
||||||
|
e.StatusCode, e.ServiceError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAzureError returns true if the passed error is an Azure Service error; false otherwise.
|
||||||
|
func IsAzureError(e error) bool {
|
||||||
|
_, ok := e.(*RequestError)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resource contains details about an Azure resource.
|
||||||
|
type Resource struct {
|
||||||
|
SubscriptionID string
|
||||||
|
ResourceGroup string
|
||||||
|
Provider string
|
||||||
|
ResourceType string
|
||||||
|
ResourceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseResourceID parses a resource ID into a ResourceDetails struct.
|
||||||
|
// See https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-resource#return-value-4.
|
||||||
|
func ParseResourceID(resourceID string) (Resource, error) {
|
||||||
|
|
||||||
|
const resourceIDPatternText = `(?i)subscriptions/(.+)/resourceGroups/(.+)/providers/(.+?)/(.+?)/(.+)`
|
||||||
|
resourceIDPattern := regexp.MustCompile(resourceIDPatternText)
|
||||||
|
match := resourceIDPattern.FindStringSubmatch(resourceID)
|
||||||
|
|
||||||
|
if len(match) == 0 {
|
||||||
|
return Resource{}, fmt.Errorf("parsing failed for %s. Invalid resource Id format", resourceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
v := strings.Split(match[5], "/")
|
||||||
|
resourceName := v[len(v)-1]
|
||||||
|
|
||||||
|
result := Resource{
|
||||||
|
SubscriptionID: match[1],
|
||||||
|
ResourceGroup: match[2],
|
||||||
|
Provider: match[3],
|
||||||
|
ResourceType: match[4],
|
||||||
|
ResourceName: resourceName,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrorWithError creates a new Error conforming object from the
|
||||||
|
// passed packageType, method, statusCode of the given resp (UndefinedStatusCode
|
||||||
|
// if resp is nil), message, and original error. message is treated as a format
|
||||||
|
// string to which the optional args apply.
|
||||||
|
func NewErrorWithError(original error, packageType string, method string, resp *http.Response, message string, args ...interface{}) RequestError {
|
||||||
|
if v, ok := original.(*RequestError); ok {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
|
||||||
|
statusCode := autorest.UndefinedStatusCode
|
||||||
|
if resp != nil {
|
||||||
|
statusCode = resp.StatusCode
|
||||||
|
}
|
||||||
|
return RequestError{
|
||||||
|
DetailedError: autorest.DetailedError{
|
||||||
|
Original: original,
|
||||||
|
PackageType: packageType,
|
||||||
|
Method: method,
|
||||||
|
StatusCode: statusCode,
|
||||||
|
Message: fmt.Sprintf(message, args...),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithReturningClientID returns a PrepareDecorator that adds an HTTP extension header of
|
||||||
|
// x-ms-client-request-id whose value is the passed, undecorated UUID (e.g.,
|
||||||
|
// "0F39878C-5F76-4DB8-A25D-61D2C193C3CA"). It also sets the x-ms-return-client-request-id
|
||||||
|
// header to true such that UUID accompanies the http.Response.
|
||||||
|
func WithReturningClientID(uuid string) autorest.PrepareDecorator {
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
WithClientID(uuid),
|
||||||
|
WithReturnClientID(true))
|
||||||
|
|
||||||
|
return func(p autorest.Preparer) autorest.Preparer {
|
||||||
|
return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
return preparer.Prepare(r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithClientID returns a PrepareDecorator that adds an HTTP extension header of
|
||||||
|
// x-ms-client-request-id whose value is passed, undecorated UUID (e.g.,
|
||||||
|
// "0F39878C-5F76-4DB8-A25D-61D2C193C3CA").
|
||||||
|
func WithClientID(uuid string) autorest.PrepareDecorator {
|
||||||
|
return autorest.WithHeader(HeaderClientID, uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithReturnClientID returns a PrepareDecorator that adds an HTTP extension header of
|
||||||
|
// x-ms-return-client-request-id whose boolean value indicates if the value of the
|
||||||
|
// x-ms-client-request-id header should be included in the http.Response.
|
||||||
|
func WithReturnClientID(b bool) autorest.PrepareDecorator {
|
||||||
|
return autorest.WithHeader(HeaderReturnClientID, strconv.FormatBool(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractClientID extracts the client identifier from the x-ms-client-request-id header set on the
|
||||||
|
// http.Request sent to the service (and returned in the http.Response)
|
||||||
|
func ExtractClientID(resp *http.Response) string {
|
||||||
|
return autorest.ExtractHeaderValue(HeaderClientID, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractRequestID extracts the Azure server generated request identifier from the
|
||||||
|
// x-ms-request-id header.
|
||||||
|
func ExtractRequestID(resp *http.Response) string {
|
||||||
|
return autorest.ExtractHeaderValue(HeaderRequestID, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithErrorUnlessStatusCode returns a RespondDecorator that emits an
|
||||||
|
// azure.RequestError by reading the response body unless the response HTTP status code
|
||||||
|
// is among the set passed.
|
||||||
|
//
|
||||||
|
// If there is a chance service may return responses other than the Azure error
|
||||||
|
// format and the response cannot be parsed into an error, a decoding error will
|
||||||
|
// be returned containing the response body. In any case, the Responder will
|
||||||
|
// return an error if the status code is not satisfied.
|
||||||
|
//
|
||||||
|
// If this Responder returns an error, the response body will be replaced with
|
||||||
|
// an in-memory reader, which needs no further closing.
|
||||||
|
func WithErrorUnlessStatusCode(codes ...int) autorest.RespondDecorator {
|
||||||
|
return func(r autorest.Responder) autorest.Responder {
|
||||||
|
return autorest.ResponderFunc(func(resp *http.Response) error {
|
||||||
|
err := r.Respond(resp)
|
||||||
|
if err == nil && !autorest.ResponseHasStatusCode(resp, codes...) {
|
||||||
|
var e RequestError
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Copy and replace the Body in case it does not contain an error object.
|
||||||
|
// This will leave the Body available to the caller.
|
||||||
|
b, decodeErr := autorest.CopyAndDecode(autorest.EncodedAsJSON, resp.Body, &e)
|
||||||
|
resp.Body = ioutil.NopCloser(&b)
|
||||||
|
if decodeErr != nil {
|
||||||
|
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b.String(), decodeErr)
|
||||||
|
} else if e.ServiceError == nil {
|
||||||
|
// Check if error is unwrapped ServiceError
|
||||||
|
if err := json.Unmarshal(b.Bytes(), &e.ServiceError); err != nil || e.ServiceError.Message == "" {
|
||||||
|
e.ServiceError = &ServiceError{
|
||||||
|
Code: "Unknown",
|
||||||
|
Message: "Unknown service error",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.RequestID = ExtractRequestID(resp)
|
||||||
|
if e.StatusCode == nil {
|
||||||
|
e.StatusCode = resp.StatusCode
|
||||||
|
}
|
||||||
|
err = &e
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
191
vendor/github.com/Azure/go-autorest/autorest/azure/environments.go
generated
vendored
Normal file
191
vendor/github.com/Azure/go-autorest/autorest/azure/environments.go
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
package azure
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EnvironmentFilepathName captures the name of the environment variable containing the path to the file
|
||||||
|
// to be used while populating the Azure Environment.
|
||||||
|
const EnvironmentFilepathName = "AZURE_ENVIRONMENT_FILEPATH"
|
||||||
|
|
||||||
|
var environments = map[string]Environment{
|
||||||
|
"AZURECHINACLOUD": ChinaCloud,
|
||||||
|
"AZUREGERMANCLOUD": GermanCloud,
|
||||||
|
"AZUREPUBLICCLOUD": PublicCloud,
|
||||||
|
"AZUREUSGOVERNMENTCLOUD": USGovernmentCloud,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Environment represents a set of endpoints for each of Azure's Clouds.
|
||||||
|
type Environment struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ManagementPortalURL string `json:"managementPortalURL"`
|
||||||
|
PublishSettingsURL string `json:"publishSettingsURL"`
|
||||||
|
ServiceManagementEndpoint string `json:"serviceManagementEndpoint"`
|
||||||
|
ResourceManagerEndpoint string `json:"resourceManagerEndpoint"`
|
||||||
|
ActiveDirectoryEndpoint string `json:"activeDirectoryEndpoint"`
|
||||||
|
GalleryEndpoint string `json:"galleryEndpoint"`
|
||||||
|
KeyVaultEndpoint string `json:"keyVaultEndpoint"`
|
||||||
|
GraphEndpoint string `json:"graphEndpoint"`
|
||||||
|
ServiceBusEndpoint string `json:"serviceBusEndpoint"`
|
||||||
|
BatchManagementEndpoint string `json:"batchManagementEndpoint"`
|
||||||
|
StorageEndpointSuffix string `json:"storageEndpointSuffix"`
|
||||||
|
SQLDatabaseDNSSuffix string `json:"sqlDatabaseDNSSuffix"`
|
||||||
|
TrafficManagerDNSSuffix string `json:"trafficManagerDNSSuffix"`
|
||||||
|
KeyVaultDNSSuffix string `json:"keyVaultDNSSuffix"`
|
||||||
|
ServiceBusEndpointSuffix string `json:"serviceBusEndpointSuffix"`
|
||||||
|
ServiceManagementVMDNSSuffix string `json:"serviceManagementVMDNSSuffix"`
|
||||||
|
ResourceManagerVMDNSSuffix string `json:"resourceManagerVMDNSSuffix"`
|
||||||
|
ContainerRegistryDNSSuffix string `json:"containerRegistryDNSSuffix"`
|
||||||
|
TokenAudience string `json:"tokenAudience"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// PublicCloud is the default public Azure cloud environment
|
||||||
|
PublicCloud = Environment{
|
||||||
|
Name: "AzurePublicCloud",
|
||||||
|
ManagementPortalURL: "https://manage.windowsazure.com/",
|
||||||
|
PublishSettingsURL: "https://manage.windowsazure.com/publishsettings/index",
|
||||||
|
ServiceManagementEndpoint: "https://management.core.windows.net/",
|
||||||
|
ResourceManagerEndpoint: "https://management.azure.com/",
|
||||||
|
ActiveDirectoryEndpoint: "https://login.microsoftonline.com/",
|
||||||
|
GalleryEndpoint: "https://gallery.azure.com/",
|
||||||
|
KeyVaultEndpoint: "https://vault.azure.net/",
|
||||||
|
GraphEndpoint: "https://graph.windows.net/",
|
||||||
|
ServiceBusEndpoint: "https://servicebus.windows.net/",
|
||||||
|
BatchManagementEndpoint: "https://batch.core.windows.net/",
|
||||||
|
StorageEndpointSuffix: "core.windows.net",
|
||||||
|
SQLDatabaseDNSSuffix: "database.windows.net",
|
||||||
|
TrafficManagerDNSSuffix: "trafficmanager.net",
|
||||||
|
KeyVaultDNSSuffix: "vault.azure.net",
|
||||||
|
ServiceBusEndpointSuffix: "servicebus.windows.net",
|
||||||
|
ServiceManagementVMDNSSuffix: "cloudapp.net",
|
||||||
|
ResourceManagerVMDNSSuffix: "cloudapp.azure.com",
|
||||||
|
ContainerRegistryDNSSuffix: "azurecr.io",
|
||||||
|
TokenAudience: "https://management.azure.com/",
|
||||||
|
}
|
||||||
|
|
||||||
|
// USGovernmentCloud is the cloud environment for the US Government
|
||||||
|
USGovernmentCloud = Environment{
|
||||||
|
Name: "AzureUSGovernmentCloud",
|
||||||
|
ManagementPortalURL: "https://manage.windowsazure.us/",
|
||||||
|
PublishSettingsURL: "https://manage.windowsazure.us/publishsettings/index",
|
||||||
|
ServiceManagementEndpoint: "https://management.core.usgovcloudapi.net/",
|
||||||
|
ResourceManagerEndpoint: "https://management.usgovcloudapi.net/",
|
||||||
|
ActiveDirectoryEndpoint: "https://login.microsoftonline.us/",
|
||||||
|
GalleryEndpoint: "https://gallery.usgovcloudapi.net/",
|
||||||
|
KeyVaultEndpoint: "https://vault.usgovcloudapi.net/",
|
||||||
|
GraphEndpoint: "https://graph.windows.net/",
|
||||||
|
ServiceBusEndpoint: "https://servicebus.usgovcloudapi.net/",
|
||||||
|
BatchManagementEndpoint: "https://batch.core.usgovcloudapi.net/",
|
||||||
|
StorageEndpointSuffix: "core.usgovcloudapi.net",
|
||||||
|
SQLDatabaseDNSSuffix: "database.usgovcloudapi.net",
|
||||||
|
TrafficManagerDNSSuffix: "usgovtrafficmanager.net",
|
||||||
|
KeyVaultDNSSuffix: "vault.usgovcloudapi.net",
|
||||||
|
ServiceBusEndpointSuffix: "servicebus.usgovcloudapi.net",
|
||||||
|
ServiceManagementVMDNSSuffix: "usgovcloudapp.net",
|
||||||
|
ResourceManagerVMDNSSuffix: "cloudapp.windowsazure.us",
|
||||||
|
ContainerRegistryDNSSuffix: "azurecr.io",
|
||||||
|
TokenAudience: "https://management.usgovcloudapi.net/",
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChinaCloud is the cloud environment operated in China
|
||||||
|
ChinaCloud = Environment{
|
||||||
|
Name: "AzureChinaCloud",
|
||||||
|
ManagementPortalURL: "https://manage.chinacloudapi.com/",
|
||||||
|
PublishSettingsURL: "https://manage.chinacloudapi.com/publishsettings/index",
|
||||||
|
ServiceManagementEndpoint: "https://management.core.chinacloudapi.cn/",
|
||||||
|
ResourceManagerEndpoint: "https://management.chinacloudapi.cn/",
|
||||||
|
ActiveDirectoryEndpoint: "https://login.chinacloudapi.cn/",
|
||||||
|
GalleryEndpoint: "https://gallery.chinacloudapi.cn/",
|
||||||
|
KeyVaultEndpoint: "https://vault.azure.cn/",
|
||||||
|
GraphEndpoint: "https://graph.chinacloudapi.cn/",
|
||||||
|
ServiceBusEndpoint: "https://servicebus.chinacloudapi.cn/",
|
||||||
|
BatchManagementEndpoint: "https://batch.chinacloudapi.cn/",
|
||||||
|
StorageEndpointSuffix: "core.chinacloudapi.cn",
|
||||||
|
SQLDatabaseDNSSuffix: "database.chinacloudapi.cn",
|
||||||
|
TrafficManagerDNSSuffix: "trafficmanager.cn",
|
||||||
|
KeyVaultDNSSuffix: "vault.azure.cn",
|
||||||
|
ServiceBusEndpointSuffix: "servicebus.chinacloudapi.cn",
|
||||||
|
ServiceManagementVMDNSSuffix: "chinacloudapp.cn",
|
||||||
|
ResourceManagerVMDNSSuffix: "cloudapp.azure.cn",
|
||||||
|
ContainerRegistryDNSSuffix: "azurecr.io",
|
||||||
|
TokenAudience: "https://management.chinacloudapi.cn/",
|
||||||
|
}
|
||||||
|
|
||||||
|
// GermanCloud is the cloud environment operated in Germany
|
||||||
|
GermanCloud = Environment{
|
||||||
|
Name: "AzureGermanCloud",
|
||||||
|
ManagementPortalURL: "http://portal.microsoftazure.de/",
|
||||||
|
PublishSettingsURL: "https://manage.microsoftazure.de/publishsettings/index",
|
||||||
|
ServiceManagementEndpoint: "https://management.core.cloudapi.de/",
|
||||||
|
ResourceManagerEndpoint: "https://management.microsoftazure.de/",
|
||||||
|
ActiveDirectoryEndpoint: "https://login.microsoftonline.de/",
|
||||||
|
GalleryEndpoint: "https://gallery.cloudapi.de/",
|
||||||
|
KeyVaultEndpoint: "https://vault.microsoftazure.de/",
|
||||||
|
GraphEndpoint: "https://graph.cloudapi.de/",
|
||||||
|
ServiceBusEndpoint: "https://servicebus.cloudapi.de/",
|
||||||
|
BatchManagementEndpoint: "https://batch.cloudapi.de/",
|
||||||
|
StorageEndpointSuffix: "core.cloudapi.de",
|
||||||
|
SQLDatabaseDNSSuffix: "database.cloudapi.de",
|
||||||
|
TrafficManagerDNSSuffix: "azuretrafficmanager.de",
|
||||||
|
KeyVaultDNSSuffix: "vault.microsoftazure.de",
|
||||||
|
ServiceBusEndpointSuffix: "servicebus.cloudapi.de",
|
||||||
|
ServiceManagementVMDNSSuffix: "azurecloudapp.de",
|
||||||
|
ResourceManagerVMDNSSuffix: "cloudapp.microsoftazure.de",
|
||||||
|
ContainerRegistryDNSSuffix: "azurecr.io",
|
||||||
|
TokenAudience: "https://management.microsoftazure.de/",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// EnvironmentFromName returns an Environment based on the common name specified.
|
||||||
|
func EnvironmentFromName(name string) (Environment, error) {
|
||||||
|
// IMPORTANT
|
||||||
|
// As per @radhikagupta5:
|
||||||
|
// This is technical debt, fundamentally here because Kubernetes is not currently accepting
|
||||||
|
// contributions to the providers. Once that is an option, the provider should be updated to
|
||||||
|
// directly call `EnvironmentFromFile`. Until then, we rely on dispatching Azure Stack environment creation
|
||||||
|
// from this method based on the name that is provided to us.
|
||||||
|
if strings.EqualFold(name, "AZURESTACKCLOUD") {
|
||||||
|
return EnvironmentFromFile(os.Getenv(EnvironmentFilepathName))
|
||||||
|
}
|
||||||
|
|
||||||
|
name = strings.ToUpper(name)
|
||||||
|
env, ok := environments[name]
|
||||||
|
if !ok {
|
||||||
|
return env, fmt.Errorf("autorest/azure: There is no cloud environment matching the name %q", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return env, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvironmentFromFile loads an Environment from a configuration file available on disk.
|
||||||
|
// This function is particularly useful in the Hybrid Cloud model, where one must define their own
|
||||||
|
// endpoints.
|
||||||
|
func EnvironmentFromFile(location string) (unmarshaled Environment, err error) {
|
||||||
|
fileContents, err := ioutil.ReadFile(location)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(fileContents, &unmarshaled)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
245
vendor/github.com/Azure/go-autorest/autorest/azure/metadata_environment.go
generated
vendored
Normal file
245
vendor/github.com/Azure/go-autorest/autorest/azure/metadata_environment.go
generated
vendored
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
package azure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
type audience []string
|
||||||
|
|
||||||
|
type authentication struct {
|
||||||
|
LoginEndpoint string `json:"loginEndpoint"`
|
||||||
|
Audiences audience `json:"audiences"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type environmentMetadataInfo struct {
|
||||||
|
GalleryEndpoint string `json:"galleryEndpoint"`
|
||||||
|
GraphEndpoint string `json:"graphEndpoint"`
|
||||||
|
PortalEndpoint string `json:"portalEndpoint"`
|
||||||
|
Authentication authentication `json:"authentication"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvironmentProperty represent property names that clients can override
|
||||||
|
type EnvironmentProperty string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// EnvironmentName ...
|
||||||
|
EnvironmentName EnvironmentProperty = "name"
|
||||||
|
// EnvironmentManagementPortalURL ..
|
||||||
|
EnvironmentManagementPortalURL EnvironmentProperty = "managementPortalURL"
|
||||||
|
// EnvironmentPublishSettingsURL ...
|
||||||
|
EnvironmentPublishSettingsURL EnvironmentProperty = "publishSettingsURL"
|
||||||
|
// EnvironmentServiceManagementEndpoint ...
|
||||||
|
EnvironmentServiceManagementEndpoint EnvironmentProperty = "serviceManagementEndpoint"
|
||||||
|
// EnvironmentResourceManagerEndpoint ...
|
||||||
|
EnvironmentResourceManagerEndpoint EnvironmentProperty = "resourceManagerEndpoint"
|
||||||
|
// EnvironmentActiveDirectoryEndpoint ...
|
||||||
|
EnvironmentActiveDirectoryEndpoint EnvironmentProperty = "activeDirectoryEndpoint"
|
||||||
|
// EnvironmentGalleryEndpoint ...
|
||||||
|
EnvironmentGalleryEndpoint EnvironmentProperty = "galleryEndpoint"
|
||||||
|
// EnvironmentKeyVaultEndpoint ...
|
||||||
|
EnvironmentKeyVaultEndpoint EnvironmentProperty = "keyVaultEndpoint"
|
||||||
|
// EnvironmentGraphEndpoint ...
|
||||||
|
EnvironmentGraphEndpoint EnvironmentProperty = "graphEndpoint"
|
||||||
|
// EnvironmentServiceBusEndpoint ...
|
||||||
|
EnvironmentServiceBusEndpoint EnvironmentProperty = "serviceBusEndpoint"
|
||||||
|
// EnvironmentBatchManagementEndpoint ...
|
||||||
|
EnvironmentBatchManagementEndpoint EnvironmentProperty = "batchManagementEndpoint"
|
||||||
|
// EnvironmentStorageEndpointSuffix ...
|
||||||
|
EnvironmentStorageEndpointSuffix EnvironmentProperty = "storageEndpointSuffix"
|
||||||
|
// EnvironmentSQLDatabaseDNSSuffix ...
|
||||||
|
EnvironmentSQLDatabaseDNSSuffix EnvironmentProperty = "sqlDatabaseDNSSuffix"
|
||||||
|
// EnvironmentTrafficManagerDNSSuffix ...
|
||||||
|
EnvironmentTrafficManagerDNSSuffix EnvironmentProperty = "trafficManagerDNSSuffix"
|
||||||
|
// EnvironmentKeyVaultDNSSuffix ...
|
||||||
|
EnvironmentKeyVaultDNSSuffix EnvironmentProperty = "keyVaultDNSSuffix"
|
||||||
|
// EnvironmentServiceBusEndpointSuffix ...
|
||||||
|
EnvironmentServiceBusEndpointSuffix EnvironmentProperty = "serviceBusEndpointSuffix"
|
||||||
|
// EnvironmentServiceManagementVMDNSSuffix ...
|
||||||
|
EnvironmentServiceManagementVMDNSSuffix EnvironmentProperty = "serviceManagementVMDNSSuffix"
|
||||||
|
// EnvironmentResourceManagerVMDNSSuffix ...
|
||||||
|
EnvironmentResourceManagerVMDNSSuffix EnvironmentProperty = "resourceManagerVMDNSSuffix"
|
||||||
|
// EnvironmentContainerRegistryDNSSuffix ...
|
||||||
|
EnvironmentContainerRegistryDNSSuffix EnvironmentProperty = "containerRegistryDNSSuffix"
|
||||||
|
// EnvironmentTokenAudience ...
|
||||||
|
EnvironmentTokenAudience EnvironmentProperty = "tokenAudience"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OverrideProperty represents property name and value that clients can override
|
||||||
|
type OverrideProperty struct {
|
||||||
|
Key EnvironmentProperty
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvironmentFromURL loads an Environment from a URL
|
||||||
|
// This function is particularly useful in the Hybrid Cloud model, where one may define their own
|
||||||
|
// endpoints.
|
||||||
|
func EnvironmentFromURL(resourceManagerEndpoint string, properties ...OverrideProperty) (environment Environment, err error) {
|
||||||
|
var metadataEnvProperties environmentMetadataInfo
|
||||||
|
|
||||||
|
if resourceManagerEndpoint == "" {
|
||||||
|
return environment, fmt.Errorf("Metadata resource manager endpoint is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if metadataEnvProperties, err = retrieveMetadataEnvironment(resourceManagerEndpoint); err != nil {
|
||||||
|
return environment, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give priority to user's override values
|
||||||
|
overrideProperties(&environment, properties)
|
||||||
|
|
||||||
|
if environment.Name == "" {
|
||||||
|
environment.Name = "HybridEnvironment"
|
||||||
|
}
|
||||||
|
stampDNSSuffix := environment.StorageEndpointSuffix
|
||||||
|
if stampDNSSuffix == "" {
|
||||||
|
stampDNSSuffix = strings.TrimSuffix(strings.TrimPrefix(strings.Replace(resourceManagerEndpoint, strings.Split(resourceManagerEndpoint, ".")[0], "", 1), "."), "/")
|
||||||
|
environment.StorageEndpointSuffix = stampDNSSuffix
|
||||||
|
}
|
||||||
|
if environment.KeyVaultDNSSuffix == "" {
|
||||||
|
environment.KeyVaultDNSSuffix = fmt.Sprintf("%s.%s", "vault", stampDNSSuffix)
|
||||||
|
}
|
||||||
|
if environment.KeyVaultEndpoint == "" {
|
||||||
|
environment.KeyVaultEndpoint = fmt.Sprintf("%s%s", "https://", environment.KeyVaultDNSSuffix)
|
||||||
|
}
|
||||||
|
if environment.TokenAudience == "" {
|
||||||
|
environment.TokenAudience = metadataEnvProperties.Authentication.Audiences[0]
|
||||||
|
}
|
||||||
|
if environment.ActiveDirectoryEndpoint == "" {
|
||||||
|
environment.ActiveDirectoryEndpoint = metadataEnvProperties.Authentication.LoginEndpoint
|
||||||
|
}
|
||||||
|
if environment.ResourceManagerEndpoint == "" {
|
||||||
|
environment.ResourceManagerEndpoint = resourceManagerEndpoint
|
||||||
|
}
|
||||||
|
if environment.GalleryEndpoint == "" {
|
||||||
|
environment.GalleryEndpoint = metadataEnvProperties.GalleryEndpoint
|
||||||
|
}
|
||||||
|
if environment.GraphEndpoint == "" {
|
||||||
|
environment.GraphEndpoint = metadataEnvProperties.GraphEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
return environment, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func overrideProperties(environment *Environment, properties []OverrideProperty) {
|
||||||
|
for _, property := range properties {
|
||||||
|
switch property.Key {
|
||||||
|
case EnvironmentName:
|
||||||
|
{
|
||||||
|
environment.Name = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentManagementPortalURL:
|
||||||
|
{
|
||||||
|
environment.ManagementPortalURL = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentPublishSettingsURL:
|
||||||
|
{
|
||||||
|
environment.PublishSettingsURL = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentServiceManagementEndpoint:
|
||||||
|
{
|
||||||
|
environment.ServiceManagementEndpoint = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentResourceManagerEndpoint:
|
||||||
|
{
|
||||||
|
environment.ResourceManagerEndpoint = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentActiveDirectoryEndpoint:
|
||||||
|
{
|
||||||
|
environment.ActiveDirectoryEndpoint = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentGalleryEndpoint:
|
||||||
|
{
|
||||||
|
environment.GalleryEndpoint = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentKeyVaultEndpoint:
|
||||||
|
{
|
||||||
|
environment.KeyVaultEndpoint = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentGraphEndpoint:
|
||||||
|
{
|
||||||
|
environment.GraphEndpoint = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentServiceBusEndpoint:
|
||||||
|
{
|
||||||
|
environment.ServiceBusEndpoint = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentBatchManagementEndpoint:
|
||||||
|
{
|
||||||
|
environment.BatchManagementEndpoint = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentStorageEndpointSuffix:
|
||||||
|
{
|
||||||
|
environment.StorageEndpointSuffix = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentSQLDatabaseDNSSuffix:
|
||||||
|
{
|
||||||
|
environment.SQLDatabaseDNSSuffix = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentTrafficManagerDNSSuffix:
|
||||||
|
{
|
||||||
|
environment.TrafficManagerDNSSuffix = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentKeyVaultDNSSuffix:
|
||||||
|
{
|
||||||
|
environment.KeyVaultDNSSuffix = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentServiceBusEndpointSuffix:
|
||||||
|
{
|
||||||
|
environment.ServiceBusEndpointSuffix = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentServiceManagementVMDNSSuffix:
|
||||||
|
{
|
||||||
|
environment.ServiceManagementVMDNSSuffix = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentResourceManagerVMDNSSuffix:
|
||||||
|
{
|
||||||
|
environment.ResourceManagerVMDNSSuffix = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentContainerRegistryDNSSuffix:
|
||||||
|
{
|
||||||
|
environment.ContainerRegistryDNSSuffix = property.Value
|
||||||
|
}
|
||||||
|
case EnvironmentTokenAudience:
|
||||||
|
{
|
||||||
|
environment.TokenAudience = property.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func retrieveMetadataEnvironment(endpoint string) (environment environmentMetadataInfo, err error) {
|
||||||
|
client := autorest.NewClientWithUserAgent("")
|
||||||
|
managementEndpoint := fmt.Sprintf("%s%s", strings.TrimSuffix(endpoint, "/"), "/metadata/endpoints?api-version=1.0")
|
||||||
|
req, _ := http.NewRequest("GET", managementEndpoint, nil)
|
||||||
|
response, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return environment, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
jsonResponse, err := ioutil.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return environment, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(jsonResponse, &environment)
|
||||||
|
return environment, err
|
||||||
|
}
|
200
vendor/github.com/Azure/go-autorest/autorest/azure/rp.go
generated
vendored
Normal file
200
vendor/github.com/Azure/go-autorest/autorest/azure/rp.go
generated
vendored
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package azure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DoRetryWithRegistration tries to register the resource provider in case it is unregistered.
|
||||||
|
// It also handles request retries
|
||||||
|
func DoRetryWithRegistration(client autorest.Client) autorest.SendDecorator {
|
||||||
|
return func(s autorest.Sender) autorest.Sender {
|
||||||
|
return autorest.SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||||
|
rr := autorest.NewRetriableRequest(r)
|
||||||
|
for currentAttempt := 0; currentAttempt < client.RetryAttempts; currentAttempt++ {
|
||||||
|
err = rr.Prepare()
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = autorest.SendWithSender(s, rr.Request(),
|
||||||
|
autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusConflict || client.SkipResourceProviderRegistration {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
var re RequestError
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
autorest.ByUnmarshallingJSON(&re),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
err = re
|
||||||
|
|
||||||
|
if re.ServiceError != nil && re.ServiceError.Code == "MissingSubscriptionRegistration" {
|
||||||
|
regErr := register(client, r, re)
|
||||||
|
if regErr != nil {
|
||||||
|
return resp, fmt.Errorf("failed auto registering Resource Provider: %s. Original error: %s", regErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp, fmt.Errorf("failed request: %s", err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProvider(re RequestError) (string, error) {
|
||||||
|
if re.ServiceError != nil && len(re.ServiceError.Details) > 0 {
|
||||||
|
return re.ServiceError.Details[0]["target"].(string), nil
|
||||||
|
}
|
||||||
|
return "", errors.New("provider was not found in the response")
|
||||||
|
}
|
||||||
|
|
||||||
|
func register(client autorest.Client, originalReq *http.Request, re RequestError) error {
|
||||||
|
subID := getSubscription(originalReq.URL.Path)
|
||||||
|
if subID == "" {
|
||||||
|
return errors.New("missing parameter subscriptionID to register resource provider")
|
||||||
|
}
|
||||||
|
providerName, err := getProvider(re)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("missing parameter provider to register resource provider: %s", err)
|
||||||
|
}
|
||||||
|
newURL := url.URL{
|
||||||
|
Scheme: originalReq.URL.Scheme,
|
||||||
|
Host: originalReq.URL.Host,
|
||||||
|
}
|
||||||
|
|
||||||
|
// taken from the resources SDK
|
||||||
|
// with almost identical code, this sections are easier to mantain
|
||||||
|
// It is also not a good idea to import the SDK here
|
||||||
|
// https://github.com/Azure/azure-sdk-for-go/blob/9f366792afa3e0ddaecdc860e793ba9d75e76c27/arm/resources/resources/providers.go#L252
|
||||||
|
pathParameters := map[string]interface{}{
|
||||||
|
"resourceProviderNamespace": autorest.Encode("path", providerName),
|
||||||
|
"subscriptionId": autorest.Encode("path", subID),
|
||||||
|
}
|
||||||
|
|
||||||
|
const APIVersion = "2016-09-01"
|
||||||
|
queryParameters := map[string]interface{}{
|
||||||
|
"api-version": APIVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsPost(),
|
||||||
|
autorest.WithBaseURL(newURL.String()),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}/register", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters),
|
||||||
|
)
|
||||||
|
|
||||||
|
req, err := preparer.Prepare(&http.Request{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req = req.WithContext(originalReq.Context())
|
||||||
|
|
||||||
|
resp, err := autorest.SendWithSender(client, req,
|
||||||
|
autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type Provider struct {
|
||||||
|
RegistrationState *string `json:"registrationState,omitempty"`
|
||||||
|
}
|
||||||
|
var provider Provider
|
||||||
|
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
|
autorest.ByUnmarshallingJSON(&provider),
|
||||||
|
autorest.ByClosing(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// poll for registered provisioning state
|
||||||
|
now := time.Now()
|
||||||
|
for err == nil && time.Since(now) < client.PollingDuration {
|
||||||
|
// taken from the resources SDK
|
||||||
|
// https://github.com/Azure/azure-sdk-for-go/blob/9f366792afa3e0ddaecdc860e793ba9d75e76c27/arm/resources/resources/providers.go#L45
|
||||||
|
preparer := autorest.CreatePreparer(
|
||||||
|
autorest.AsGet(),
|
||||||
|
autorest.WithBaseURL(newURL.String()),
|
||||||
|
autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}", pathParameters),
|
||||||
|
autorest.WithQueryParameters(queryParameters),
|
||||||
|
)
|
||||||
|
req, err = preparer.Prepare(&http.Request{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req = req.WithContext(originalReq.Context())
|
||||||
|
|
||||||
|
resp, err := autorest.SendWithSender(client, req,
|
||||||
|
autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = autorest.Respond(
|
||||||
|
resp,
|
||||||
|
WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
|
autorest.ByUnmarshallingJSON(&provider),
|
||||||
|
autorest.ByClosing(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if provider.RegistrationState != nil &&
|
||||||
|
*provider.RegistrationState == "Registered" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
delayed := autorest.DelayWithRetryAfter(resp, originalReq.Context().Done())
|
||||||
|
if !delayed && !autorest.DelayForBackoff(client.PollingDelay, 0, originalReq.Context().Done()) {
|
||||||
|
return originalReq.Context().Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !(time.Since(now) < client.PollingDuration) {
|
||||||
|
return errors.New("polling for resource provider registration has exceeded the polling duration")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSubscription(path string) string {
|
||||||
|
parts := strings.Split(path, "/")
|
||||||
|
for i, v := range parts {
|
||||||
|
if v == "subscriptions" && (i+1) < len(parts) {
|
||||||
|
return parts[i+1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
264
vendor/github.com/Azure/go-autorest/autorest/client.go
generated
vendored
Normal file
264
vendor/github.com/Azure/go-autorest/autorest/client.go
generated
vendored
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/cookiejar"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultPollingDelay is a reasonable delay between polling requests.
|
||||||
|
DefaultPollingDelay = 60 * time.Second
|
||||||
|
|
||||||
|
// DefaultPollingDuration is a reasonable total polling duration.
|
||||||
|
DefaultPollingDuration = 15 * time.Minute
|
||||||
|
|
||||||
|
// DefaultRetryAttempts is number of attempts for retry status codes (5xx).
|
||||||
|
DefaultRetryAttempts = 3
|
||||||
|
|
||||||
|
// DefaultRetryDuration is the duration to wait between retries.
|
||||||
|
DefaultRetryDuration = 30 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// defaultUserAgent builds a string containing the Go version, system archityecture and OS,
|
||||||
|
// and the go-autorest version.
|
||||||
|
defaultUserAgent = fmt.Sprintf("Go/%s (%s-%s) go-autorest/%s",
|
||||||
|
runtime.Version(),
|
||||||
|
runtime.GOARCH,
|
||||||
|
runtime.GOOS,
|
||||||
|
Version(),
|
||||||
|
)
|
||||||
|
|
||||||
|
// StatusCodesForRetry are a defined group of status code for which the client will retry
|
||||||
|
StatusCodesForRetry = []int{
|
||||||
|
http.StatusRequestTimeout, // 408
|
||||||
|
http.StatusTooManyRequests, // 429
|
||||||
|
http.StatusInternalServerError, // 500
|
||||||
|
http.StatusBadGateway, // 502
|
||||||
|
http.StatusServiceUnavailable, // 503
|
||||||
|
http.StatusGatewayTimeout, // 504
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
requestFormat = `HTTP Request Begin ===================================================
|
||||||
|
%s
|
||||||
|
===================================================== HTTP Request End
|
||||||
|
`
|
||||||
|
responseFormat = `HTTP Response Begin ===================================================
|
||||||
|
%s
|
||||||
|
===================================================== HTTP Response End
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Response serves as the base for all responses from generated clients. It provides access to the
|
||||||
|
// last http.Response.
|
||||||
|
type Response struct {
|
||||||
|
*http.Response `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoggingInspector implements request and response inspectors that log the full request and
|
||||||
|
// response to a supplied log.
|
||||||
|
type LoggingInspector struct {
|
||||||
|
Logger *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithInspection returns a PrepareDecorator that emits the http.Request to the supplied logger. The
|
||||||
|
// body is restored after being emitted.
|
||||||
|
//
|
||||||
|
// Note: Since it reads the entire Body, this decorator should not be used where body streaming is
|
||||||
|
// important. It is best used to trace JSON or similar body values.
|
||||||
|
func (li LoggingInspector) WithInspection() PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
var body, b bytes.Buffer
|
||||||
|
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
r.Body = ioutil.NopCloser(io.TeeReader(r.Body, &body))
|
||||||
|
if err := r.Write(&b); err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to write response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
li.Logger.Printf(requestFormat, b.String())
|
||||||
|
|
||||||
|
r.Body = ioutil.NopCloser(&body)
|
||||||
|
return p.Prepare(r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByInspecting returns a RespondDecorator that emits the http.Response to the supplied logger. The
|
||||||
|
// body is restored after being emitted.
|
||||||
|
//
|
||||||
|
// Note: Since it reads the entire Body, this decorator should not be used where body streaming is
|
||||||
|
// important. It is best used to trace JSON or similar body values.
|
||||||
|
func (li LoggingInspector) ByInspecting() RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
var body, b bytes.Buffer
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resp.Body = ioutil.NopCloser(io.TeeReader(resp.Body, &body))
|
||||||
|
if err := resp.Write(&b); err != nil {
|
||||||
|
return fmt.Errorf("Failed to write response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
li.Logger.Printf(responseFormat, b.String())
|
||||||
|
|
||||||
|
resp.Body = ioutil.NopCloser(&body)
|
||||||
|
return r.Respond(resp)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client is the base for autorest generated clients. It provides default, "do nothing"
|
||||||
|
// implementations of an Authorizer, RequestInspector, and ResponseInspector. It also returns the
|
||||||
|
// standard, undecorated http.Client as a default Sender.
|
||||||
|
//
|
||||||
|
// Generated clients should also use Error (see NewError and NewErrorWithError) for errors and
|
||||||
|
// return responses that compose with Response.
|
||||||
|
//
|
||||||
|
// Most customization of generated clients is best achieved by supplying a custom Authorizer, custom
|
||||||
|
// RequestInspector, and / or custom ResponseInspector. Users may log requests, implement circuit
|
||||||
|
// breakers (see https://msdn.microsoft.com/en-us/library/dn589784.aspx) or otherwise influence
|
||||||
|
// sending the request by providing a decorated Sender.
|
||||||
|
type Client struct {
|
||||||
|
Authorizer Authorizer
|
||||||
|
Sender Sender
|
||||||
|
RequestInspector PrepareDecorator
|
||||||
|
ResponseInspector RespondDecorator
|
||||||
|
|
||||||
|
// PollingDelay sets the polling frequency used in absence of a Retry-After HTTP header
|
||||||
|
PollingDelay time.Duration
|
||||||
|
|
||||||
|
// PollingDuration sets the maximum polling time after which an error is returned.
|
||||||
|
PollingDuration time.Duration
|
||||||
|
|
||||||
|
// RetryAttempts sets the default number of retry attempts for client.
|
||||||
|
RetryAttempts int
|
||||||
|
|
||||||
|
// RetryDuration sets the delay duration for retries.
|
||||||
|
RetryDuration time.Duration
|
||||||
|
|
||||||
|
// UserAgent, if not empty, will be set as the HTTP User-Agent header on all requests sent
|
||||||
|
// through the Do method.
|
||||||
|
UserAgent string
|
||||||
|
|
||||||
|
Jar http.CookieJar
|
||||||
|
|
||||||
|
// Set to true to skip attempted registration of resource providers (false by default).
|
||||||
|
SkipResourceProviderRegistration bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientWithUserAgent returns an instance of a Client with the UserAgent set to the passed
|
||||||
|
// string.
|
||||||
|
func NewClientWithUserAgent(ua string) Client {
|
||||||
|
c := Client{
|
||||||
|
PollingDelay: DefaultPollingDelay,
|
||||||
|
PollingDuration: DefaultPollingDuration,
|
||||||
|
RetryAttempts: DefaultRetryAttempts,
|
||||||
|
RetryDuration: DefaultRetryDuration,
|
||||||
|
UserAgent: defaultUserAgent,
|
||||||
|
}
|
||||||
|
c.Sender = c.sender()
|
||||||
|
c.AddToUserAgent(ua)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddToUserAgent adds an extension to the current user agent
|
||||||
|
func (c *Client) AddToUserAgent(extension string) error {
|
||||||
|
if extension != "" {
|
||||||
|
c.UserAgent = fmt.Sprintf("%s %s", c.UserAgent, extension)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Extension was empty, User Agent stayed as %s", c.UserAgent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do implements the Sender interface by invoking the active Sender after applying authorization.
|
||||||
|
// If Sender is not set, it uses a new instance of http.Client. In both cases it will, if UserAgent
|
||||||
|
// is set, apply set the User-Agent header.
|
||||||
|
func (c Client) Do(r *http.Request) (*http.Response, error) {
|
||||||
|
if r.UserAgent() == "" {
|
||||||
|
r, _ = Prepare(r,
|
||||||
|
WithUserAgent(c.UserAgent))
|
||||||
|
}
|
||||||
|
// NOTE: c.WithInspection() must be last in the list so that it can inspect all preceding operations
|
||||||
|
r, err := Prepare(r,
|
||||||
|
c.WithAuthorization(),
|
||||||
|
c.WithInspection())
|
||||||
|
if err != nil {
|
||||||
|
var resp *http.Response
|
||||||
|
if detErr, ok := err.(DetailedError); ok {
|
||||||
|
// if the authorization failed (e.g. invalid credentials) there will
|
||||||
|
// be a response associated with the error, be sure to return it.
|
||||||
|
resp = detErr.Response
|
||||||
|
}
|
||||||
|
return resp, NewErrorWithError(err, "autorest/Client", "Do", nil, "Preparing request failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := SendWithSender(c.sender(), r)
|
||||||
|
Respond(resp, c.ByInspecting())
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// sender returns the Sender to which to send requests.
|
||||||
|
func (c Client) sender() Sender {
|
||||||
|
if c.Sender == nil {
|
||||||
|
j, _ := cookiejar.New(nil)
|
||||||
|
return &http.Client{Jar: j}
|
||||||
|
}
|
||||||
|
return c.Sender
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithAuthorization is a convenience method that returns the WithAuthorization PrepareDecorator
|
||||||
|
// from the current Authorizer. If not Authorizer is set, it uses the NullAuthorizer.
|
||||||
|
func (c Client) WithAuthorization() PrepareDecorator {
|
||||||
|
return c.authorizer().WithAuthorization()
|
||||||
|
}
|
||||||
|
|
||||||
|
// authorizer returns the Authorizer to use.
|
||||||
|
func (c Client) authorizer() Authorizer {
|
||||||
|
if c.Authorizer == nil {
|
||||||
|
return NullAuthorizer{}
|
||||||
|
}
|
||||||
|
return c.Authorizer
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithInspection is a convenience method that passes the request to the supplied RequestInspector,
|
||||||
|
// if present, or returns the WithNothing PrepareDecorator otherwise.
|
||||||
|
func (c Client) WithInspection() PrepareDecorator {
|
||||||
|
if c.RequestInspector == nil {
|
||||||
|
return WithNothing()
|
||||||
|
}
|
||||||
|
return c.RequestInspector
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByInspecting is a convenience method that passes the response to the supplied ResponseInspector,
|
||||||
|
// if present, or returns the ByIgnoring RespondDecorator otherwise.
|
||||||
|
func (c Client) ByInspecting() RespondDecorator {
|
||||||
|
if c.ResponseInspector == nil {
|
||||||
|
return ByIgnoring()
|
||||||
|
}
|
||||||
|
return c.ResponseInspector
|
||||||
|
}
|
96
vendor/github.com/Azure/go-autorest/autorest/date/date.go
generated
vendored
Normal file
96
vendor/github.com/Azure/go-autorest/autorest/date/date.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
Package date provides time.Time derivatives that conform to the Swagger.io (https://swagger.io/)
|
||||||
|
defined date formats: Date and DateTime. Both types may, in most cases, be used in lieu of
|
||||||
|
time.Time types. And both convert to time.Time through a ToTime method.
|
||||||
|
*/
|
||||||
|
package date
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
fullDate = "2006-01-02"
|
||||||
|
fullDateJSON = `"2006-01-02"`
|
||||||
|
dateFormat = "%04d-%02d-%02d"
|
||||||
|
jsonFormat = `"%04d-%02d-%02d"`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Date defines a type similar to time.Time but assumes a layout of RFC3339 full-date (i.e.,
|
||||||
|
// 2006-01-02).
|
||||||
|
type Date struct {
|
||||||
|
time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseDate create a new Date from the passed string.
|
||||||
|
func ParseDate(date string) (d Date, err error) {
|
||||||
|
return parseDate(date, fullDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDate(date string, format string) (Date, error) {
|
||||||
|
d, err := time.Parse(format, date)
|
||||||
|
return Date{Time: d}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary preserves the Date as a byte array conforming to RFC3339 full-date (i.e.,
|
||||||
|
// 2006-01-02).
|
||||||
|
func (d Date) MarshalBinary() ([]byte, error) {
|
||||||
|
return d.MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary reconstitutes a Date saved as a byte array conforming to RFC3339 full-date (i.e.,
|
||||||
|
// 2006-01-02).
|
||||||
|
func (d *Date) UnmarshalBinary(data []byte) error {
|
||||||
|
return d.UnmarshalText(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON preserves the Date as a JSON string conforming to RFC3339 full-date (i.e.,
|
||||||
|
// 2006-01-02).
|
||||||
|
func (d Date) MarshalJSON() (json []byte, err error) {
|
||||||
|
return []byte(fmt.Sprintf(jsonFormat, d.Year(), d.Month(), d.Day())), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON reconstitutes the Date from a JSON string conforming to RFC3339 full-date (i.e.,
|
||||||
|
// 2006-01-02).
|
||||||
|
func (d *Date) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
d.Time, err = time.Parse(fullDateJSON, string(data))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText preserves the Date as a byte array conforming to RFC3339 full-date (i.e.,
|
||||||
|
// 2006-01-02).
|
||||||
|
func (d Date) MarshalText() (text []byte, err error) {
|
||||||
|
return []byte(fmt.Sprintf(dateFormat, d.Year(), d.Month(), d.Day())), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText reconstitutes a Date saved as a byte array conforming to RFC3339 full-date (i.e.,
|
||||||
|
// 2006-01-02).
|
||||||
|
func (d *Date) UnmarshalText(data []byte) (err error) {
|
||||||
|
d.Time, err = time.Parse(fullDate, string(data))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the Date formatted as an RFC3339 full-date string (i.e., 2006-01-02).
|
||||||
|
func (d Date) String() string {
|
||||||
|
return fmt.Sprintf(dateFormat, d.Year(), d.Month(), d.Day())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTime returns a Date as a time.Time
|
||||||
|
func (d Date) ToTime() time.Time {
|
||||||
|
return d.Time
|
||||||
|
}
|
103
vendor/github.com/Azure/go-autorest/autorest/date/time.go
generated
vendored
Normal file
103
vendor/github.com/Azure/go-autorest/autorest/date/time.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package date
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Azure reports time in UTC but it doesn't include the 'Z' time zone suffix in some cases.
|
||||||
|
const (
|
||||||
|
azureUtcFormatJSON = `"2006-01-02T15:04:05.999999999"`
|
||||||
|
azureUtcFormat = "2006-01-02T15:04:05.999999999"
|
||||||
|
rfc3339JSON = `"` + time.RFC3339Nano + `"`
|
||||||
|
rfc3339 = time.RFC3339Nano
|
||||||
|
tzOffsetRegex = `(Z|z|\+|-)(\d+:\d+)*"*$`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Time defines a type similar to time.Time but assumes a layout of RFC3339 date-time (i.e.,
|
||||||
|
// 2006-01-02T15:04:05Z).
|
||||||
|
type Time struct {
|
||||||
|
time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary preserves the Time as a byte array conforming to RFC3339 date-time (i.e.,
|
||||||
|
// 2006-01-02T15:04:05Z).
|
||||||
|
func (t Time) MarshalBinary() ([]byte, error) {
|
||||||
|
return t.Time.MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary reconstitutes a Time saved as a byte array conforming to RFC3339 date-time
|
||||||
|
// (i.e., 2006-01-02T15:04:05Z).
|
||||||
|
func (t *Time) UnmarshalBinary(data []byte) error {
|
||||||
|
return t.UnmarshalText(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON preserves the Time as a JSON string conforming to RFC3339 date-time (i.e.,
|
||||||
|
// 2006-01-02T15:04:05Z).
|
||||||
|
func (t Time) MarshalJSON() (json []byte, err error) {
|
||||||
|
return t.Time.MarshalJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON reconstitutes the Time from a JSON string conforming to RFC3339 date-time
|
||||||
|
// (i.e., 2006-01-02T15:04:05Z).
|
||||||
|
func (t *Time) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
timeFormat := azureUtcFormatJSON
|
||||||
|
match, err := regexp.Match(tzOffsetRegex, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if match {
|
||||||
|
timeFormat = rfc3339JSON
|
||||||
|
}
|
||||||
|
t.Time, err = ParseTime(timeFormat, string(data))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText preserves the Time as a byte array conforming to RFC3339 date-time (i.e.,
|
||||||
|
// 2006-01-02T15:04:05Z).
|
||||||
|
func (t Time) MarshalText() (text []byte, err error) {
|
||||||
|
return t.Time.MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText reconstitutes a Time saved as a byte array conforming to RFC3339 date-time
|
||||||
|
// (i.e., 2006-01-02T15:04:05Z).
|
||||||
|
func (t *Time) UnmarshalText(data []byte) (err error) {
|
||||||
|
timeFormat := azureUtcFormat
|
||||||
|
match, err := regexp.Match(tzOffsetRegex, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if match {
|
||||||
|
timeFormat = rfc3339
|
||||||
|
}
|
||||||
|
t.Time, err = ParseTime(timeFormat, string(data))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the Time formatted as an RFC3339 date-time string (i.e.,
|
||||||
|
// 2006-01-02T15:04:05Z).
|
||||||
|
func (t Time) String() string {
|
||||||
|
// Note: time.Time.String does not return an RFC3339 compliant string, time.Time.MarshalText does.
|
||||||
|
b, err := t.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTime returns a Time as a time.Time
|
||||||
|
func (t Time) ToTime() time.Time {
|
||||||
|
return t.Time
|
||||||
|
}
|
100
vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go
generated
vendored
Normal file
100
vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
package date
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
rfc1123JSON = `"` + time.RFC1123 + `"`
|
||||||
|
rfc1123 = time.RFC1123
|
||||||
|
)
|
||||||
|
|
||||||
|
// TimeRFC1123 defines a type similar to time.Time but assumes a layout of RFC1123 date-time (i.e.,
|
||||||
|
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||||
|
type TimeRFC1123 struct {
|
||||||
|
time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON reconstitutes the Time from a JSON string conforming to RFC1123 date-time
|
||||||
|
// (i.e., Mon, 02 Jan 2006 15:04:05 MST).
|
||||||
|
func (t *TimeRFC1123) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
t.Time, err = ParseTime(rfc1123JSON, string(data))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON preserves the Time as a JSON string conforming to RFC1123 date-time (i.e.,
|
||||||
|
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||||
|
func (t TimeRFC1123) MarshalJSON() ([]byte, error) {
|
||||||
|
if y := t.Year(); y < 0 || y >= 10000 {
|
||||||
|
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
|
||||||
|
}
|
||||||
|
b := []byte(t.Format(rfc1123JSON))
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText preserves the Time as a byte array conforming to RFC1123 date-time (i.e.,
|
||||||
|
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||||
|
func (t TimeRFC1123) MarshalText() ([]byte, error) {
|
||||||
|
if y := t.Year(); y < 0 || y >= 10000 {
|
||||||
|
return nil, errors.New("Time.MarshalText: year outside of range [0,9999]")
|
||||||
|
}
|
||||||
|
|
||||||
|
b := []byte(t.Format(rfc1123))
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText reconstitutes a Time saved as a byte array conforming to RFC1123 date-time
|
||||||
|
// (i.e., Mon, 02 Jan 2006 15:04:05 MST).
|
||||||
|
func (t *TimeRFC1123) UnmarshalText(data []byte) (err error) {
|
||||||
|
t.Time, err = ParseTime(rfc1123, string(data))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary preserves the Time as a byte array conforming to RFC1123 date-time (i.e.,
|
||||||
|
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||||
|
func (t TimeRFC1123) MarshalBinary() ([]byte, error) {
|
||||||
|
return t.MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary reconstitutes a Time saved as a byte array conforming to RFC1123 date-time
|
||||||
|
// (i.e., Mon, 02 Jan 2006 15:04:05 MST).
|
||||||
|
func (t *TimeRFC1123) UnmarshalBinary(data []byte) error {
|
||||||
|
return t.UnmarshalText(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTime returns a Time as a time.Time
|
||||||
|
func (t TimeRFC1123) ToTime() time.Time {
|
||||||
|
return t.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the Time formatted as an RFC1123 date-time string (i.e.,
|
||||||
|
// Mon, 02 Jan 2006 15:04:05 MST).
|
||||||
|
func (t TimeRFC1123) String() string {
|
||||||
|
// Note: time.Time.String does not return an RFC1123 compliant string, time.Time.MarshalText does.
|
||||||
|
b, err := t.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
123
vendor/github.com/Azure/go-autorest/autorest/date/unixtime.go
generated
vendored
Normal file
123
vendor/github.com/Azure/go-autorest/autorest/date/unixtime.go
generated
vendored
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
package date
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// unixEpoch is the moment in time that should be treated as timestamp 0.
|
||||||
|
var unixEpoch = time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
|
// UnixTime marshals and unmarshals a time that is represented as the number
|
||||||
|
// of seconds (ignoring skip-seconds) since the Unix Epoch.
|
||||||
|
type UnixTime time.Time
|
||||||
|
|
||||||
|
// Duration returns the time as a Duration since the UnixEpoch.
|
||||||
|
func (t UnixTime) Duration() time.Duration {
|
||||||
|
return time.Time(t).Sub(unixEpoch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnixTimeFromSeconds creates a UnixTime as a number of seconds from the UnixEpoch.
|
||||||
|
func NewUnixTimeFromSeconds(seconds float64) UnixTime {
|
||||||
|
return NewUnixTimeFromDuration(time.Duration(seconds * float64(time.Second)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnixTimeFromNanoseconds creates a UnixTime as a number of nanoseconds from the UnixEpoch.
|
||||||
|
func NewUnixTimeFromNanoseconds(nanoseconds int64) UnixTime {
|
||||||
|
return NewUnixTimeFromDuration(time.Duration(nanoseconds))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnixTimeFromDuration creates a UnixTime as a duration of time since the UnixEpoch.
|
||||||
|
func NewUnixTimeFromDuration(dur time.Duration) UnixTime {
|
||||||
|
return UnixTime(unixEpoch.Add(dur))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnixEpoch retreives the moment considered the Unix Epoch. I.e. The time represented by '0'
|
||||||
|
func UnixEpoch() time.Time {
|
||||||
|
return unixEpoch
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON preserves the UnixTime as a JSON number conforming to Unix Timestamp requirements.
|
||||||
|
// (i.e. the number of seconds since midnight January 1st, 1970 not considering leap seconds.)
|
||||||
|
func (t UnixTime) MarshalJSON() ([]byte, error) {
|
||||||
|
buffer := &bytes.Buffer{}
|
||||||
|
enc := json.NewEncoder(buffer)
|
||||||
|
err := enc.Encode(float64(time.Time(t).UnixNano()) / 1e9)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON reconstitures a UnixTime saved as a JSON number of the number of seconds since
|
||||||
|
// midnight January 1st, 1970.
|
||||||
|
func (t *UnixTime) UnmarshalJSON(text []byte) error {
|
||||||
|
dec := json.NewDecoder(bytes.NewReader(text))
|
||||||
|
|
||||||
|
var secondsSinceEpoch float64
|
||||||
|
if err := dec.Decode(&secondsSinceEpoch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = NewUnixTimeFromSeconds(secondsSinceEpoch)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText stores the number of seconds since the Unix Epoch as a textual floating point number.
|
||||||
|
func (t UnixTime) MarshalText() ([]byte, error) {
|
||||||
|
cast := time.Time(t)
|
||||||
|
return cast.MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText populates a UnixTime with a value stored textually as a floating point number of seconds since the Unix Epoch.
|
||||||
|
func (t *UnixTime) UnmarshalText(raw []byte) error {
|
||||||
|
var unmarshaled time.Time
|
||||||
|
|
||||||
|
if err := unmarshaled.UnmarshalText(raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = UnixTime(unmarshaled)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary converts a UnixTime into a binary.LittleEndian float64 of nanoseconds since the epoch.
|
||||||
|
func (t UnixTime) MarshalBinary() ([]byte, error) {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
|
payload := int64(t.Duration())
|
||||||
|
|
||||||
|
if err := binary.Write(buf, binary.LittleEndian, &payload); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary converts a from a binary.LittleEndian float64 of nanoseconds since the epoch into a UnixTime.
|
||||||
|
func (t *UnixTime) UnmarshalBinary(raw []byte) error {
|
||||||
|
var nanosecondsSinceEpoch int64
|
||||||
|
|
||||||
|
if err := binary.Read(bytes.NewReader(raw), binary.LittleEndian, &nanosecondsSinceEpoch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*t = NewUnixTimeFromNanoseconds(nanosecondsSinceEpoch)
|
||||||
|
return nil
|
||||||
|
}
|
25
vendor/github.com/Azure/go-autorest/autorest/date/utility.go
generated
vendored
Normal file
25
vendor/github.com/Azure/go-autorest/autorest/date/utility.go
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package date
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseTime to parse Time string to specified format.
|
||||||
|
func ParseTime(format string, t string) (d time.Time, err error) {
|
||||||
|
return time.Parse(format, strings.ToUpper(t))
|
||||||
|
}
|
98
vendor/github.com/Azure/go-autorest/autorest/error.go
generated
vendored
Normal file
98
vendor/github.com/Azure/go-autorest/autorest/error.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UndefinedStatusCode is used when HTTP status code is not available for an error.
|
||||||
|
UndefinedStatusCode = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// DetailedError encloses a error with details of the package, method, and associated HTTP
|
||||||
|
// status code (if any).
|
||||||
|
type DetailedError struct {
|
||||||
|
Original error
|
||||||
|
|
||||||
|
// PackageType is the package type of the object emitting the error. For types, the value
|
||||||
|
// matches that produced the the '%T' format specifier of the fmt package. For other elements,
|
||||||
|
// such as functions, it is just the package name (e.g., "autorest").
|
||||||
|
PackageType string
|
||||||
|
|
||||||
|
// Method is the name of the method raising the error.
|
||||||
|
Method string
|
||||||
|
|
||||||
|
// StatusCode is the HTTP Response StatusCode (if non-zero) that led to the error.
|
||||||
|
StatusCode interface{}
|
||||||
|
|
||||||
|
// Message is the error message.
|
||||||
|
Message string
|
||||||
|
|
||||||
|
// Service Error is the response body of failed API in bytes
|
||||||
|
ServiceError []byte
|
||||||
|
|
||||||
|
// Response is the response object that was returned during failure if applicable.
|
||||||
|
Response *http.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewError creates a new Error conforming object from the passed packageType, method, and
|
||||||
|
// message. message is treated as a format string to which the optional args apply.
|
||||||
|
func NewError(packageType string, method string, message string, args ...interface{}) DetailedError {
|
||||||
|
return NewErrorWithError(nil, packageType, method, nil, message, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrorWithResponse creates a new Error conforming object from the passed
|
||||||
|
// packageType, method, statusCode of the given resp (UndefinedStatusCode if
|
||||||
|
// resp is nil), and message. message is treated as a format string to which the
|
||||||
|
// optional args apply.
|
||||||
|
func NewErrorWithResponse(packageType string, method string, resp *http.Response, message string, args ...interface{}) DetailedError {
|
||||||
|
return NewErrorWithError(nil, packageType, method, resp, message, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrorWithError creates a new Error conforming object from the
|
||||||
|
// passed packageType, method, statusCode of the given resp (UndefinedStatusCode
|
||||||
|
// if resp is nil), message, and original error. message is treated as a format
|
||||||
|
// string to which the optional args apply.
|
||||||
|
func NewErrorWithError(original error, packageType string, method string, resp *http.Response, message string, args ...interface{}) DetailedError {
|
||||||
|
if v, ok := original.(DetailedError); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
statusCode := UndefinedStatusCode
|
||||||
|
if resp != nil {
|
||||||
|
statusCode = resp.StatusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
return DetailedError{
|
||||||
|
Original: original,
|
||||||
|
PackageType: packageType,
|
||||||
|
Method: method,
|
||||||
|
StatusCode: statusCode,
|
||||||
|
Message: fmt.Sprintf(message, args...),
|
||||||
|
Response: resp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns a formatted containing all available details (i.e., PackageType, Method,
|
||||||
|
// StatusCode, Message, and original error (if any)).
|
||||||
|
func (e DetailedError) Error() string {
|
||||||
|
if e.Original == nil {
|
||||||
|
return fmt.Sprintf("%s#%s: %s: StatusCode=%d", e.PackageType, e.Method, e.Message, e.StatusCode)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s#%s: %s: StatusCode=%d -- Original Error: %v", e.PackageType, e.Method, e.Message, e.StatusCode, e.Original)
|
||||||
|
}
|
480
vendor/github.com/Azure/go-autorest/autorest/preparer.go
generated
vendored
Normal file
480
vendor/github.com/Azure/go-autorest/autorest/preparer.go
generated
vendored
Normal file
|
@ -0,0 +1,480 @@
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
mimeTypeJSON = "application/json"
|
||||||
|
mimeTypeOctetStream = "application/octet-stream"
|
||||||
|
mimeTypeFormPost = "application/x-www-form-urlencoded"
|
||||||
|
|
||||||
|
headerAuthorization = "Authorization"
|
||||||
|
headerContentType = "Content-Type"
|
||||||
|
headerUserAgent = "User-Agent"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Preparer is the interface that wraps the Prepare method.
|
||||||
|
//
|
||||||
|
// Prepare accepts and possibly modifies an http.Request (e.g., adding Headers). Implementations
|
||||||
|
// must ensure to not share or hold per-invocation state since Preparers may be shared and re-used.
|
||||||
|
type Preparer interface {
|
||||||
|
Prepare(*http.Request) (*http.Request, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreparerFunc is a method that implements the Preparer interface.
|
||||||
|
type PreparerFunc func(*http.Request) (*http.Request, error)
|
||||||
|
|
||||||
|
// Prepare implements the Preparer interface on PreparerFunc.
|
||||||
|
func (pf PreparerFunc) Prepare(r *http.Request) (*http.Request, error) {
|
||||||
|
return pf(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareDecorator takes and possibly decorates, by wrapping, a Preparer. Decorators may affect the
|
||||||
|
// http.Request and pass it along or, first, pass the http.Request along then affect the result.
|
||||||
|
type PrepareDecorator func(Preparer) Preparer
|
||||||
|
|
||||||
|
// CreatePreparer creates, decorates, and returns a Preparer.
|
||||||
|
// Without decorators, the returned Preparer returns the passed http.Request unmodified.
|
||||||
|
// Preparers are safe to share and re-use.
|
||||||
|
func CreatePreparer(decorators ...PrepareDecorator) Preparer {
|
||||||
|
return DecoratePreparer(
|
||||||
|
Preparer(PreparerFunc(func(r *http.Request) (*http.Request, error) { return r, nil })),
|
||||||
|
decorators...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecoratePreparer accepts a Preparer and a, possibly empty, set of PrepareDecorators, which it
|
||||||
|
// applies to the Preparer. Decorators are applied in the order received, but their affect upon the
|
||||||
|
// request depends on whether they are a pre-decorator (change the http.Request and then pass it
|
||||||
|
// along) or a post-decorator (pass the http.Request along and alter it on return).
|
||||||
|
func DecoratePreparer(p Preparer, decorators ...PrepareDecorator) Preparer {
|
||||||
|
for _, decorate := range decorators {
|
||||||
|
p = decorate(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare accepts an http.Request and a, possibly empty, set of PrepareDecorators.
|
||||||
|
// It creates a Preparer from the decorators which it then applies to the passed http.Request.
|
||||||
|
func Prepare(r *http.Request, decorators ...PrepareDecorator) (*http.Request, error) {
|
||||||
|
if r == nil {
|
||||||
|
return nil, NewError("autorest", "Prepare", "Invoked without an http.Request")
|
||||||
|
}
|
||||||
|
return CreatePreparer(decorators...).Prepare(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithNothing returns a "do nothing" PrepareDecorator that makes no changes to the passed
|
||||||
|
// http.Request.
|
||||||
|
func WithNothing() PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
return p.Prepare(r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHeader returns a PrepareDecorator that sets the specified HTTP header of the http.Request to
|
||||||
|
// the passed value. It canonicalizes the passed header name (via http.CanonicalHeaderKey) before
|
||||||
|
// adding the header.
|
||||||
|
func WithHeader(header string, value string) PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
if r.Header == nil {
|
||||||
|
r.Header = make(http.Header)
|
||||||
|
}
|
||||||
|
r.Header.Set(http.CanonicalHeaderKey(header), value)
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHeaders returns a PrepareDecorator that sets the specified HTTP headers of the http.Request to
|
||||||
|
// the passed value. It canonicalizes the passed headers name (via http.CanonicalHeaderKey) before
|
||||||
|
// adding them.
|
||||||
|
func WithHeaders(headers map[string]interface{}) PrepareDecorator {
|
||||||
|
h := ensureValueStrings(headers)
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
if r.Header == nil {
|
||||||
|
r.Header = make(http.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, value := range h {
|
||||||
|
r.Header.Set(http.CanonicalHeaderKey(name), value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBearerAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
|
||||||
|
// value is "Bearer " followed by the supplied token.
|
||||||
|
func WithBearerAuthorization(token string) PrepareDecorator {
|
||||||
|
return WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", token))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsContentType returns a PrepareDecorator that adds an HTTP Content-Type header whose value
|
||||||
|
// is the passed contentType.
|
||||||
|
func AsContentType(contentType string) PrepareDecorator {
|
||||||
|
return WithHeader(headerContentType, contentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithUserAgent returns a PrepareDecorator that adds an HTTP User-Agent header whose value is the
|
||||||
|
// passed string.
|
||||||
|
func WithUserAgent(ua string) PrepareDecorator {
|
||||||
|
return WithHeader(headerUserAgent, ua)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsFormURLEncoded returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
|
||||||
|
// "application/x-www-form-urlencoded".
|
||||||
|
func AsFormURLEncoded() PrepareDecorator {
|
||||||
|
return AsContentType(mimeTypeFormPost)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsJSON returns a PrepareDecorator that adds an HTTP Content-Type header whose value is
|
||||||
|
// "application/json".
|
||||||
|
func AsJSON() PrepareDecorator {
|
||||||
|
return AsContentType(mimeTypeJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsOctetStream returns a PrepareDecorator that adds the "application/octet-stream" Content-Type header.
|
||||||
|
func AsOctetStream() PrepareDecorator {
|
||||||
|
return AsContentType(mimeTypeOctetStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMethod returns a PrepareDecorator that sets the HTTP method of the passed request. The
|
||||||
|
// decorator does not validate that the passed method string is a known HTTP method.
|
||||||
|
func WithMethod(method string) PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r.Method = method
|
||||||
|
return p.Prepare(r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsDelete returns a PrepareDecorator that sets the HTTP method to DELETE.
|
||||||
|
func AsDelete() PrepareDecorator { return WithMethod("DELETE") }
|
||||||
|
|
||||||
|
// AsGet returns a PrepareDecorator that sets the HTTP method to GET.
|
||||||
|
func AsGet() PrepareDecorator { return WithMethod("GET") }
|
||||||
|
|
||||||
|
// AsHead returns a PrepareDecorator that sets the HTTP method to HEAD.
|
||||||
|
func AsHead() PrepareDecorator { return WithMethod("HEAD") }
|
||||||
|
|
||||||
|
// AsOptions returns a PrepareDecorator that sets the HTTP method to OPTIONS.
|
||||||
|
func AsOptions() PrepareDecorator { return WithMethod("OPTIONS") }
|
||||||
|
|
||||||
|
// AsPatch returns a PrepareDecorator that sets the HTTP method to PATCH.
|
||||||
|
func AsPatch() PrepareDecorator { return WithMethod("PATCH") }
|
||||||
|
|
||||||
|
// AsPost returns a PrepareDecorator that sets the HTTP method to POST.
|
||||||
|
func AsPost() PrepareDecorator { return WithMethod("POST") }
|
||||||
|
|
||||||
|
// AsPut returns a PrepareDecorator that sets the HTTP method to PUT.
|
||||||
|
func AsPut() PrepareDecorator { return WithMethod("PUT") }
|
||||||
|
|
||||||
|
// WithBaseURL returns a PrepareDecorator that populates the http.Request with a url.URL constructed
|
||||||
|
// from the supplied baseUrl.
|
||||||
|
func WithBaseURL(baseURL string) PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
var u *url.URL
|
||||||
|
if u, err = url.Parse(baseURL); err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
if u.Scheme == "" {
|
||||||
|
err = fmt.Errorf("autorest: No scheme detected in URL %s", baseURL)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
r.URL = u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCustomBaseURL returns a PrepareDecorator that replaces brace-enclosed keys within the
|
||||||
|
// request base URL (i.e., http.Request.URL) with the corresponding values from the passed map.
|
||||||
|
func WithCustomBaseURL(baseURL string, urlParameters map[string]interface{}) PrepareDecorator {
|
||||||
|
parameters := ensureValueStrings(urlParameters)
|
||||||
|
for key, value := range parameters {
|
||||||
|
baseURL = strings.Replace(baseURL, "{"+key+"}", value, -1)
|
||||||
|
}
|
||||||
|
return WithBaseURL(baseURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) into the
|
||||||
|
// http.Request body.
|
||||||
|
func WithFormData(v url.Values) PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
s := v.Encode()
|
||||||
|
|
||||||
|
if r.Header == nil {
|
||||||
|
r.Header = make(http.Header)
|
||||||
|
}
|
||||||
|
r.Header.Set(http.CanonicalHeaderKey(headerContentType), mimeTypeFormPost)
|
||||||
|
r.ContentLength = int64(len(s))
|
||||||
|
r.Body = ioutil.NopCloser(strings.NewReader(s))
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMultiPartFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) form parameters
|
||||||
|
// into the http.Request body.
|
||||||
|
func WithMultiPartFormData(formDataParameters map[string]interface{}) PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
var body bytes.Buffer
|
||||||
|
writer := multipart.NewWriter(&body)
|
||||||
|
for key, value := range formDataParameters {
|
||||||
|
if rc, ok := value.(io.ReadCloser); ok {
|
||||||
|
var fd io.Writer
|
||||||
|
if fd, err = writer.CreateFormFile(key, key); err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
if _, err = io.Copy(fd, rc); err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err = writer.WriteField(key, ensureValueString(value)); err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = writer.Close(); err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
if r.Header == nil {
|
||||||
|
r.Header = make(http.Header)
|
||||||
|
}
|
||||||
|
r.Header.Set(http.CanonicalHeaderKey(headerContentType), writer.FormDataContentType())
|
||||||
|
r.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))
|
||||||
|
r.ContentLength = int64(body.Len())
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFile returns a PrepareDecorator that sends file in request body.
|
||||||
|
func WithFile(f io.ReadCloser) PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
b, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
r.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||||
|
r.ContentLength = int64(len(b))
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBool returns a PrepareDecorator that encodes the passed bool into the body of the request
|
||||||
|
// and sets the Content-Length header.
|
||||||
|
func WithBool(v bool) PrepareDecorator {
|
||||||
|
return WithString(fmt.Sprintf("%v", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFloat32 returns a PrepareDecorator that encodes the passed float32 into the body of the
|
||||||
|
// request and sets the Content-Length header.
|
||||||
|
func WithFloat32(v float32) PrepareDecorator {
|
||||||
|
return WithString(fmt.Sprintf("%v", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFloat64 returns a PrepareDecorator that encodes the passed float64 into the body of the
|
||||||
|
// request and sets the Content-Length header.
|
||||||
|
func WithFloat64(v float64) PrepareDecorator {
|
||||||
|
return WithString(fmt.Sprintf("%v", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithInt32 returns a PrepareDecorator that encodes the passed int32 into the body of the request
|
||||||
|
// and sets the Content-Length header.
|
||||||
|
func WithInt32(v int32) PrepareDecorator {
|
||||||
|
return WithString(fmt.Sprintf("%v", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithInt64 returns a PrepareDecorator that encodes the passed int64 into the body of the request
|
||||||
|
// and sets the Content-Length header.
|
||||||
|
func WithInt64(v int64) PrepareDecorator {
|
||||||
|
return WithString(fmt.Sprintf("%v", v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithString returns a PrepareDecorator that encodes the passed string into the body of the request
|
||||||
|
// and sets the Content-Length header.
|
||||||
|
func WithString(v string) PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
r.ContentLength = int64(len(v))
|
||||||
|
r.Body = ioutil.NopCloser(strings.NewReader(v))
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithJSON returns a PrepareDecorator that encodes the data passed as JSON into the body of the
|
||||||
|
// request and sets the Content-Length header.
|
||||||
|
func WithJSON(v interface{}) PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err == nil {
|
||||||
|
r.ContentLength = int64(len(b))
|
||||||
|
r.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPath returns a PrepareDecorator that adds the supplied path to the request URL. If the path
|
||||||
|
// is absolute (that is, it begins with a "/"), it replaces the existing path.
|
||||||
|
func WithPath(path string) PrepareDecorator {
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
if r.URL == nil {
|
||||||
|
return r, NewError("autorest", "WithPath", "Invoked with a nil URL")
|
||||||
|
}
|
||||||
|
if r.URL, err = parseURL(r.URL, path); err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEscapedPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
|
||||||
|
// request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map. The
|
||||||
|
// values will be escaped (aka URL encoded) before insertion into the path.
|
||||||
|
func WithEscapedPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
|
||||||
|
parameters := escapeValueStrings(ensureValueStrings(pathParameters))
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
if r.URL == nil {
|
||||||
|
return r, NewError("autorest", "WithEscapedPathParameters", "Invoked with a nil URL")
|
||||||
|
}
|
||||||
|
for key, value := range parameters {
|
||||||
|
path = strings.Replace(path, "{"+key+"}", value, -1)
|
||||||
|
}
|
||||||
|
if r.URL, err = parseURL(r.URL, path); err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPathParameters returns a PrepareDecorator that replaces brace-enclosed keys within the
|
||||||
|
// request path (i.e., http.Request.URL.Path) with the corresponding values from the passed map.
|
||||||
|
func WithPathParameters(path string, pathParameters map[string]interface{}) PrepareDecorator {
|
||||||
|
parameters := ensureValueStrings(pathParameters)
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
if r.URL == nil {
|
||||||
|
return r, NewError("autorest", "WithPathParameters", "Invoked with a nil URL")
|
||||||
|
}
|
||||||
|
for key, value := range parameters {
|
||||||
|
path = strings.Replace(path, "{"+key+"}", value, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.URL, err = parseURL(r.URL, path); err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseURL(u *url.URL, path string) (*url.URL, error) {
|
||||||
|
p := strings.TrimRight(u.String(), "/")
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
path = "/" + path
|
||||||
|
}
|
||||||
|
return url.Parse(p + path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithQueryParameters returns a PrepareDecorators that encodes and applies the query parameters
|
||||||
|
// given in the supplied map (i.e., key=value).
|
||||||
|
func WithQueryParameters(queryParameters map[string]interface{}) PrepareDecorator {
|
||||||
|
parameters := ensureValueStrings(queryParameters)
|
||||||
|
return func(p Preparer) Preparer {
|
||||||
|
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||||
|
r, err := p.Prepare(r)
|
||||||
|
if err == nil {
|
||||||
|
if r.URL == nil {
|
||||||
|
return r, NewError("autorest", "WithQueryParameters", "Invoked with a nil URL")
|
||||||
|
}
|
||||||
|
|
||||||
|
v := r.URL.Query()
|
||||||
|
for key, value := range parameters {
|
||||||
|
d, err := url.QueryUnescape(value)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
v.Add(key, d)
|
||||||
|
}
|
||||||
|
r.URL.RawQuery = v.Encode()
|
||||||
|
}
|
||||||
|
return r, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
250
vendor/github.com/Azure/go-autorest/autorest/responder.go
generated
vendored
Normal file
250
vendor/github.com/Azure/go-autorest/autorest/responder.go
generated
vendored
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Responder is the interface that wraps the Respond method.
|
||||||
|
//
|
||||||
|
// Respond accepts and reacts to an http.Response. Implementations must ensure to not share or hold
|
||||||
|
// state since Responders may be shared and re-used.
|
||||||
|
type Responder interface {
|
||||||
|
Respond(*http.Response) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponderFunc is a method that implements the Responder interface.
|
||||||
|
type ResponderFunc func(*http.Response) error
|
||||||
|
|
||||||
|
// Respond implements the Responder interface on ResponderFunc.
|
||||||
|
func (rf ResponderFunc) Respond(r *http.Response) error {
|
||||||
|
return rf(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RespondDecorator takes and possibly decorates, by wrapping, a Responder. Decorators may react to
|
||||||
|
// the http.Response and pass it along or, first, pass the http.Response along then react.
|
||||||
|
type RespondDecorator func(Responder) Responder
|
||||||
|
|
||||||
|
// CreateResponder creates, decorates, and returns a Responder. Without decorators, the returned
|
||||||
|
// Responder returns the passed http.Response unmodified. Responders may or may not be safe to share
|
||||||
|
// and re-used: It depends on the applied decorators. For example, a standard decorator that closes
|
||||||
|
// the response body is fine to share whereas a decorator that reads the body into a passed struct
|
||||||
|
// is not.
|
||||||
|
//
|
||||||
|
// To prevent memory leaks, ensure that at least one Responder closes the response body.
|
||||||
|
func CreateResponder(decorators ...RespondDecorator) Responder {
|
||||||
|
return DecorateResponder(
|
||||||
|
Responder(ResponderFunc(func(r *http.Response) error { return nil })),
|
||||||
|
decorators...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecorateResponder accepts a Responder and a, possibly empty, set of RespondDecorators, which it
|
||||||
|
// applies to the Responder. Decorators are applied in the order received, but their affect upon the
|
||||||
|
// request depends on whether they are a pre-decorator (react to the http.Response and then pass it
|
||||||
|
// along) or a post-decorator (pass the http.Response along and then react).
|
||||||
|
func DecorateResponder(r Responder, decorators ...RespondDecorator) Responder {
|
||||||
|
for _, decorate := range decorators {
|
||||||
|
r = decorate(r)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Respond accepts an http.Response and a, possibly empty, set of RespondDecorators.
|
||||||
|
// It creates a Responder from the decorators it then applies to the passed http.Response.
|
||||||
|
func Respond(r *http.Response, decorators ...RespondDecorator) error {
|
||||||
|
if r == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return CreateResponder(decorators...).Respond(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByIgnoring returns a RespondDecorator that ignores the passed http.Response passing it unexamined
|
||||||
|
// to the next RespondDecorator.
|
||||||
|
func ByIgnoring() RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
return r.Respond(resp)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByCopying copies the contents of the http.Response Body into the passed bytes.Buffer as
|
||||||
|
// the Body is read.
|
||||||
|
func ByCopying(b *bytes.Buffer) RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
err := r.Respond(resp)
|
||||||
|
if err == nil && resp != nil && resp.Body != nil {
|
||||||
|
resp.Body = TeeReadCloser(resp.Body, b)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByDiscardingBody returns a RespondDecorator that first invokes the passed Responder after which
|
||||||
|
// it copies the remaining bytes (if any) in the response body to ioutil.Discard. Since the passed
|
||||||
|
// Responder is invoked prior to discarding the response body, the decorator may occur anywhere
|
||||||
|
// within the set.
|
||||||
|
func ByDiscardingBody() RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
err := r.Respond(resp)
|
||||||
|
if err == nil && resp != nil && resp.Body != nil {
|
||||||
|
if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil {
|
||||||
|
return fmt.Errorf("Error discarding the response body: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByClosing returns a RespondDecorator that first invokes the passed Responder after which it
|
||||||
|
// closes the response body. Since the passed Responder is invoked prior to closing the response
|
||||||
|
// body, the decorator may occur anywhere within the set.
|
||||||
|
func ByClosing() RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
err := r.Respond(resp)
|
||||||
|
if resp != nil && resp.Body != nil {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
return fmt.Errorf("Error closing the response body: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByClosingIfError returns a RespondDecorator that first invokes the passed Responder after which
|
||||||
|
// it closes the response if the passed Responder returns an error and the response body exists.
|
||||||
|
func ByClosingIfError() RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
err := r.Respond(resp)
|
||||||
|
if err != nil && resp != nil && resp.Body != nil {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
return fmt.Errorf("Error closing the response body: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByUnmarshallingJSON returns a RespondDecorator that decodes a JSON document returned in the
|
||||||
|
// response Body into the value pointed to by v.
|
||||||
|
func ByUnmarshallingJSON(v interface{}) RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
err := r.Respond(resp)
|
||||||
|
if err == nil {
|
||||||
|
b, errInner := ioutil.ReadAll(resp.Body)
|
||||||
|
// Some responses might include a BOM, remove for successful unmarshalling
|
||||||
|
b = bytes.TrimPrefix(b, []byte("\xef\xbb\xbf"))
|
||||||
|
if errInner != nil {
|
||||||
|
err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner)
|
||||||
|
} else if len(strings.Trim(string(b), " ")) > 0 {
|
||||||
|
errInner = json.Unmarshal(b, v)
|
||||||
|
if errInner != nil {
|
||||||
|
err = fmt.Errorf("Error occurred unmarshalling JSON - Error = '%v' JSON = '%s'", errInner, string(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByUnmarshallingXML returns a RespondDecorator that decodes a XML document returned in the
|
||||||
|
// response Body into the value pointed to by v.
|
||||||
|
func ByUnmarshallingXML(v interface{}) RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
err := r.Respond(resp)
|
||||||
|
if err == nil {
|
||||||
|
b, errInner := ioutil.ReadAll(resp.Body)
|
||||||
|
if errInner != nil {
|
||||||
|
err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner)
|
||||||
|
} else {
|
||||||
|
errInner = xml.Unmarshal(b, v)
|
||||||
|
if errInner != nil {
|
||||||
|
err = fmt.Errorf("Error occurred unmarshalling Xml - Error = '%v' Xml = '%s'", errInner, string(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithErrorUnlessStatusCode returns a RespondDecorator that emits an error unless the response
|
||||||
|
// StatusCode is among the set passed. On error, response body is fully read into a buffer and
|
||||||
|
// presented in the returned error, as well as in the response body.
|
||||||
|
func WithErrorUnlessStatusCode(codes ...int) RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
err := r.Respond(resp)
|
||||||
|
if err == nil && !ResponseHasStatusCode(resp, codes...) {
|
||||||
|
derr := NewErrorWithResponse("autorest", "WithErrorUnlessStatusCode", resp, "%v %v failed with %s",
|
||||||
|
resp.Request.Method,
|
||||||
|
resp.Request.URL,
|
||||||
|
resp.Status)
|
||||||
|
if resp.Body != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
b, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
derr.ServiceError = b
|
||||||
|
resp.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||||
|
}
|
||||||
|
err = derr
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithErrorUnlessOK returns a RespondDecorator that emits an error if the response StatusCode is
|
||||||
|
// anything other than HTTP 200.
|
||||||
|
func WithErrorUnlessOK() RespondDecorator {
|
||||||
|
return WithErrorUnlessStatusCode(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractHeader extracts all values of the specified header from the http.Response. It returns an
|
||||||
|
// empty string slice if the passed http.Response is nil or the header does not exist.
|
||||||
|
func ExtractHeader(header string, resp *http.Response) []string {
|
||||||
|
if resp != nil && resp.Header != nil {
|
||||||
|
return resp.Header[http.CanonicalHeaderKey(header)]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractHeaderValue extracts the first value of the specified header from the http.Response. It
|
||||||
|
// returns an empty string if the passed http.Response is nil or the header does not exist.
|
||||||
|
func ExtractHeaderValue(header string, resp *http.Response) string {
|
||||||
|
h := ExtractHeader(header, resp)
|
||||||
|
if len(h) > 0 {
|
||||||
|
return h[0]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
52
vendor/github.com/Azure/go-autorest/autorest/retriablerequest.go
generated
vendored
Normal file
52
vendor/github.com/Azure/go-autorest/autorest/retriablerequest.go
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewRetriableRequest returns a wrapper around an HTTP request that support retry logic.
|
||||||
|
func NewRetriableRequest(req *http.Request) *RetriableRequest {
|
||||||
|
return &RetriableRequest{req: req}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request returns the wrapped HTTP request.
|
||||||
|
func (rr *RetriableRequest) Request() *http.Request {
|
||||||
|
return rr.req
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rr *RetriableRequest) prepareFromByteReader() (err error) {
|
||||||
|
// fall back to making a copy (only do this once)
|
||||||
|
b := []byte{}
|
||||||
|
if rr.req.ContentLength > 0 {
|
||||||
|
b = make([]byte, rr.req.ContentLength)
|
||||||
|
_, err = io.ReadFull(rr.req.Body, b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
b, err = ioutil.ReadAll(rr.req.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rr.br = bytes.NewReader(b)
|
||||||
|
rr.req.Body = ioutil.NopCloser(rr.br)
|
||||||
|
return err
|
||||||
|
}
|
54
vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.7.go
generated
vendored
Normal file
54
vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.7.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// +build !go1.8
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RetriableRequest provides facilities for retrying an HTTP request.
|
||||||
|
type RetriableRequest struct {
|
||||||
|
req *http.Request
|
||||||
|
br *bytes.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare signals that the request is about to be sent.
|
||||||
|
func (rr *RetriableRequest) Prepare() (err error) {
|
||||||
|
// preserve the request body; this is to support retry logic as
|
||||||
|
// the underlying transport will always close the reqeust body
|
||||||
|
if rr.req.Body != nil {
|
||||||
|
if rr.br != nil {
|
||||||
|
_, err = rr.br.Seek(0, 0 /*io.SeekStart*/)
|
||||||
|
rr.req.Body = ioutil.NopCloser(rr.br)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if rr.br == nil {
|
||||||
|
// fall back to making a copy (only do this once)
|
||||||
|
err = rr.prepareFromByteReader()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeRequestBody(req *http.Request) {
|
||||||
|
req.Body = nil
|
||||||
|
req.ContentLength = 0
|
||||||
|
}
|
66
vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.8.go
generated
vendored
Normal file
66
vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.8.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// +build go1.8
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RetriableRequest provides facilities for retrying an HTTP request.
|
||||||
|
type RetriableRequest struct {
|
||||||
|
req *http.Request
|
||||||
|
rc io.ReadCloser
|
||||||
|
br *bytes.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare signals that the request is about to be sent.
|
||||||
|
func (rr *RetriableRequest) Prepare() (err error) {
|
||||||
|
// preserve the request body; this is to support retry logic as
|
||||||
|
// the underlying transport will always close the reqeust body
|
||||||
|
if rr.req.Body != nil {
|
||||||
|
if rr.rc != nil {
|
||||||
|
rr.req.Body = rr.rc
|
||||||
|
} else if rr.br != nil {
|
||||||
|
_, err = rr.br.Seek(0, io.SeekStart)
|
||||||
|
rr.req.Body = ioutil.NopCloser(rr.br)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if rr.req.GetBody != nil {
|
||||||
|
// this will allow us to preserve the body without having to
|
||||||
|
// make a copy. note we need to do this on each iteration
|
||||||
|
rr.rc, err = rr.req.GetBody()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if rr.br == nil {
|
||||||
|
// fall back to making a copy (only do this once)
|
||||||
|
err = rr.prepareFromByteReader()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeRequestBody(req *http.Request) {
|
||||||
|
req.Body = nil
|
||||||
|
req.GetBody = nil
|
||||||
|
req.ContentLength = 0
|
||||||
|
}
|
325
vendor/github.com/Azure/go-autorest/autorest/sender.go
generated
vendored
Normal file
325
vendor/github.com/Azure/go-autorest/autorest/sender.go
generated
vendored
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sender is the interface that wraps the Do method to send HTTP requests.
|
||||||
|
//
|
||||||
|
// The standard http.Client conforms to this interface.
|
||||||
|
type Sender interface {
|
||||||
|
Do(*http.Request) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SenderFunc is a method that implements the Sender interface.
|
||||||
|
type SenderFunc func(*http.Request) (*http.Response, error)
|
||||||
|
|
||||||
|
// Do implements the Sender interface on SenderFunc.
|
||||||
|
func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) {
|
||||||
|
return sf(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendDecorator takes and possibily decorates, by wrapping, a Sender. Decorators may affect the
|
||||||
|
// http.Request and pass it along or, first, pass the http.Request along then react to the
|
||||||
|
// http.Response result.
|
||||||
|
type SendDecorator func(Sender) Sender
|
||||||
|
|
||||||
|
// CreateSender creates, decorates, and returns, as a Sender, the default http.Client.
|
||||||
|
func CreateSender(decorators ...SendDecorator) Sender {
|
||||||
|
return DecorateSender(&http.Client{}, decorators...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecorateSender accepts a Sender and a, possibly empty, set of SendDecorators, which is applies to
|
||||||
|
// the Sender. Decorators are applied in the order received, but their affect upon the request
|
||||||
|
// depends on whether they are a pre-decorator (change the http.Request and then pass it along) or a
|
||||||
|
// post-decorator (pass the http.Request along and react to the results in http.Response).
|
||||||
|
func DecorateSender(s Sender, decorators ...SendDecorator) Sender {
|
||||||
|
for _, decorate := range decorators {
|
||||||
|
s = decorate(s)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send sends, by means of the default http.Client, the passed http.Request, returning the
|
||||||
|
// http.Response and possible error. It also accepts a, possibly empty, set of SendDecorators which
|
||||||
|
// it will apply the http.Client before invoking the Do method.
|
||||||
|
//
|
||||||
|
// Send is a convenience method and not recommended for production. Advanced users should use
|
||||||
|
// SendWithSender, passing and sharing their own Sender (e.g., instance of http.Client).
|
||||||
|
//
|
||||||
|
// Send will not poll or retry requests.
|
||||||
|
func Send(r *http.Request, decorators ...SendDecorator) (*http.Response, error) {
|
||||||
|
return SendWithSender(&http.Client{}, r, decorators...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendWithSender sends the passed http.Request, through the provided Sender, returning the
|
||||||
|
// http.Response and possible error. It also accepts a, possibly empty, set of SendDecorators which
|
||||||
|
// it will apply the http.Client before invoking the Do method.
|
||||||
|
//
|
||||||
|
// SendWithSender will not poll or retry requests.
|
||||||
|
func SendWithSender(s Sender, r *http.Request, decorators ...SendDecorator) (*http.Response, error) {
|
||||||
|
return DecorateSender(s, decorators...).Do(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterDelay returns a SendDecorator that delays for the passed time.Duration before
|
||||||
|
// invoking the Sender. The delay may be terminated by closing the optional channel on the
|
||||||
|
// http.Request. If canceled, no further Senders are invoked.
|
||||||
|
func AfterDelay(d time.Duration) SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
|
if !DelayForBackoff(d, 0, r.Context().Done()) {
|
||||||
|
return nil, fmt.Errorf("autorest: AfterDelay canceled before full delay")
|
||||||
|
}
|
||||||
|
return s.Do(r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsIs returns a SendDecorator that invokes the passed Sender without modifying the http.Request.
|
||||||
|
func AsIs() SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
|
return s.Do(r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoCloseIfError returns a SendDecorator that first invokes the passed Sender after which
|
||||||
|
// it closes the response if the passed Sender returns an error and the response body exists.
|
||||||
|
func DoCloseIfError() SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
|
resp, err := s.Do(r)
|
||||||
|
if err != nil {
|
||||||
|
Respond(resp, ByDiscardingBody(), ByClosing())
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoErrorIfStatusCode returns a SendDecorator that emits an error if the response StatusCode is
|
||||||
|
// among the set passed. Since these are artificial errors, the response body may still require
|
||||||
|
// closing.
|
||||||
|
func DoErrorIfStatusCode(codes ...int) SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
|
resp, err := s.Do(r)
|
||||||
|
if err == nil && ResponseHasStatusCode(resp, codes...) {
|
||||||
|
err = NewErrorWithResponse("autorest", "DoErrorIfStatusCode", resp, "%v %v failed with %s",
|
||||||
|
resp.Request.Method,
|
||||||
|
resp.Request.URL,
|
||||||
|
resp.Status)
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoErrorUnlessStatusCode returns a SendDecorator that emits an error unless the response
|
||||||
|
// StatusCode is among the set passed. Since these are artificial errors, the response body
|
||||||
|
// may still require closing.
|
||||||
|
func DoErrorUnlessStatusCode(codes ...int) SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
|
resp, err := s.Do(r)
|
||||||
|
if err == nil && !ResponseHasStatusCode(resp, codes...) {
|
||||||
|
err = NewErrorWithResponse("autorest", "DoErrorUnlessStatusCode", resp, "%v %v failed with %s",
|
||||||
|
resp.Request.Method,
|
||||||
|
resp.Request.URL,
|
||||||
|
resp.Status)
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoPollForStatusCodes returns a SendDecorator that polls if the http.Response contains one of the
|
||||||
|
// passed status codes. It expects the http.Response to contain a Location header providing the
|
||||||
|
// URL at which to poll (using GET) and will poll until the time passed is equal to or greater than
|
||||||
|
// the supplied duration. It will delay between requests for the duration specified in the
|
||||||
|
// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled by
|
||||||
|
// closing the optional channel on the http.Request.
|
||||||
|
func DoPollForStatusCodes(duration time.Duration, delay time.Duration, codes ...int) SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||||
|
resp, err = s.Do(r)
|
||||||
|
|
||||||
|
if err == nil && ResponseHasStatusCode(resp, codes...) {
|
||||||
|
r, err = NewPollingRequestWithContext(r.Context(), resp)
|
||||||
|
|
||||||
|
for err == nil && ResponseHasStatusCode(resp, codes...) {
|
||||||
|
Respond(resp,
|
||||||
|
ByDiscardingBody(),
|
||||||
|
ByClosing())
|
||||||
|
resp, err = SendWithSender(s, r,
|
||||||
|
AfterDelay(GetRetryAfter(resp, delay)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoRetryForAttempts returns a SendDecorator that retries a failed request for up to the specified
|
||||||
|
// number of attempts, exponentially backing off between requests using the supplied backoff
|
||||||
|
// time.Duration (which may be zero). Retrying may be canceled by closing the optional channel on
|
||||||
|
// the http.Request.
|
||||||
|
func DoRetryForAttempts(attempts int, backoff time.Duration) SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||||
|
rr := NewRetriableRequest(r)
|
||||||
|
for attempt := 0; attempt < attempts; attempt++ {
|
||||||
|
err = rr.Prepare()
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
resp, err = s.Do(rr.Request())
|
||||||
|
if err == nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
if !DelayForBackoff(backoff, attempt, r.Context().Done()) {
|
||||||
|
return nil, r.Context().Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoRetryForStatusCodes returns a SendDecorator that retries for specified statusCodes for up to the specified
|
||||||
|
// number of attempts, exponentially backing off between requests using the supplied backoff
|
||||||
|
// time.Duration (which may be zero). Retrying may be canceled by closing the optional channel on
|
||||||
|
// the http.Request.
|
||||||
|
func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||||
|
rr := NewRetriableRequest(r)
|
||||||
|
// Increment to add the first call (attempts denotes number of retries)
|
||||||
|
attempts++
|
||||||
|
for attempt := 0; attempt < attempts; {
|
||||||
|
err = rr.Prepare()
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
resp, err = s.Do(rr.Request())
|
||||||
|
// if the error isn't temporary don't bother retrying
|
||||||
|
if err != nil && !IsTemporaryNetworkError(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// we want to retry if err is not nil (e.g. transient network failure). note that for failed authentication
|
||||||
|
// resp and err will both have a value, so in this case we don't want to retry as it will never succeed.
|
||||||
|
if err == nil && !ResponseHasStatusCode(resp, codes...) || IsTokenRefreshError(err) {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
delayed := DelayWithRetryAfter(resp, r.Context().Done())
|
||||||
|
if !delayed && !DelayForBackoff(backoff, attempt, r.Context().Done()) {
|
||||||
|
return nil, r.Context().Err()
|
||||||
|
}
|
||||||
|
// don't count a 429 against the number of attempts
|
||||||
|
// so that we continue to retry until it succeeds
|
||||||
|
if resp == nil || resp.StatusCode != http.StatusTooManyRequests {
|
||||||
|
attempt++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelayWithRetryAfter invokes time.After for the duration specified in the "Retry-After" header in
|
||||||
|
// responses with status code 429
|
||||||
|
func DelayWithRetryAfter(resp *http.Response, cancel <-chan struct{}) bool {
|
||||||
|
if resp == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
retryAfter, _ := strconv.Atoi(resp.Header.Get("Retry-After"))
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests && retryAfter > 0 {
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Duration(retryAfter) * time.Second):
|
||||||
|
return true
|
||||||
|
case <-cancel:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoRetryForDuration returns a SendDecorator that retries the request until the total time is equal
|
||||||
|
// to or greater than the specified duration, exponentially backing off between requests using the
|
||||||
|
// supplied backoff time.Duration (which may be zero). Retrying may be canceled by closing the
|
||||||
|
// optional channel on the http.Request.
|
||||||
|
func DoRetryForDuration(d time.Duration, backoff time.Duration) SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
|
||||||
|
rr := NewRetriableRequest(r)
|
||||||
|
end := time.Now().Add(d)
|
||||||
|
for attempt := 0; time.Now().Before(end); attempt++ {
|
||||||
|
err = rr.Prepare()
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
resp, err = s.Do(rr.Request())
|
||||||
|
if err == nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
if !DelayForBackoff(backoff, attempt, r.Context().Done()) {
|
||||||
|
return nil, r.Context().Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLogging returns a SendDecorator that implements simple before and after logging of the
|
||||||
|
// request.
|
||||||
|
func WithLogging(logger *log.Logger) SendDecorator {
|
||||||
|
return func(s Sender) Sender {
|
||||||
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
|
logger.Printf("Sending %s %s", r.Method, r.URL)
|
||||||
|
resp, err := s.Do(r)
|
||||||
|
if err != nil {
|
||||||
|
logger.Printf("%s %s received error '%v'", r.Method, r.URL, err)
|
||||||
|
} else {
|
||||||
|
logger.Printf("%s %s received %s", r.Method, r.URL, resp.Status)
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelayForBackoff invokes time.After for the supplied backoff duration raised to the power of
|
||||||
|
// passed attempt (i.e., an exponential backoff delay). Backoff duration is in seconds and can set
|
||||||
|
// to zero for no delay. The delay may be canceled by closing the passed channel. If terminated early,
|
||||||
|
// returns false.
|
||||||
|
// Note: Passing attempt 1 will result in doubling "backoff" duration. Treat this as a zero-based attempt
|
||||||
|
// count.
|
||||||
|
func DelayForBackoff(backoff time.Duration, attempt int, cancel <-chan struct{}) bool {
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Duration(backoff.Seconds()*math.Pow(2, float64(attempt))) * time.Second):
|
||||||
|
return true
|
||||||
|
case <-cancel:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
147
vendor/github.com/Azure/go-autorest/autorest/to/convert.go
generated
vendored
Normal file
147
vendor/github.com/Azure/go-autorest/autorest/to/convert.go
generated
vendored
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
Package to provides helpers to ease working with pointer values of marshalled structures.
|
||||||
|
*/
|
||||||
|
package to
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// String returns a string value for the passed string pointer. It returns the empty string if the
|
||||||
|
// pointer is nil.
|
||||||
|
func String(s *string) string {
|
||||||
|
if s != nil {
|
||||||
|
return *s
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringPtr returns a pointer to the passed string.
|
||||||
|
func StringPtr(s string) *string {
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice returns a string slice value for the passed string slice pointer. It returns a nil
|
||||||
|
// slice if the pointer is nil.
|
||||||
|
func StringSlice(s *[]string) []string {
|
||||||
|
if s != nil {
|
||||||
|
return *s
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlicePtr returns a pointer to the passed string slice.
|
||||||
|
func StringSlicePtr(s []string) *[]string {
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringMap returns a map of strings built from the map of string pointers. The empty string is
|
||||||
|
// used for nil pointers.
|
||||||
|
func StringMap(msp map[string]*string) map[string]string {
|
||||||
|
ms := make(map[string]string, len(msp))
|
||||||
|
for k, sp := range msp {
|
||||||
|
if sp != nil {
|
||||||
|
ms[k] = *sp
|
||||||
|
} else {
|
||||||
|
ms[k] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringMapPtr returns a pointer to a map of string pointers built from the passed map of strings.
|
||||||
|
func StringMapPtr(ms map[string]string) *map[string]*string {
|
||||||
|
msp := make(map[string]*string, len(ms))
|
||||||
|
for k, s := range ms {
|
||||||
|
msp[k] = StringPtr(s)
|
||||||
|
}
|
||||||
|
return &msp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool returns a bool value for the passed bool pointer. It returns false if the pointer is nil.
|
||||||
|
func Bool(b *bool) bool {
|
||||||
|
if b != nil {
|
||||||
|
return *b
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolPtr returns a pointer to the passed bool.
|
||||||
|
func BoolPtr(b bool) *bool {
|
||||||
|
return &b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int returns an int value for the passed int pointer. It returns 0 if the pointer is nil.
|
||||||
|
func Int(i *int) int {
|
||||||
|
if i != nil {
|
||||||
|
return *i
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntPtr returns a pointer to the passed int.
|
||||||
|
func IntPtr(i int) *int {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32 returns an int value for the passed int pointer. It returns 0 if the pointer is nil.
|
||||||
|
func Int32(i *int32) int32 {
|
||||||
|
if i != nil {
|
||||||
|
return *i
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32Ptr returns a pointer to the passed int32.
|
||||||
|
func Int32Ptr(i int32) *int32 {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 returns an int value for the passed int pointer. It returns 0 if the pointer is nil.
|
||||||
|
func Int64(i *int64) int64 {
|
||||||
|
if i != nil {
|
||||||
|
return *i
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Ptr returns a pointer to the passed int64.
|
||||||
|
func Int64Ptr(i int64) *int64 {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32 returns an int value for the passed int pointer. It returns 0.0 if the pointer is nil.
|
||||||
|
func Float32(i *float32) float32 {
|
||||||
|
if i != nil {
|
||||||
|
return *i
|
||||||
|
}
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32Ptr returns a pointer to the passed float32.
|
||||||
|
func Float32Ptr(i float32) *float32 {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 returns an int value for the passed int pointer. It returns 0.0 if the pointer is nil.
|
||||||
|
func Float64(i *float64) float64 {
|
||||||
|
if i != nil {
|
||||||
|
return *i
|
||||||
|
}
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64Ptr returns a pointer to the passed float64.
|
||||||
|
func Float64Ptr(i float64) *float64 {
|
||||||
|
return &i
|
||||||
|
}
|
227
vendor/github.com/Azure/go-autorest/autorest/utility.go
generated
vendored
Normal file
227
vendor/github.com/Azure/go-autorest/autorest/utility.go
generated
vendored
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Azure/go-autorest/autorest/adal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EncodedAs is a series of constants specifying various data encodings
|
||||||
|
type EncodedAs string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// EncodedAsJSON states that data is encoded as JSON
|
||||||
|
EncodedAsJSON EncodedAs = "JSON"
|
||||||
|
|
||||||
|
// EncodedAsXML states that data is encoded as Xml
|
||||||
|
EncodedAsXML EncodedAs = "XML"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decoder defines the decoding method json.Decoder and xml.Decoder share
|
||||||
|
type Decoder interface {
|
||||||
|
Decode(v interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoder creates a new decoder appropriate to the passed encoding.
|
||||||
|
// encodedAs specifies the type of encoding and r supplies the io.Reader containing the
|
||||||
|
// encoded data.
|
||||||
|
func NewDecoder(encodedAs EncodedAs, r io.Reader) Decoder {
|
||||||
|
if encodedAs == EncodedAsJSON {
|
||||||
|
return json.NewDecoder(r)
|
||||||
|
} else if encodedAs == EncodedAsXML {
|
||||||
|
return xml.NewDecoder(r)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyAndDecode decodes the data from the passed io.Reader while making a copy. Having a copy
|
||||||
|
// is especially useful if there is a chance the data will fail to decode.
|
||||||
|
// encodedAs specifies the expected encoding, r provides the io.Reader to the data, and v
|
||||||
|
// is the decoding destination.
|
||||||
|
func CopyAndDecode(encodedAs EncodedAs, r io.Reader, v interface{}) (bytes.Buffer, error) {
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
return b, NewDecoder(encodedAs, io.TeeReader(r, &b)).Decode(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TeeReadCloser returns a ReadCloser that writes to w what it reads from rc.
|
||||||
|
// It utilizes io.TeeReader to copy the data read and has the same behavior when reading.
|
||||||
|
// Further, when it is closed, it ensures that rc is closed as well.
|
||||||
|
func TeeReadCloser(rc io.ReadCloser, w io.Writer) io.ReadCloser {
|
||||||
|
return &teeReadCloser{rc, io.TeeReader(rc, w)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type teeReadCloser struct {
|
||||||
|
rc io.ReadCloser
|
||||||
|
r io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *teeReadCloser) Read(p []byte) (int, error) {
|
||||||
|
return t.r.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *teeReadCloser) Close() error {
|
||||||
|
return t.rc.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsInt(ints []int, n int) bool {
|
||||||
|
for _, i := range ints {
|
||||||
|
if i == n {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func escapeValueStrings(m map[string]string) map[string]string {
|
||||||
|
for key, value := range m {
|
||||||
|
m[key] = url.QueryEscape(value)
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureValueStrings(mapOfInterface map[string]interface{}) map[string]string {
|
||||||
|
mapOfStrings := make(map[string]string)
|
||||||
|
for key, value := range mapOfInterface {
|
||||||
|
mapOfStrings[key] = ensureValueString(value)
|
||||||
|
}
|
||||||
|
return mapOfStrings
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureValueString(value interface{}) string {
|
||||||
|
if value == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch v := value.(type) {
|
||||||
|
case string:
|
||||||
|
return v
|
||||||
|
case []byte:
|
||||||
|
return string(v)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapToValues method converts map[string]interface{} to url.Values.
|
||||||
|
func MapToValues(m map[string]interface{}) url.Values {
|
||||||
|
v := url.Values{}
|
||||||
|
for key, value := range m {
|
||||||
|
x := reflect.ValueOf(value)
|
||||||
|
if x.Kind() == reflect.Array || x.Kind() == reflect.Slice {
|
||||||
|
for i := 0; i < x.Len(); i++ {
|
||||||
|
v.Add(key, ensureValueString(x.Index(i)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v.Add(key, ensureValueString(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsStringSlice method converts interface{} to []string. This expects a
|
||||||
|
//that the parameter passed to be a slice or array of a type that has the underlying
|
||||||
|
//type a string.
|
||||||
|
func AsStringSlice(s interface{}) ([]string, error) {
|
||||||
|
v := reflect.ValueOf(s)
|
||||||
|
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
|
||||||
|
return nil, NewError("autorest", "AsStringSlice", "the value's type is not an array.")
|
||||||
|
}
|
||||||
|
stringSlice := make([]string, 0, v.Len())
|
||||||
|
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
stringSlice = append(stringSlice, v.Index(i).String())
|
||||||
|
}
|
||||||
|
return stringSlice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String method converts interface v to string. If interface is a list, it
|
||||||
|
// joins list elements using the seperator. Note that only sep[0] will be used for
|
||||||
|
// joining if any separator is specified.
|
||||||
|
func String(v interface{}, sep ...string) string {
|
||||||
|
if len(sep) == 0 {
|
||||||
|
return ensureValueString(v)
|
||||||
|
}
|
||||||
|
stringSlice, ok := v.([]string)
|
||||||
|
if ok == false {
|
||||||
|
var err error
|
||||||
|
stringSlice, err = AsStringSlice(v)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("autorest: Couldn't convert value to a string %s.", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ensureValueString(strings.Join(stringSlice, sep[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode method encodes url path and query parameters.
|
||||||
|
func Encode(location string, v interface{}, sep ...string) string {
|
||||||
|
s := String(v, sep...)
|
||||||
|
switch strings.ToLower(location) {
|
||||||
|
case "path":
|
||||||
|
return pathEscape(s)
|
||||||
|
case "query":
|
||||||
|
return queryEscape(s)
|
||||||
|
default:
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pathEscape(s string) string {
|
||||||
|
return strings.Replace(url.QueryEscape(s), "+", "%20", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryEscape(s string) string {
|
||||||
|
return url.QueryEscape(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeToGet turns the specified http.Request into a GET (it assumes it wasn't).
|
||||||
|
// This is mainly useful for long-running operations that use the Azure-AsyncOperation
|
||||||
|
// header, so we change the initial PUT into a GET to retrieve the final result.
|
||||||
|
func ChangeToGet(req *http.Request) *http.Request {
|
||||||
|
req.Method = "GET"
|
||||||
|
req.Body = nil
|
||||||
|
req.ContentLength = 0
|
||||||
|
req.Header.Del("Content-Length")
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTokenRefreshError returns true if the specified error implements the TokenRefreshError
|
||||||
|
// interface. If err is a DetailedError it will walk the chain of Original errors.
|
||||||
|
func IsTokenRefreshError(err error) bool {
|
||||||
|
if _, ok := err.(adal.TokenRefreshError); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if de, ok := err.(DetailedError); ok {
|
||||||
|
return IsTokenRefreshError(de.Original)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTemporaryNetworkError returns true if the specified error is a temporary network error.
|
||||||
|
func IsTemporaryNetworkError(err error) bool {
|
||||||
|
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
20
vendor/github.com/Azure/go-autorest/autorest/version.go
generated
vendored
Normal file
20
vendor/github.com/Azure/go-autorest/autorest/version.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package autorest
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Version returns the semantic version (see http://semver.org).
|
||||||
|
func Version() string {
|
||||||
|
return "v10.9.0"
|
||||||
|
}
|
22
vendor/github.com/JamesClonk/vultr/LICENSE
generated
vendored
Normal file
22
vendor/github.com/JamesClonk/vultr/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Fabio Berchtold
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
71
vendor/github.com/JamesClonk/vultr/lib/account_info.go
generated
vendored
Normal file
71
vendor/github.com/JamesClonk/vultr/lib/account_info.go
generated
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccountInfo of Vultr account
|
||||||
|
type AccountInfo struct {
|
||||||
|
Balance float64 `json:"balance"`
|
||||||
|
PendingCharges float64 `json:"pending_charges"`
|
||||||
|
LastPaymentDate string `json:"last_payment_date"`
|
||||||
|
LastPaymentAmount float64 `json:"last_payment_amount"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccountInfo retrieves the Vultr account information about current balance, pending charges, etc..
|
||||||
|
func (c *Client) GetAccountInfo() (info AccountInfo, err error) {
|
||||||
|
if err := c.get(`account/info`, &info); err != nil {
|
||||||
|
return AccountInfo{}, err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaller on AccountInfo.
|
||||||
|
// This is needed because the Vultr API is inconsistent in it's JSON responses for account info.
|
||||||
|
// Some fields can change type, from JSON number to JSON string and vice-versa.
|
||||||
|
func (a *AccountInfo) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
if a == nil {
|
||||||
|
*a = AccountInfo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &fields); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := fmt.Sprintf("%v", fields["balance"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
b, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.Balance = b
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["pending_charges"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
pc, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.PendingCharges = pc
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["last_payment_amount"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
lpa, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.LastPaymentAmount = lpa
|
||||||
|
|
||||||
|
a.LastPaymentDate = fmt.Sprintf("%v", fields["last_payment_date"])
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
38
vendor/github.com/JamesClonk/vultr/lib/applications.go
generated
vendored
Normal file
38
vendor/github.com/JamesClonk/vultr/lib/applications.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Application on Vultr
|
||||||
|
type Application struct {
|
||||||
|
ID string `json:"APPID"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
ShortName string `json:"short_name"`
|
||||||
|
DeployName string `json:"deploy_name"`
|
||||||
|
Surcharge float64 `json:"surcharge"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type applications []Application
|
||||||
|
|
||||||
|
func (s applications) Len() int { return len(s) }
|
||||||
|
func (s applications) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s applications) Less(i, j int) bool {
|
||||||
|
return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetApplications returns a list of all available applications on Vultr
|
||||||
|
func (c *Client) GetApplications() ([]Application, error) {
|
||||||
|
var appMap map[string]Application
|
||||||
|
if err := c.get(`app/list`, &appMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var appList []Application
|
||||||
|
for _, app := range appMap {
|
||||||
|
appList = append(appList, app)
|
||||||
|
}
|
||||||
|
sort.Sort(applications(appList))
|
||||||
|
return appList, nil
|
||||||
|
}
|
210
vendor/github.com/JamesClonk/vultr/lib/block_storage.go
generated
vendored
Normal file
210
vendor/github.com/JamesClonk/vultr/lib/block_storage.go
generated
vendored
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BlockStorage on Vultr account
|
||||||
|
type BlockStorage struct {
|
||||||
|
ID string `json:"SUBID,string"`
|
||||||
|
Name string `json:"label"`
|
||||||
|
RegionID int `json:"DCID,string"`
|
||||||
|
SizeGB int `json:"size_gb,string"`
|
||||||
|
Created string `json:"date_created"`
|
||||||
|
Cost string `json:"cost_per_month"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
AttachedTo string `json:"attached_to_SUBID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type blockstorages []BlockStorage
|
||||||
|
|
||||||
|
func (b blockstorages) Len() int { return len(b) }
|
||||||
|
func (b blockstorages) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||||
|
func (b blockstorages) Less(i, j int) bool {
|
||||||
|
// sort order: name, size, status
|
||||||
|
if strings.ToLower(b[i].Name) < strings.ToLower(b[j].Name) {
|
||||||
|
return true
|
||||||
|
} else if strings.ToLower(b[i].Name) > strings.ToLower(b[j].Name) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if b[i].SizeGB < b[j].SizeGB {
|
||||||
|
return true
|
||||||
|
} else if b[i].SizeGB > b[j].SizeGB {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return b[i].Status < b[j].Status
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaller on BlockStorage.
|
||||||
|
// This is needed because the Vultr API is inconsistent in it's JSON responses.
|
||||||
|
// Some fields can change type, from JSON number to JSON string and vice-versa.
|
||||||
|
func (b *BlockStorage) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
if b == nil {
|
||||||
|
*b = BlockStorage{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &fields); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := fmt.Sprintf("%v", fields["SUBID"])
|
||||||
|
if len(value) == 0 || value == "<nil>" || value == "0" {
|
||||||
|
b.ID = ""
|
||||||
|
} else {
|
||||||
|
id, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.ID = strconv.FormatFloat(id, 'f', -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["DCID"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
region, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.RegionID = int(region)
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["size_gb"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
size, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.SizeGB = int(size)
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["attached_to_SUBID"])
|
||||||
|
if len(value) == 0 || value == "<nil>" || value == "0" {
|
||||||
|
b.AttachedTo = ""
|
||||||
|
} else {
|
||||||
|
attached, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.AttachedTo = strconv.FormatFloat(attached, 'f', -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Name = fmt.Sprintf("%v", fields["label"])
|
||||||
|
b.Created = fmt.Sprintf("%v", fields["date_created"])
|
||||||
|
b.Status = fmt.Sprintf("%v", fields["status"])
|
||||||
|
b.Cost = fmt.Sprintf("%v", fields["cost_per_month"])
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockStorages returns a list of all active block storages on Vultr account
|
||||||
|
func (c *Client) GetBlockStorages() (storages []BlockStorage, err error) {
|
||||||
|
if err := c.get(`block/list`, &storages); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sort.Sort(blockstorages(storages))
|
||||||
|
return storages, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockStorage returns block storage with given ID
|
||||||
|
func (c *Client) GetBlockStorage(id string) (BlockStorage, error) {
|
||||||
|
storages, err := c.GetBlockStorages()
|
||||||
|
if err != nil {
|
||||||
|
return BlockStorage{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range storages {
|
||||||
|
if s.ID == id {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BlockStorage{}, fmt.Errorf("BlockStorage with ID %v not found", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateBlockStorage creates a new block storage on Vultr account
|
||||||
|
func (c *Client) CreateBlockStorage(name string, regionID, size int) (BlockStorage, error) {
|
||||||
|
values := url.Values{
|
||||||
|
"label": {name},
|
||||||
|
"DCID": {fmt.Sprintf("%v", regionID)},
|
||||||
|
"size_gb": {fmt.Sprintf("%v", size)},
|
||||||
|
}
|
||||||
|
|
||||||
|
var storage BlockStorage
|
||||||
|
if err := c.post(`block/create`, values, &storage); err != nil {
|
||||||
|
return BlockStorage{}, err
|
||||||
|
}
|
||||||
|
storage.RegionID = regionID
|
||||||
|
storage.Name = name
|
||||||
|
storage.SizeGB = size
|
||||||
|
|
||||||
|
return storage, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResizeBlockStorage resizes an existing block storage
|
||||||
|
func (c *Client) ResizeBlockStorage(id string, size int) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"size_gb": {fmt.Sprintf("%v", size)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`block/resize`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LabelBlockStorage changes the label on an existing block storage
|
||||||
|
func (c *Client) LabelBlockStorage(id, name string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"label": {name},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`block/label_set`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AttachBlockStorage attaches block storage to an existing virtual machine
|
||||||
|
func (c *Client) AttachBlockStorage(id, serverID string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"attach_to_SUBID": {serverID},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`block/attach`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetachBlockStorage detaches block storage from virtual machine
|
||||||
|
func (c *Client) DetachBlockStorage(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`block/detach`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBlockStorage deletes an existing block storage
|
||||||
|
func (c *Client) DeleteBlockStorage(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`block/delete`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
258
vendor/github.com/JamesClonk/vultr/lib/client.go
generated
vendored
Normal file
258
vendor/github.com/JamesClonk/vultr/lib/client.go
generated
vendored
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/juju/ratelimit"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Version of this libary
|
||||||
|
Version = "1.15.0"
|
||||||
|
|
||||||
|
// APIVersion of Vultr
|
||||||
|
APIVersion = "v1"
|
||||||
|
|
||||||
|
// DefaultEndpoint to be used
|
||||||
|
DefaultEndpoint = "https://api.vultr.com/"
|
||||||
|
|
||||||
|
mediaType = "application/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// retryableStatusCodes are API response status codes that indicate that
|
||||||
|
// the failed request can be retried without further actions.
|
||||||
|
var retryableStatusCodes = map[int]struct{}{
|
||||||
|
503: {}, // Rate limit hit
|
||||||
|
500: {}, // Internal server error. Try again at a later time.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client represents the Vultr API client
|
||||||
|
type Client struct {
|
||||||
|
// HTTP client for communication with the Vultr API
|
||||||
|
client *http.Client
|
||||||
|
|
||||||
|
// User agent for HTTP client
|
||||||
|
UserAgent string
|
||||||
|
|
||||||
|
// Endpoint URL for API requests
|
||||||
|
Endpoint *url.URL
|
||||||
|
|
||||||
|
// API key for accessing the Vultr API
|
||||||
|
APIKey string
|
||||||
|
|
||||||
|
// Max. number of request attempts
|
||||||
|
MaxAttempts int
|
||||||
|
|
||||||
|
// Throttling struct
|
||||||
|
bucket *ratelimit.Bucket
|
||||||
|
|
||||||
|
// Optional function called after every successful request made to the API
|
||||||
|
onRequestCompleted RequestCompletionCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestCompletionCallback defines the type of the request callback function
|
||||||
|
type RequestCompletionCallback func(*http.Request, *http.Response)
|
||||||
|
|
||||||
|
// Options represents optional settings and flags that can be passed to NewClient
|
||||||
|
type Options struct {
|
||||||
|
// HTTP client for communication with the Vultr API
|
||||||
|
HTTPClient *http.Client
|
||||||
|
|
||||||
|
// User agent for HTTP client
|
||||||
|
UserAgent string
|
||||||
|
|
||||||
|
// Endpoint URL for API requests
|
||||||
|
Endpoint string
|
||||||
|
|
||||||
|
// API rate limitation, calls per duration
|
||||||
|
RateLimitation time.Duration
|
||||||
|
|
||||||
|
// Max. number of times to retry API calls
|
||||||
|
MaxRetries int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient creates new Vultr API client. Options are optional and can be nil.
|
||||||
|
func NewClient(apiKey string, options *Options) *Client {
|
||||||
|
userAgent := "vultr-go/" + Version
|
||||||
|
transport := &http.Transport{
|
||||||
|
TLSNextProto: make(map[string]func(string, *tls.Conn) http.RoundTripper),
|
||||||
|
}
|
||||||
|
client := http.DefaultClient
|
||||||
|
client.Transport = transport
|
||||||
|
endpoint, _ := url.Parse(DefaultEndpoint)
|
||||||
|
rate := 505 * time.Millisecond
|
||||||
|
attempts := 1
|
||||||
|
|
||||||
|
if options != nil {
|
||||||
|
if options.HTTPClient != nil {
|
||||||
|
client = options.HTTPClient
|
||||||
|
}
|
||||||
|
if options.UserAgent != "" {
|
||||||
|
userAgent = options.UserAgent
|
||||||
|
}
|
||||||
|
if options.Endpoint != "" {
|
||||||
|
endpoint, _ = url.Parse(options.Endpoint)
|
||||||
|
}
|
||||||
|
if options.RateLimitation != 0 {
|
||||||
|
rate = options.RateLimitation
|
||||||
|
}
|
||||||
|
if options.MaxRetries != 0 {
|
||||||
|
attempts = options.MaxRetries + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
UserAgent: userAgent,
|
||||||
|
client: client,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
APIKey: apiKey,
|
||||||
|
MaxAttempts: attempts,
|
||||||
|
bucket: ratelimit.NewBucket(rate, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiPath(path string) string {
|
||||||
|
return fmt.Sprintf("/%s/%s", APIVersion, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) get(path string, data interface{}) error {
|
||||||
|
req, err := c.newRequest("GET", apiPath(path), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.do(req, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) post(path string, values url.Values, data interface{}) error {
|
||||||
|
req, err := c.newRequest("POST", apiPath(path), strings.NewReader(values.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.do(req, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnRequestCompleted sets the API request completion callback
|
||||||
|
func (c *Client) OnRequestCompleted(rc RequestCompletionCallback) {
|
||||||
|
c.onRequestCompleted = rc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) newRequest(method string, path string, body io.Reader) (*http.Request, error) {
|
||||||
|
relPath, err := url.Parse(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
url := c.Endpoint.ResolveReference(relPath)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, url.String(), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("API-Key", c.APIKey)
|
||||||
|
req.Header.Add("User-Agent", c.UserAgent)
|
||||||
|
req.Header.Add("Accept", mediaType)
|
||||||
|
|
||||||
|
if req.Method == "POST" {
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) do(req *http.Request, data interface{}) error {
|
||||||
|
// Throttle http requests to avoid hitting Vultr's API rate-limit
|
||||||
|
c.bucket.Wait(1)
|
||||||
|
|
||||||
|
// Request body gets drained on each read so we
|
||||||
|
// need to save it's content for retrying requests
|
||||||
|
var err error
|
||||||
|
var requestBody []byte
|
||||||
|
if req.Body != nil {
|
||||||
|
requestBody, err = ioutil.ReadAll(req.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error reading request body: %v", err)
|
||||||
|
}
|
||||||
|
req.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiError error
|
||||||
|
for tryCount := 1; tryCount <= c.MaxAttempts; tryCount++ {
|
||||||
|
// Restore request body to the original state
|
||||||
|
if requestBody != nil {
|
||||||
|
req.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.onRequestCompleted != nil {
|
||||||
|
c.onRequestCompleted(req, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
if data != nil {
|
||||||
|
// avoid unmarshalling problem because Vultr API returns
|
||||||
|
// empty array instead of empty map when it shouldn't!
|
||||||
|
if string(body) == `[]` {
|
||||||
|
data = nil
|
||||||
|
} else {
|
||||||
|
if err := json.Unmarshal(body, data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
apiError = errors.New(string(body))
|
||||||
|
if !isCodeRetryable(resp.StatusCode) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
delay := backoffDuration(tryCount)
|
||||||
|
time.Sleep(delay)
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiError
|
||||||
|
}
|
||||||
|
|
||||||
|
// backoffDuration returns the duration to wait before retrying the request.
|
||||||
|
// Duration is an exponential function of the retry count with a jitter of ~0-30%.
|
||||||
|
func backoffDuration(retryCount int) time.Duration {
|
||||||
|
// Upper limit of delay at ~1 minute
|
||||||
|
if retryCount > 7 {
|
||||||
|
retryCount = 7
|
||||||
|
}
|
||||||
|
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
delay := (1 << uint(retryCount)) * (rand.Intn(150) + 500)
|
||||||
|
return time.Duration(delay) * time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
|
// isCodeRetryable returns true if the given status code means that we should retry.
|
||||||
|
func isCodeRetryable(statusCode int) bool {
|
||||||
|
if _, ok := retryableStatusCodes[statusCode]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
150
vendor/github.com/JamesClonk/vultr/lib/dns.go
generated
vendored
Normal file
150
vendor/github.com/JamesClonk/vultr/lib/dns.go
generated
vendored
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DNSDomain represents a DNS domain on Vultr
|
||||||
|
type DNSDomain struct {
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
Created string `json:"date_created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type dnsdomains []DNSDomain
|
||||||
|
|
||||||
|
func (d dnsdomains) Len() int { return len(d) }
|
||||||
|
func (d dnsdomains) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||||
|
func (d dnsdomains) Less(i, j int) bool {
|
||||||
|
return strings.ToLower(d[i].Domain) < strings.ToLower(d[j].Domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSRecord represents a DNS record on Vultr
|
||||||
|
type DNSRecord struct {
|
||||||
|
RecordID int `json:"RECORDID"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
TTL int `json:"ttl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type dnsrecords []DNSRecord
|
||||||
|
|
||||||
|
func (d dnsrecords) Len() int { return len(d) }
|
||||||
|
func (d dnsrecords) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||||
|
func (d dnsrecords) Less(i, j int) bool {
|
||||||
|
// sort order: type, data, name
|
||||||
|
if d[i].Type < d[j].Type {
|
||||||
|
return true
|
||||||
|
} else if d[i].Type > d[j].Type {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if d[i].Data < d[j].Data {
|
||||||
|
return true
|
||||||
|
} else if d[i].Data > d[j].Data {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return strings.ToLower(d[i].Name) < strings.ToLower(d[j].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDNSDomains returns a list of available domains on Vultr account
|
||||||
|
func (c *Client) GetDNSDomains() (domains []DNSDomain, err error) {
|
||||||
|
if err := c.get(`dns/list`, &domains); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sort.Sort(dnsdomains(domains))
|
||||||
|
return domains, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDNSRecords returns a list of all DNS records of a particular domain
|
||||||
|
func (c *Client) GetDNSRecords(domain string) (records []DNSRecord, err error) {
|
||||||
|
if err := c.get(`dns/records?domain=`+domain, &records); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sort.Sort(dnsrecords(records))
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateDNSDomain creates a new DNS domain name on Vultr
|
||||||
|
func (c *Client) CreateDNSDomain(domain, serverIP string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"domain": {domain},
|
||||||
|
"serverip": {serverIP},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`dns/create_domain`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDNSDomain deletes an existing DNS domain name
|
||||||
|
func (c *Client) DeleteDNSDomain(domain string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"domain": {domain},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`dns/delete_domain`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateDNSRecord creates a new DNS record
|
||||||
|
func (c *Client) CreateDNSRecord(domain, name, rtype, data string, priority, ttl int) error {
|
||||||
|
values := url.Values{
|
||||||
|
"domain": {domain},
|
||||||
|
"name": {name},
|
||||||
|
"type": {rtype},
|
||||||
|
"data": {data},
|
||||||
|
"priority": {fmt.Sprintf("%v", priority)},
|
||||||
|
"ttl": {fmt.Sprintf("%v", ttl)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`dns/create_record`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDNSRecord updates an existing DNS record
|
||||||
|
func (c *Client) UpdateDNSRecord(domain string, dnsrecord DNSRecord) error {
|
||||||
|
values := url.Values{
|
||||||
|
"domain": {domain},
|
||||||
|
"RECORDID": {fmt.Sprintf("%v", dnsrecord.RecordID)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if dnsrecord.Name != "" {
|
||||||
|
values.Add("name", dnsrecord.Name)
|
||||||
|
}
|
||||||
|
if dnsrecord.Data != "" {
|
||||||
|
values.Add("data", dnsrecord.Data)
|
||||||
|
}
|
||||||
|
if dnsrecord.Priority != 0 {
|
||||||
|
values.Add("priority", fmt.Sprintf("%v", dnsrecord.Priority))
|
||||||
|
}
|
||||||
|
if dnsrecord.TTL != 0 {
|
||||||
|
values.Add("ttl", fmt.Sprintf("%v", dnsrecord.TTL))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`dns/update_record`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDNSRecord deletes an existing DNS record
|
||||||
|
func (c *Client) DeleteDNSRecord(domain string, recordID int) error {
|
||||||
|
values := url.Values{
|
||||||
|
"domain": {domain},
|
||||||
|
"RECORDID": {fmt.Sprintf("%v", recordID)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`dns/delete_record`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
252
vendor/github.com/JamesClonk/vultr/lib/firewall.go
generated
vendored
Normal file
252
vendor/github.com/JamesClonk/vultr/lib/firewall.go
generated
vendored
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FirewallGroup represents a firewall group on Vultr
|
||||||
|
type FirewallGroup struct {
|
||||||
|
ID string `json:"FIREWALLGROUPID"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Created string `json:"date_created"`
|
||||||
|
Modified string `json:"date_modified"`
|
||||||
|
InstanceCount int `json:"instance_count"`
|
||||||
|
RuleCount int `json:"rule_count"`
|
||||||
|
MaxRuleCount int `json:"max_rule_count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FirewallRule represents a firewall rule on Vultr
|
||||||
|
type FirewallRule struct {
|
||||||
|
RuleNumber int `json:"rulenumber"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
Port string `json:"port"`
|
||||||
|
Network *net.IPNet
|
||||||
|
}
|
||||||
|
|
||||||
|
type firewallGroups []FirewallGroup
|
||||||
|
|
||||||
|
func (f firewallGroups) Len() int { return len(f) }
|
||||||
|
func (f firewallGroups) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
|
||||||
|
func (f firewallGroups) Less(i, j int) bool {
|
||||||
|
// sort order: description
|
||||||
|
return strings.ToLower(f[i].Description) < strings.ToLower(f[j].Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
type firewallRules []FirewallRule
|
||||||
|
|
||||||
|
func (r firewallRules) Len() int { return len(r) }
|
||||||
|
func (r firewallRules) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||||
|
func (r firewallRules) Less(i, j int) bool {
|
||||||
|
// sort order: rule number
|
||||||
|
return r[i].RuleNumber < r[j].RuleNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaller on FirewallRule.
|
||||||
|
// This is needed because the Vultr API is inconsistent in it's JSON responses.
|
||||||
|
// Some fields can change type, from JSON number to JSON string and vice-versa.
|
||||||
|
func (r *FirewallRule) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
if r == nil {
|
||||||
|
*r = FirewallRule{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &fields); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := fmt.Sprintf("%v", fields["rulenumber"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
number, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.RuleNumber = int(number)
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["subnet_size"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
subnetSize, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Action = fmt.Sprintf("%v", fields["action"])
|
||||||
|
r.Protocol = fmt.Sprintf("%v", fields["protocol"])
|
||||||
|
r.Port = fmt.Sprintf("%v", fields["port"])
|
||||||
|
subnet := fmt.Sprintf("%v", fields["subnet"])
|
||||||
|
if subnet == "<nil>" {
|
||||||
|
subnet = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(subnet) > 0 {
|
||||||
|
_, r.Network, err = net.ParseCIDR(fmt.Sprintf("%s/%d", subnet, subnetSize))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to parse subnet from Vultr API")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This case is used to create a valid default CIDR when the Vultr API does not return a subnet/subnet size at all, e.g. the response after creating a new rule.
|
||||||
|
_, r.Network, _ = net.ParseCIDR("0.0.0.0/0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFirewallGroups returns a list of all available firewall groups on Vultr
|
||||||
|
func (c *Client) GetFirewallGroups() ([]FirewallGroup, error) {
|
||||||
|
var groupMap map[string]FirewallGroup
|
||||||
|
if err := c.get(`firewall/group_list`, &groupMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var groupList []FirewallGroup
|
||||||
|
for _, g := range groupMap {
|
||||||
|
groupList = append(groupList, g)
|
||||||
|
}
|
||||||
|
sort.Sort(firewallGroups(groupList))
|
||||||
|
return groupList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFirewallGroup returns the firewall group with given ID
|
||||||
|
func (c *Client) GetFirewallGroup(id string) (FirewallGroup, error) {
|
||||||
|
groups, err := c.GetFirewallGroups()
|
||||||
|
if err != nil {
|
||||||
|
return FirewallGroup{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, g := range groups {
|
||||||
|
if g.ID == id {
|
||||||
|
return g, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FirewallGroup{}, fmt.Errorf("Firewall group with ID %v not found", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateFirewallGroup creates a new firewall group in Vultr account
|
||||||
|
func (c *Client) CreateFirewallGroup(description string) (string, error) {
|
||||||
|
values := url.Values{}
|
||||||
|
|
||||||
|
// Optional description
|
||||||
|
if len(description) > 0 {
|
||||||
|
values.Add("description", description)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result FirewallGroup
|
||||||
|
err := c.post(`firewall/group_create`, values, &result)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result.ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteFirewallGroup deletes an existing firewall group
|
||||||
|
func (c *Client) DeleteFirewallGroup(groupID string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"FIREWALLGROUPID": {groupID},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`firewall/group_delete`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFirewallGroupDescription sets the description of an existing firewall group
|
||||||
|
func (c *Client) SetFirewallGroupDescription(groupID, description string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"FIREWALLGROUPID": {groupID},
|
||||||
|
"description": {description},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`firewall/group_set_description`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFirewallRules returns a list of rules for the given firewall group
|
||||||
|
func (c *Client) GetFirewallRules(groupID string) ([]FirewallRule, error) {
|
||||||
|
var ruleMap map[string]FirewallRule
|
||||||
|
ipTypes := []string{"v4", "v6"}
|
||||||
|
for _, ipType := range ipTypes {
|
||||||
|
args := fmt.Sprintf("direction=in&FIREWALLGROUPID=%s&ip_type=%s",
|
||||||
|
groupID, ipType)
|
||||||
|
if err := c.get(`firewall/rule_list?`+args, &ruleMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ruleList []FirewallRule
|
||||||
|
for _, r := range ruleMap {
|
||||||
|
ruleList = append(ruleList, r)
|
||||||
|
}
|
||||||
|
sort.Sort(firewallRules(ruleList))
|
||||||
|
return ruleList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateFirewallRule creates a new firewall rule in Vultr account.
|
||||||
|
// groupID is the ID of the firewall group to create the rule in
|
||||||
|
// protocol must be one of: "icmp", "tcp", "udp", "gre"
|
||||||
|
// port can be a port number or colon separated port range (TCP/UDP only)
|
||||||
|
func (c *Client) CreateFirewallRule(groupID, protocol, port string,
|
||||||
|
network *net.IPNet) (int, error) {
|
||||||
|
ip := network.IP.String()
|
||||||
|
maskBits, _ := network.Mask.Size()
|
||||||
|
if ip == "<nil>" {
|
||||||
|
return 0, fmt.Errorf("Invalid network")
|
||||||
|
}
|
||||||
|
|
||||||
|
var ipType string
|
||||||
|
if network.IP.To4() != nil {
|
||||||
|
ipType = "v4"
|
||||||
|
} else {
|
||||||
|
ipType = "v6"
|
||||||
|
}
|
||||||
|
|
||||||
|
values := url.Values{
|
||||||
|
"FIREWALLGROUPID": {groupID},
|
||||||
|
// possible values: "in"
|
||||||
|
"direction": {"in"},
|
||||||
|
// possible values: "icmp", "tcp", "udp", "gre"
|
||||||
|
"protocol": {protocol},
|
||||||
|
// possible values: "v4", "v6"
|
||||||
|
"ip_type": {ipType},
|
||||||
|
// IP address representing a subnet
|
||||||
|
"subnet": {ip},
|
||||||
|
// IP prefix size in bits
|
||||||
|
"subnet_size": {fmt.Sprintf("%v", maskBits)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(port) > 0 {
|
||||||
|
values.Add("port", port)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result FirewallRule
|
||||||
|
err := c.post(`firewall/rule_create`, values, &result)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return result.RuleNumber, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteFirewallRule deletes an existing firewall rule
|
||||||
|
func (c *Client) DeleteFirewallRule(ruleNumber int, groupID string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"FIREWALLGROUPID": {groupID},
|
||||||
|
"rulenumber": {fmt.Sprintf("%v", ruleNumber)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`firewall/rule_delete`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
192
vendor/github.com/JamesClonk/vultr/lib/ip.go
generated
vendored
Normal file
192
vendor/github.com/JamesClonk/vultr/lib/ip.go
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IPv4 information of a virtual machine
|
||||||
|
type IPv4 struct {
|
||||||
|
IP string `json:"ip"`
|
||||||
|
Netmask string `json:"netmask"`
|
||||||
|
Gateway string `json:"gateway"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
ReverseDNS string `json:"reverse"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ipv4s []IPv4
|
||||||
|
|
||||||
|
func (s ipv4s) Len() int { return len(s) }
|
||||||
|
func (s ipv4s) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s ipv4s) Less(i, j int) bool {
|
||||||
|
// sort order: type, ip
|
||||||
|
if s[i].Type < s[j].Type {
|
||||||
|
return true
|
||||||
|
} else if s[i].Type > s[j].Type {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s[i].IP < s[j].IP
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPv6 information of a virtual machine
|
||||||
|
type IPv6 struct {
|
||||||
|
IP string `json:"ip"`
|
||||||
|
Network string `json:"network"`
|
||||||
|
NetworkSize string `json:"network_size"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ipv6s []IPv6
|
||||||
|
|
||||||
|
func (s ipv6s) Len() int { return len(s) }
|
||||||
|
func (s ipv6s) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s ipv6s) Less(i, j int) bool {
|
||||||
|
// sort order: type, ip
|
||||||
|
if s[i].Type < s[j].Type {
|
||||||
|
return true
|
||||||
|
} else if s[i].Type > s[j].Type {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s[i].IP < s[j].IP
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReverseDNSIPv6 information of a virtual machine
|
||||||
|
type ReverseDNSIPv6 struct {
|
||||||
|
IP string `json:"ip"`
|
||||||
|
ReverseDNS string `json:"reverse"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type reverseDNSIPv6s []ReverseDNSIPv6
|
||||||
|
|
||||||
|
func (s reverseDNSIPv6s) Len() int { return len(s) }
|
||||||
|
func (s reverseDNSIPv6s) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s reverseDNSIPv6s) Less(i, j int) bool { return s[i].IP < s[j].IP }
|
||||||
|
|
||||||
|
// ListIPv4 lists the IPv4 information of a virtual machine
|
||||||
|
func (c *Client) ListIPv4(id string) (list []IPv4, err error) {
|
||||||
|
var ipMap map[string][]IPv4
|
||||||
|
if err := c.get(`server/list_ipv4?SUBID=`+id, &ipMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, iplist := range ipMap {
|
||||||
|
for _, ip := range iplist {
|
||||||
|
list = append(list, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Sort(ipv4s(list))
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIPv4 creates an IPv4 address and attaches it to a virtual machine
|
||||||
|
func (c *Client) CreateIPv4(id string, reboot bool) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"reboot": {fmt.Sprintf("%t", reboot)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/create_ipv4`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIPv4 deletes an IPv4 address and detaches it from a virtual machine
|
||||||
|
func (c *Client) DeleteIPv4(id, ip string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"ip": {ip},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/destroy_ipv4`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListIPv6 lists the IPv4 information of a virtual machine
|
||||||
|
func (c *Client) ListIPv6(id string) (list []IPv6, err error) {
|
||||||
|
var ipMap map[string][]IPv6
|
||||||
|
if err := c.get(`server/list_ipv6?SUBID=`+id, &ipMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, iplist := range ipMap {
|
||||||
|
for _, ip := range iplist {
|
||||||
|
list = append(list, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Sort(ipv6s(list))
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListIPv6ReverseDNS lists the IPv6 reverse DNS entries of a virtual machine
|
||||||
|
func (c *Client) ListIPv6ReverseDNS(id string) (list []ReverseDNSIPv6, err error) {
|
||||||
|
var ipMap map[string][]ReverseDNSIPv6
|
||||||
|
if err := c.get(`server/reverse_list_ipv6?SUBID=`+id, &ipMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, iplist := range ipMap {
|
||||||
|
for _, ip := range iplist {
|
||||||
|
list = append(list, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Sort(reverseDNSIPv6s(list))
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIPv6ReverseDNS removes a reverse DNS entry for an IPv6 address of a virtual machine
|
||||||
|
func (c *Client) DeleteIPv6ReverseDNS(id string, ip string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"ip": {ip},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/reverse_delete_ipv6`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIPv6ReverseDNS sets a reverse DNS entry for an IPv6 address of a virtual machine
|
||||||
|
func (c *Client) SetIPv6ReverseDNS(id, ip, entry string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"ip": {ip},
|
||||||
|
"entry": {entry},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/reverse_set_ipv6`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultIPv4ReverseDNS sets a reverse DNS entry for an IPv4 address of a virtual machine to the original setting
|
||||||
|
func (c *Client) DefaultIPv4ReverseDNS(id, ip string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"ip": {ip},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/reverse_default_ipv4`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIPv4ReverseDNS sets a reverse DNS entry for an IPv4 address of a virtual machine
|
||||||
|
func (c *Client) SetIPv4ReverseDNS(id, ip, entry string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"ip": {ip},
|
||||||
|
"entry": {entry},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/reverse_set_ipv4`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
44
vendor/github.com/JamesClonk/vultr/lib/iso.go
generated
vendored
Normal file
44
vendor/github.com/JamesClonk/vultr/lib/iso.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ISO image on Vultr
|
||||||
|
type ISO struct {
|
||||||
|
ID int `json:"ISOID"`
|
||||||
|
Created string `json:"date_created"`
|
||||||
|
Filename string `json:"filename"`
|
||||||
|
Size int `json:"size"`
|
||||||
|
MD5sum string `json:"md5sum"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type isos []ISO
|
||||||
|
|
||||||
|
func (s isos) Len() int { return len(s) }
|
||||||
|
func (s isos) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s isos) Less(i, j int) bool {
|
||||||
|
// sort order: filename, created
|
||||||
|
if strings.ToLower(s[i].Filename) < strings.ToLower(s[j].Filename) {
|
||||||
|
return true
|
||||||
|
} else if strings.ToLower(s[i].Filename) > strings.ToLower(s[j].Filename) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s[i].Created < s[j].Created
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetISO returns a list of all ISO images on Vultr account
|
||||||
|
func (c *Client) GetISO() ([]ISO, error) {
|
||||||
|
var isoMap map[string]ISO
|
||||||
|
if err := c.get(`iso/list`, &isoMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var isoList []ISO
|
||||||
|
for _, iso := range isoMap {
|
||||||
|
isoList = append(isoList, iso)
|
||||||
|
}
|
||||||
|
sort.Sort(isos(isoList))
|
||||||
|
return isoList, nil
|
||||||
|
}
|
37
vendor/github.com/JamesClonk/vultr/lib/os.go
generated
vendored
Normal file
37
vendor/github.com/JamesClonk/vultr/lib/os.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OS image on Vultr
|
||||||
|
type OS struct {
|
||||||
|
ID int `json:"OSID"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Arch string `json:"arch"`
|
||||||
|
Family string `json:"family"`
|
||||||
|
Windows bool `json:"windows"`
|
||||||
|
Surcharge string `json:"surcharge"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type oses []OS
|
||||||
|
|
||||||
|
func (s oses) Len() int { return len(s) }
|
||||||
|
func (s oses) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s oses) Less(i, j int) bool { return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) }
|
||||||
|
|
||||||
|
// GetOS returns a list of all available operating systems on Vultr
|
||||||
|
func (c *Client) GetOS() ([]OS, error) {
|
||||||
|
var osMap map[string]OS
|
||||||
|
if err := c.get(`os/list`, &osMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var osList []OS
|
||||||
|
for _, os := range osMap {
|
||||||
|
osList = append(osList, os)
|
||||||
|
}
|
||||||
|
sort.Sort(oses(osList))
|
||||||
|
return osList, nil
|
||||||
|
}
|
78
vendor/github.com/JamesClonk/vultr/lib/plans.go
generated
vendored
Normal file
78
vendor/github.com/JamesClonk/vultr/lib/plans.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Plan on Vultr
|
||||||
|
type Plan struct {
|
||||||
|
ID int `json:"VPSPLANID,string"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
VCpus int `json:"vcpu_count,string"`
|
||||||
|
RAM string `json:"ram"`
|
||||||
|
Disk string `json:"disk"`
|
||||||
|
Bandwidth string `json:"bandwidth"`
|
||||||
|
Price string `json:"price_per_month"`
|
||||||
|
Regions []int `json:"available_locations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type plans []Plan
|
||||||
|
|
||||||
|
func (p plans) Len() int { return len(p) }
|
||||||
|
func (p plans) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
|
func (p plans) Less(i, j int) bool {
|
||||||
|
pa, _ := strconv.ParseFloat(strings.TrimSpace(p[i].Price), 64)
|
||||||
|
pb, _ := strconv.ParseFloat(strings.TrimSpace(p[j].Price), 64)
|
||||||
|
ra, _ := strconv.ParseInt(strings.TrimSpace(p[i].RAM), 10, 64)
|
||||||
|
rb, _ := strconv.ParseInt(strings.TrimSpace(p[j].RAM), 10, 64)
|
||||||
|
da, _ := strconv.ParseInt(strings.TrimSpace(p[i].Disk), 10, 64)
|
||||||
|
db, _ := strconv.ParseInt(strings.TrimSpace(p[j].Disk), 10, 64)
|
||||||
|
|
||||||
|
// sort order: price, vcpu, ram, disk
|
||||||
|
if pa < pb {
|
||||||
|
return true
|
||||||
|
} else if pa > pb {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if p[i].VCpus < p[j].VCpus {
|
||||||
|
return true
|
||||||
|
} else if p[i].VCpus > p[j].VCpus {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ra < rb {
|
||||||
|
return true
|
||||||
|
} else if ra > rb {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return da < db
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPlans returns a list of all available plans on Vultr account
|
||||||
|
func (c *Client) GetPlans() ([]Plan, error) {
|
||||||
|
var planMap map[string]Plan
|
||||||
|
if err := c.get(`plans/list`, &planMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var p plans
|
||||||
|
for _, plan := range planMap {
|
||||||
|
p = append(p, plan)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(plans(p))
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAvailablePlansForRegion returns available plans for specified region
|
||||||
|
func (c *Client) GetAvailablePlansForRegion(id int) (planIDs []int, err error) {
|
||||||
|
if err := c.get(fmt.Sprintf(`regions/availability?DCID=%v`, id), &planIDs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
44
vendor/github.com/JamesClonk/vultr/lib/regions.go
generated
vendored
Normal file
44
vendor/github.com/JamesClonk/vultr/lib/regions.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import "sort"
|
||||||
|
|
||||||
|
// Region on Vultr
|
||||||
|
type Region struct {
|
||||||
|
ID int `json:"DCID,string"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
Continent string `json:"continent"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Ddos bool `json:"ddos_protection"`
|
||||||
|
BlockStorage bool `json:"block_storage"`
|
||||||
|
Code string `json:"regioncode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type regions []Region
|
||||||
|
|
||||||
|
func (s regions) Len() int { return len(s) }
|
||||||
|
func (s regions) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s regions) Less(i, j int) bool {
|
||||||
|
// sort order: continent, name
|
||||||
|
if s[i].Continent < s[j].Continent {
|
||||||
|
return true
|
||||||
|
} else if s[i].Continent > s[j].Continent {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s[i].Name < s[j].Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRegions returns a list of all available Vultr regions
|
||||||
|
func (c *Client) GetRegions() ([]Region, error) {
|
||||||
|
var regionMap map[string]Region
|
||||||
|
if err := c.get(`regions/list`, ®ionMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var regionList []Region
|
||||||
|
for _, os := range regionMap {
|
||||||
|
regionList = append(regionList, os)
|
||||||
|
}
|
||||||
|
sort.Sort(regions(regionList))
|
||||||
|
return regionList, nil
|
||||||
|
}
|
192
vendor/github.com/JamesClonk/vultr/lib/reservedip.go
generated
vendored
Normal file
192
vendor/github.com/JamesClonk/vultr/lib/reservedip.go
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IP on Vultr
|
||||||
|
type IP struct {
|
||||||
|
ID string `json:"SUBID,string"`
|
||||||
|
RegionID int `json:"DCID,string"`
|
||||||
|
IPType string `json:"ip_type"`
|
||||||
|
Subnet string `json:"subnet"`
|
||||||
|
SubnetSize int `json:"subnet_size"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
AttachedTo string `json:"attached_SUBID,string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ips []IP
|
||||||
|
|
||||||
|
func (s ips) Len() int { return len(s) }
|
||||||
|
func (s ips) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s ips) Less(i, j int) bool {
|
||||||
|
// sort order: label, iptype, subnet
|
||||||
|
if strings.ToLower(s[i].Label) < strings.ToLower(s[j].Label) {
|
||||||
|
return true
|
||||||
|
} else if strings.ToLower(s[i].Label) > strings.ToLower(s[j].Label) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if s[i].IPType < s[j].IPType {
|
||||||
|
return true
|
||||||
|
} else if s[i].IPType > s[j].IPType {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s[i].Subnet < s[j].Subnet
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaller on IP.
|
||||||
|
// This is needed because the Vultr API is inconsistent in it's JSON responses.
|
||||||
|
// Some fields can change type, from JSON number to JSON string and vice-versa.
|
||||||
|
func (i *IP) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
if i == nil {
|
||||||
|
*i = IP{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &fields); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := fmt.Sprintf("%v", fields["SUBID"])
|
||||||
|
if len(value) == 0 || value == "<nil>" || value == "0" {
|
||||||
|
i.ID = ""
|
||||||
|
} else {
|
||||||
|
id, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.ID = strconv.FormatFloat(id, 'f', -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["DCID"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
region, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.RegionID = int(region)
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["attached_SUBID"])
|
||||||
|
if len(value) == 0 || value == "<nil>" || value == "0" || value == "false" {
|
||||||
|
i.AttachedTo = ""
|
||||||
|
} else {
|
||||||
|
attached, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.AttachedTo = strconv.FormatFloat(attached, 'f', -1, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["subnet_size"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
size, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.SubnetSize = int(size)
|
||||||
|
|
||||||
|
i.IPType = fmt.Sprintf("%v", fields["ip_type"])
|
||||||
|
i.Subnet = fmt.Sprintf("%v", fields["subnet"])
|
||||||
|
i.Label = fmt.Sprintf("%v", fields["label"])
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListReservedIP returns a list of all available reserved IPs on Vultr account
|
||||||
|
func (c *Client) ListReservedIP() ([]IP, error) {
|
||||||
|
var ipMap map[string]IP
|
||||||
|
|
||||||
|
err := c.get(`reservedip/list`, &ipMap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ipList := make([]IP, 0)
|
||||||
|
for _, ip := range ipMap {
|
||||||
|
ipList = append(ipList, ip)
|
||||||
|
}
|
||||||
|
sort.Sort(ips(ipList))
|
||||||
|
return ipList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReservedIP returns reserved IP with given ID
|
||||||
|
func (c *Client) GetReservedIP(id string) (IP, error) {
|
||||||
|
var ipMap map[string]IP
|
||||||
|
|
||||||
|
err := c.get(`reservedip/list`, &ipMap)
|
||||||
|
if err != nil {
|
||||||
|
return IP{}, err
|
||||||
|
}
|
||||||
|
if ip, ok := ipMap[id]; ok {
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
|
return IP{}, fmt.Errorf("IP with ID %v not found", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateReservedIP creates a new reserved IP on Vultr account
|
||||||
|
func (c *Client) CreateReservedIP(regionID int, ipType string, label string) (string, error) {
|
||||||
|
values := url.Values{
|
||||||
|
"DCID": {fmt.Sprintf("%v", regionID)},
|
||||||
|
"ip_type": {ipType},
|
||||||
|
}
|
||||||
|
if len(label) > 0 {
|
||||||
|
values.Add("label", label)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := IP{}
|
||||||
|
err := c.post(`reservedip/create`, values, &result)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result.ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DestroyReservedIP deletes an existing reserved IP
|
||||||
|
func (c *Client) DestroyReservedIP(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
}
|
||||||
|
return c.post(`reservedip/destroy`, values, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AttachReservedIP attaches a reserved IP to a virtual machine
|
||||||
|
func (c *Client) AttachReservedIP(ip string, serverID string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"ip_address": {ip},
|
||||||
|
"attach_SUBID": {serverID},
|
||||||
|
}
|
||||||
|
return c.post(`reservedip/attach`, values, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetachReservedIP detaches a reserved IP from an existing virtual machine
|
||||||
|
func (c *Client) DetachReservedIP(serverID string, ip string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"ip_address": {ip},
|
||||||
|
"detach_SUBID": {serverID},
|
||||||
|
}
|
||||||
|
return c.post(`reservedip/detach`, values, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertReservedIP converts an existing virtual machines IP to a reserved IP
|
||||||
|
func (c *Client) ConvertReservedIP(serverID string, ip string) (string, error) {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {serverID},
|
||||||
|
"ip_address": {ip},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := IP{}
|
||||||
|
err := c.post(`reservedip/convert`, values, &result)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result.ID, err
|
||||||
|
}
|
126
vendor/github.com/JamesClonk/vultr/lib/scripts.go
generated
vendored
Normal file
126
vendor/github.com/JamesClonk/vultr/lib/scripts.go
generated
vendored
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StartupScript on Vultr account
|
||||||
|
type StartupScript struct {
|
||||||
|
ID string `json:"SCRIPTID"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Content string `json:"script"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type startupscripts []StartupScript
|
||||||
|
|
||||||
|
func (s startupscripts) Len() int { return len(s) }
|
||||||
|
func (s startupscripts) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s startupscripts) Less(i, j int) bool {
|
||||||
|
return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaller on StartupScript.
|
||||||
|
// Necessary because the SCRIPTID field has inconsistent types.
|
||||||
|
func (s *StartupScript) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
if s == nil {
|
||||||
|
*s = StartupScript{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &fields); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.ID = fmt.Sprintf("%v", fields["SCRIPTID"])
|
||||||
|
s.Name = fmt.Sprintf("%v", fields["name"])
|
||||||
|
s.Type = fmt.Sprintf("%v", fields["type"])
|
||||||
|
s.Content = fmt.Sprintf("%v", fields["script"])
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStartupScripts returns a list of all startup scripts on the current Vultr account
|
||||||
|
func (c *Client) GetStartupScripts() (scripts []StartupScript, err error) {
|
||||||
|
var scriptMap map[string]StartupScript
|
||||||
|
if err := c.get(`startupscript/list`, &scriptMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, script := range scriptMap {
|
||||||
|
if script.Type == "" {
|
||||||
|
script.Type = "boot" // set default script type
|
||||||
|
}
|
||||||
|
scripts = append(scripts, script)
|
||||||
|
}
|
||||||
|
sort.Sort(startupscripts(scripts))
|
||||||
|
return scripts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStartupScript returns the startup script with the given ID
|
||||||
|
func (c *Client) GetStartupScript(id string) (StartupScript, error) {
|
||||||
|
scripts, err := c.GetStartupScripts()
|
||||||
|
if err != nil {
|
||||||
|
return StartupScript{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scripts {
|
||||||
|
if s.ID == id {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return StartupScript{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateStartupScript creates a new startup script
|
||||||
|
func (c *Client) CreateStartupScript(name, content, scriptType string) (StartupScript, error) {
|
||||||
|
values := url.Values{
|
||||||
|
"name": {name},
|
||||||
|
"script": {content},
|
||||||
|
"type": {scriptType},
|
||||||
|
}
|
||||||
|
|
||||||
|
var script StartupScript
|
||||||
|
if err := c.post(`startupscript/create`, values, &script); err != nil {
|
||||||
|
return StartupScript{}, err
|
||||||
|
}
|
||||||
|
script.Name = name
|
||||||
|
script.Content = content
|
||||||
|
script.Type = scriptType
|
||||||
|
|
||||||
|
return script, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateStartupScript updates an existing startup script
|
||||||
|
func (c *Client) UpdateStartupScript(script StartupScript) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SCRIPTID": {script.ID},
|
||||||
|
}
|
||||||
|
if script.Name != "" {
|
||||||
|
values.Add("name", script.Name)
|
||||||
|
}
|
||||||
|
if script.Content != "" {
|
||||||
|
values.Add("script", script.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`startupscript/update`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteStartupScript deletes an existing startup script from Vultr account
|
||||||
|
func (c *Client) DeleteStartupScript(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SCRIPTID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`startupscript/destroy`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
561
vendor/github.com/JamesClonk/vultr/lib/servers.go
generated
vendored
Normal file
561
vendor/github.com/JamesClonk/vultr/lib/servers.go
generated
vendored
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server (virtual machine) on Vultr account
|
||||||
|
type Server struct {
|
||||||
|
ID string `json:"SUBID"`
|
||||||
|
Name string `json:"label"`
|
||||||
|
OS string `json:"os"`
|
||||||
|
RAM string `json:"ram"`
|
||||||
|
Disk string `json:"disk"`
|
||||||
|
MainIP string `json:"main_ip"`
|
||||||
|
VCpus int `json:"vcpu_count,string"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
RegionID int `json:"DCID,string"`
|
||||||
|
DefaultPassword string `json:"default_password"`
|
||||||
|
Created string `json:"date_created"`
|
||||||
|
PendingCharges float64 `json:"pending_charges"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Cost string `json:"cost_per_month"`
|
||||||
|
CurrentBandwidth float64 `json:"current_bandwidth_gb"`
|
||||||
|
AllowedBandwidth float64 `json:"allowed_bandwidth_gb,string"`
|
||||||
|
NetmaskV4 string `json:"netmask_v4"`
|
||||||
|
GatewayV4 string `json:"gateway_v4"`
|
||||||
|
PowerStatus string `json:"power_status"`
|
||||||
|
ServerState string `json:"server_state"`
|
||||||
|
PlanID int `json:"VPSPLANID,string"`
|
||||||
|
V6Networks []V6Network `json:"v6_networks"`
|
||||||
|
InternalIP string `json:"internal_ip"`
|
||||||
|
KVMUrl string `json:"kvm_url"`
|
||||||
|
AutoBackups string `json:"auto_backups"`
|
||||||
|
Tag string `json:"tag"`
|
||||||
|
OSID string `json:"OSID"`
|
||||||
|
AppID string `json:"APPID"`
|
||||||
|
FirewallGroupID string `json:"FIREWALLGROUPID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerOptions are optional parameters to be used during server creation
|
||||||
|
type ServerOptions struct {
|
||||||
|
IPXEChainURL string
|
||||||
|
ISO int
|
||||||
|
Script int
|
||||||
|
UserData string
|
||||||
|
Snapshot string
|
||||||
|
SSHKey string
|
||||||
|
ReservedIP string
|
||||||
|
IPV6 bool
|
||||||
|
PrivateNetworking bool
|
||||||
|
AutoBackups bool
|
||||||
|
DontNotifyOnActivate bool
|
||||||
|
Hostname string
|
||||||
|
Tag string
|
||||||
|
AppID string
|
||||||
|
FirewallGroupID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type servers []Server
|
||||||
|
|
||||||
|
func (s servers) Len() int { return len(s) }
|
||||||
|
func (s servers) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s servers) Less(i, j int) bool {
|
||||||
|
// sort order: name, ip
|
||||||
|
if strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) {
|
||||||
|
return true
|
||||||
|
} else if strings.ToLower(s[i].Name) > strings.ToLower(s[j].Name) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s[i].MainIP < s[j].MainIP
|
||||||
|
}
|
||||||
|
|
||||||
|
// V6Network represents a IPv6 network of a Vultr server
|
||||||
|
type V6Network struct {
|
||||||
|
Network string `json:"v6_network"`
|
||||||
|
MainIP string `json:"v6_main_ip"`
|
||||||
|
NetworkSize string `json:"v6_network_size"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ISOStatus represents an ISO image attached to a Vultr server
|
||||||
|
type ISOStatus struct {
|
||||||
|
State string `json:"state"`
|
||||||
|
ISOID string `json:"ISOID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaller on Server.
|
||||||
|
// This is needed because the Vultr API is inconsistent in it's JSON responses for servers.
|
||||||
|
// Some fields can change type, from JSON number to JSON string and vice-versa.
|
||||||
|
func (s *Server) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
if s == nil {
|
||||||
|
*s = Server{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &fields); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := fmt.Sprintf("%v", fields["vcpu_count"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
vcpu, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.VCpus = int(vcpu)
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["DCID"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
region, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.RegionID = int(region)
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["VPSPLANID"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
plan, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.PlanID = int(plan)
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["pending_charges"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
pc, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.PendingCharges = pc
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["current_bandwidth_gb"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
cb, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.CurrentBandwidth = cb
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["allowed_bandwidth_gb"])
|
||||||
|
if len(value) == 0 || value == "<nil>" {
|
||||||
|
value = "0"
|
||||||
|
}
|
||||||
|
ab, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.AllowedBandwidth = ab
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["OSID"])
|
||||||
|
if value == "<nil>" {
|
||||||
|
value = ""
|
||||||
|
}
|
||||||
|
s.OSID = value
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["APPID"])
|
||||||
|
if value == "<nil>" || value == "0" {
|
||||||
|
value = ""
|
||||||
|
}
|
||||||
|
s.AppID = value
|
||||||
|
|
||||||
|
value = fmt.Sprintf("%v", fields["FIREWALLGROUPID"])
|
||||||
|
if value == "<nil>" || value == "0" {
|
||||||
|
value = ""
|
||||||
|
}
|
||||||
|
s.FirewallGroupID = value
|
||||||
|
|
||||||
|
s.ID = fmt.Sprintf("%v", fields["SUBID"])
|
||||||
|
s.Name = fmt.Sprintf("%v", fields["label"])
|
||||||
|
s.OS = fmt.Sprintf("%v", fields["os"])
|
||||||
|
s.RAM = fmt.Sprintf("%v", fields["ram"])
|
||||||
|
s.Disk = fmt.Sprintf("%v", fields["disk"])
|
||||||
|
s.MainIP = fmt.Sprintf("%v", fields["main_ip"])
|
||||||
|
s.Location = fmt.Sprintf("%v", fields["location"])
|
||||||
|
s.DefaultPassword = fmt.Sprintf("%v", fields["default_password"])
|
||||||
|
s.Created = fmt.Sprintf("%v", fields["date_created"])
|
||||||
|
s.Status = fmt.Sprintf("%v", fields["status"])
|
||||||
|
s.Cost = fmt.Sprintf("%v", fields["cost_per_month"])
|
||||||
|
s.NetmaskV4 = fmt.Sprintf("%v", fields["netmask_v4"])
|
||||||
|
s.GatewayV4 = fmt.Sprintf("%v", fields["gateway_v4"])
|
||||||
|
s.PowerStatus = fmt.Sprintf("%v", fields["power_status"])
|
||||||
|
s.ServerState = fmt.Sprintf("%v", fields["server_state"])
|
||||||
|
|
||||||
|
v6networks := make([]V6Network, 0)
|
||||||
|
if networks, ok := fields["v6_networks"].([]interface{}); ok {
|
||||||
|
for _, network := range networks {
|
||||||
|
if network, ok := network.(map[string]interface{}); ok {
|
||||||
|
v6network := V6Network{
|
||||||
|
Network: fmt.Sprintf("%v", network["v6_network"]),
|
||||||
|
MainIP: fmt.Sprintf("%v", network["v6_main_ip"]),
|
||||||
|
NetworkSize: fmt.Sprintf("%v", network["v6_network_size"]),
|
||||||
|
}
|
||||||
|
v6networks = append(v6networks, v6network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.V6Networks = v6networks
|
||||||
|
}
|
||||||
|
|
||||||
|
s.InternalIP = fmt.Sprintf("%v", fields["internal_ip"])
|
||||||
|
s.KVMUrl = fmt.Sprintf("%v", fields["kvm_url"])
|
||||||
|
s.AutoBackups = fmt.Sprintf("%v", fields["auto_backups"])
|
||||||
|
s.Tag = fmt.Sprintf("%v", fields["tag"])
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServers returns a list of current virtual machines on Vultr account
|
||||||
|
func (c *Client) GetServers() (serverList []Server, err error) {
|
||||||
|
var serverMap map[string]Server
|
||||||
|
if err := c.get(`server/list`, &serverMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, server := range serverMap {
|
||||||
|
serverList = append(serverList, server)
|
||||||
|
}
|
||||||
|
sort.Sort(servers(serverList))
|
||||||
|
return serverList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServersByTag returns a list of all virtual machines matching by tag
|
||||||
|
func (c *Client) GetServersByTag(tag string) (serverList []Server, err error) {
|
||||||
|
var serverMap map[string]Server
|
||||||
|
if err := c.get(`server/list?tag=`+tag, &serverMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, server := range serverMap {
|
||||||
|
serverList = append(serverList, server)
|
||||||
|
}
|
||||||
|
sort.Sort(servers(serverList))
|
||||||
|
return serverList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServer returns the virtual machine with the given ID
|
||||||
|
func (c *Client) GetServer(id string) (server Server, err error) {
|
||||||
|
if err := c.get(`server/list?SUBID=`+id, &server); err != nil {
|
||||||
|
return Server{}, err
|
||||||
|
}
|
||||||
|
return server, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateServer creates a new virtual machine on Vultr. ServerOptions are optional settings.
|
||||||
|
func (c *Client) CreateServer(name string, regionID, planID, osID int, options *ServerOptions) (Server, error) {
|
||||||
|
values := url.Values{
|
||||||
|
"label": {name},
|
||||||
|
"DCID": {fmt.Sprintf("%v", regionID)},
|
||||||
|
"VPSPLANID": {fmt.Sprintf("%v", planID)},
|
||||||
|
"OSID": {fmt.Sprintf("%v", osID)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if options != nil {
|
||||||
|
if options.IPXEChainURL != "" {
|
||||||
|
values.Add("ipxe_chain_url", options.IPXEChainURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.ISO != 0 {
|
||||||
|
values.Add("ISOID", fmt.Sprintf("%v", options.ISO))
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.Script != 0 {
|
||||||
|
values.Add("SCRIPTID", fmt.Sprintf("%v", options.Script))
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.UserData != "" {
|
||||||
|
values.Add("userdata", base64.StdEncoding.EncodeToString([]byte(options.UserData)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.Snapshot != "" {
|
||||||
|
values.Add("SNAPSHOTID", options.Snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.SSHKey != "" {
|
||||||
|
values.Add("SSHKEYID", options.SSHKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.ReservedIP != "" {
|
||||||
|
values.Add("reserved_ip_v4", options.ReservedIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
values.Add("enable_ipv6", "no")
|
||||||
|
if options.IPV6 {
|
||||||
|
values.Set("enable_ipv6", "yes")
|
||||||
|
}
|
||||||
|
|
||||||
|
values.Add("enable_private_network", "no")
|
||||||
|
if options.PrivateNetworking {
|
||||||
|
values.Set("enable_private_network", "yes")
|
||||||
|
}
|
||||||
|
|
||||||
|
values.Add("auto_backups", "no")
|
||||||
|
if options.AutoBackups {
|
||||||
|
values.Set("auto_backups", "yes")
|
||||||
|
}
|
||||||
|
|
||||||
|
values.Add("notify_activate", "yes")
|
||||||
|
if options.DontNotifyOnActivate {
|
||||||
|
values.Set("notify_activate", "no")
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.Hostname != "" {
|
||||||
|
values.Add("hostname", options.Hostname)
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.Tag != "" {
|
||||||
|
values.Add("tag", options.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.AppID != "" {
|
||||||
|
values.Add("APPID", options.AppID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.FirewallGroupID != "" {
|
||||||
|
values.Add("FIREWALLGROUPID", options.FirewallGroupID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var server Server
|
||||||
|
if err := c.post(`server/create`, values, &server); err != nil {
|
||||||
|
return Server{}, err
|
||||||
|
}
|
||||||
|
server.Name = name
|
||||||
|
server.RegionID = regionID
|
||||||
|
server.PlanID = planID
|
||||||
|
|
||||||
|
return server, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenameServer renames an existing virtual machine
|
||||||
|
func (c *Client) RenameServer(id, name string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"label": {name},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/label_set`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TagServer replaces the tag on an existing virtual machine
|
||||||
|
func (c *Client) TagServer(id, tag string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"tag": {tag},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/tag_set`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartServer starts an existing virtual machine
|
||||||
|
func (c *Client) StartServer(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/start`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HaltServer stops an existing virtual machine
|
||||||
|
func (c *Client) HaltServer(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/halt`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RebootServer reboots an existing virtual machine
|
||||||
|
func (c *Client) RebootServer(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/reboot`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReinstallServer reinstalls the operating system on an existing virtual machine
|
||||||
|
func (c *Client) ReinstallServer(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/reinstall`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeOSofServer changes the virtual machine to a different operating system
|
||||||
|
func (c *Client) ChangeOSofServer(id string, osID int) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"OSID": {fmt.Sprintf("%v", osID)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/os_change`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOSforServer lists all available operating systems to which an existing virtual machine can be changed
|
||||||
|
func (c *Client) ListOSforServer(id string) (os []OS, err error) {
|
||||||
|
var osMap map[string]OS
|
||||||
|
if err := c.get(`server/os_change_list?SUBID=`+id, &osMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, o := range osMap {
|
||||||
|
os = append(os, o)
|
||||||
|
}
|
||||||
|
sort.Sort(oses(os))
|
||||||
|
return os, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AttachISOtoServer attaches an ISO image to an existing virtual machine and reboots it
|
||||||
|
func (c *Client) AttachISOtoServer(id string, isoID int) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"ISOID": {fmt.Sprintf("%v", isoID)},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/iso_attach`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetachISOfromServer detaches the currently mounted ISO image from the virtual machine and reboots it
|
||||||
|
func (c *Client) DetachISOfromServer(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/iso_detach`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetISOStatusofServer retrieves the current ISO image state of an existing virtual machine
|
||||||
|
func (c *Client) GetISOStatusofServer(id string) (isoStatus ISOStatus, err error) {
|
||||||
|
if err := c.get(`server/iso_status?SUBID=`+id, &isoStatus); err != nil {
|
||||||
|
return ISOStatus{}, err
|
||||||
|
}
|
||||||
|
return isoStatus, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteServer deletes an existing virtual machine
|
||||||
|
func (c *Client) DeleteServer(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/destroy`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFirewallGroup adds a virtual machine to a firewall group
|
||||||
|
func (c *Client) SetFirewallGroup(id, firewallgroup string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"FIREWALLGROUPID": {firewallgroup},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/firewall_group_set`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnsetFirewallGroup removes a virtual machine from a firewall group
|
||||||
|
func (c *Client) UnsetFirewallGroup(id string) error {
|
||||||
|
return c.SetFirewallGroup(id, "0")
|
||||||
|
}
|
||||||
|
|
||||||
|
// BandwidthOfServer retrieves the bandwidth used by a virtual machine
|
||||||
|
func (c *Client) BandwidthOfServer(id string) (bandwidth []map[string]string, err error) {
|
||||||
|
var bandwidthMap map[string][][]string
|
||||||
|
if err := c.get(`server/bandwidth?SUBID=`+id, &bandwidthMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse incoming bytes
|
||||||
|
for _, b := range bandwidthMap["incoming_bytes"] {
|
||||||
|
bMap := make(map[string]string)
|
||||||
|
bMap["date"] = b[0]
|
||||||
|
bMap["incoming"] = b[1]
|
||||||
|
bandwidth = append(bandwidth, bMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse outgoing bytes (we'll assume that incoming and outgoing dates are always a match)
|
||||||
|
for _, b := range bandwidthMap["outgoing_bytes"] {
|
||||||
|
for i := range bandwidth {
|
||||||
|
if bandwidth[i]["date"] == b[0] {
|
||||||
|
bandwidth[i]["outgoing"] = b[1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bandwidth, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeApplicationofServer changes the virtual machine to a different application
|
||||||
|
func (c *Client) ChangeApplicationofServer(id string, appID string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"APPID": {appID},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`server/app_change`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListApplicationsforServer lists all available operating systems to which an existing virtual machine can be changed
|
||||||
|
func (c *Client) ListApplicationsforServer(id string) (apps []Application, err error) {
|
||||||
|
var appMap map[string]Application
|
||||||
|
if err := c.get(`server/app_change_list?SUBID=`+id, &appMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, app := range appMap {
|
||||||
|
apps = append(apps, app)
|
||||||
|
}
|
||||||
|
sort.Sort(applications(apps))
|
||||||
|
return apps, nil
|
||||||
|
}
|
72
vendor/github.com/JamesClonk/vultr/lib/snapshots.go
generated
vendored
Normal file
72
vendor/github.com/JamesClonk/vultr/lib/snapshots.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Snapshot of a virtual machine on Vultr account
|
||||||
|
type Snapshot struct {
|
||||||
|
ID string `json:"SNAPSHOTID"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Size string `json:"size"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Created string `json:"date_created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type snapshots []Snapshot
|
||||||
|
|
||||||
|
func (s snapshots) Len() int { return len(s) }
|
||||||
|
func (s snapshots) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s snapshots) Less(i, j int) bool {
|
||||||
|
// sort order: description, created
|
||||||
|
if strings.ToLower(s[i].Description) < strings.ToLower(s[j].Description) {
|
||||||
|
return true
|
||||||
|
} else if strings.ToLower(s[i].Description) > strings.ToLower(s[j].Description) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return s[i].Created < s[j].Created
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSnapshots retrieves a list of all snapshots on Vultr account
|
||||||
|
func (c *Client) GetSnapshots() (snapshotList []Snapshot, err error) {
|
||||||
|
var snapshotMap map[string]Snapshot
|
||||||
|
if err := c.get(`snapshot/list`, &snapshotMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, snapshot := range snapshotMap {
|
||||||
|
snapshotList = append(snapshotList, snapshot)
|
||||||
|
}
|
||||||
|
sort.Sort(snapshots(snapshotList))
|
||||||
|
return snapshotList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSnapshot creates a new virtual machine snapshot
|
||||||
|
func (c *Client) CreateSnapshot(id, description string) (Snapshot, error) {
|
||||||
|
values := url.Values{
|
||||||
|
"SUBID": {id},
|
||||||
|
"description": {description},
|
||||||
|
}
|
||||||
|
|
||||||
|
var snapshot Snapshot
|
||||||
|
if err := c.post(`snapshot/create`, values, &snapshot); err != nil {
|
||||||
|
return Snapshot{}, err
|
||||||
|
}
|
||||||
|
snapshot.Description = description
|
||||||
|
|
||||||
|
return snapshot, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSnapshot deletes an existing virtual machine snapshot
|
||||||
|
func (c *Client) DeleteSnapshot(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SNAPSHOTID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`snapshot/destroy`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
82
vendor/github.com/JamesClonk/vultr/lib/sshkeys.go
generated
vendored
Normal file
82
vendor/github.com/JamesClonk/vultr/lib/sshkeys.go
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SSHKey on Vultr account
|
||||||
|
type SSHKey struct {
|
||||||
|
ID string `json:"SSHKEYID"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Key string `json:"ssh_key"`
|
||||||
|
Created string `json:"date_created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type sshkeys []SSHKey
|
||||||
|
|
||||||
|
func (s sshkeys) Len() int { return len(s) }
|
||||||
|
func (s sshkeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
func (s sshkeys) Less(i, j int) bool { return strings.ToLower(s[i].Name) < strings.ToLower(s[j].Name) }
|
||||||
|
|
||||||
|
// GetSSHKeys returns a list of SSHKeys from Vultr account
|
||||||
|
func (c *Client) GetSSHKeys() (keys []SSHKey, err error) {
|
||||||
|
var keyMap map[string]SSHKey
|
||||||
|
if err := c.get(`sshkey/list`, &keyMap); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range keyMap {
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
sort.Sort(sshkeys(keys))
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSSHKey creates new SSHKey on Vultr
|
||||||
|
func (c *Client) CreateSSHKey(name, key string) (SSHKey, error) {
|
||||||
|
values := url.Values{
|
||||||
|
"name": {name},
|
||||||
|
"ssh_key": {key},
|
||||||
|
}
|
||||||
|
|
||||||
|
var sshKey SSHKey
|
||||||
|
if err := c.post(`sshkey/create`, values, &sshKey); err != nil {
|
||||||
|
return SSHKey{}, err
|
||||||
|
}
|
||||||
|
sshKey.Name = name
|
||||||
|
sshKey.Key = key
|
||||||
|
|
||||||
|
return sshKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSSHKey updates an existing SSHKey entry
|
||||||
|
func (c *Client) UpdateSSHKey(key SSHKey) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SSHKEYID": {key.ID},
|
||||||
|
}
|
||||||
|
if key.Name != "" {
|
||||||
|
values.Add("name", key.Name)
|
||||||
|
}
|
||||||
|
if key.Key != "" {
|
||||||
|
values.Add("ssh_key", key.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`sshkey/update`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSSHKey deletes an existing SSHKey from Vultr account
|
||||||
|
func (c *Client) DeleteSSHKey(id string) error {
|
||||||
|
values := url.Values{
|
||||||
|
"SSHKEYID": {id},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.post(`sshkey/destroy`, values, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
201
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/LICENSE
generated
vendored
Normal file
201
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
36
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1/api.go
generated
vendored
Normal file
36
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1/api.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resource is the "base" type for all API resources
|
||||||
|
type Resource struct {
|
||||||
|
Complete chan bool `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes the Complete channel, if it is necessary
|
||||||
|
// need to create a resource specific Init(), make sure to
|
||||||
|
// initialize the channel.
|
||||||
|
func (resource *Resource) Init() {
|
||||||
|
resource.Complete = make(chan bool, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostUnmarshalJSON is a default implementation of the
|
||||||
|
// PostUnmarshalJSON hook that simply calls Init() and
|
||||||
|
// sends true to the Complete channel. This is overridden
|
||||||
|
// in many resources, in particular those that represent
|
||||||
|
// collections, and have to initialize sub-resources also.
|
||||||
|
func (resource *Resource) PostUnmarshalJSON() error {
|
||||||
|
resource.Init()
|
||||||
|
resource.Complete <- true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetJSON returns the raw (indented) JSON (as []bytes)
|
||||||
|
func (resource *Resource) GetJSON() ([]byte, error) {
|
||||||
|
return json.MarshalIndent(resource, "", " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONBody is a generic struct for temporary JSON unmarshalling.
|
||||||
|
type JSONBody map[string]interface{}
|
111
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1/client.go
generated
vendored
Normal file
111
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1/client.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
// Package client is a simple library for http.Client to sign Akamai OPEN Edgegrid API requests
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
|
||||||
|
"github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
libraryVersion = "0.6.2"
|
||||||
|
// UserAgent is the User-Agent value sent for all requests
|
||||||
|
UserAgent = "Akamai-Open-Edgegrid-golang/" + libraryVersion + " golang/" + strings.TrimPrefix(runtime.Version(), "go")
|
||||||
|
// Client is the *http.Client to use
|
||||||
|
Client = http.DefaultClient
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewRequest creates an HTTP request that can be sent to Akamai APIs. A relative URL can be provided in path, which will be resolved to the
|
||||||
|
// Host specified in Config. If body is specified, it will be sent as the request body.
|
||||||
|
func NewRequest(config edgegrid.Config, method, path string, body io.Reader) (*http.Request, error) {
|
||||||
|
var (
|
||||||
|
baseURL *url.URL
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if strings.HasPrefix(config.Host, "https://") {
|
||||||
|
baseURL, err = url.Parse(config.Host)
|
||||||
|
} else {
|
||||||
|
baseURL, err = url.Parse("https://" + config.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rel, err := url.Parse(strings.TrimPrefix(path, "/"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
u := baseURL.ResolveReference(rel)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, u.String(), body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("User-Agent", UserAgent)
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewJSONRequest creates an HTTP request that can be sent to the Akamai APIs with a JSON body
|
||||||
|
// The JSON body is encoded and the Content-Type/Accept headers are set automatically.
|
||||||
|
func NewJSONRequest(config edgegrid.Config, method, path string, body interface{}) (*http.Request, error) {
|
||||||
|
jsonBody, err := jsonhooks.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewReader(jsonBody)
|
||||||
|
req, err := NewRequest(config, method, path, buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Accept", "application/json,*/*")
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do performs a given HTTP Request, signed with the Akamai OPEN Edgegrid
|
||||||
|
// Authorization header. An edgegrid.Response or an error is returned.
|
||||||
|
func Do(config edgegrid.Config, req *http.Request) (*http.Response, error) {
|
||||||
|
Client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||||
|
req = edgegrid.AddRequestHeader(config, req)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
req = edgegrid.AddRequestHeader(config, req)
|
||||||
|
res, err := Client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyJSON unmarshals the Response.Body into a given data structure
|
||||||
|
func BodyJSON(r *http.Response, data interface{}) error {
|
||||||
|
if data == nil {
|
||||||
|
return errors.New("You must pass in an interface{}")
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = jsonhooks.Unmarshal(body, data)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
88
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1/errors.go
generated
vendored
Normal file
88
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// APIError exposes an Akamai OPEN Edgegrid Error
|
||||||
|
type APIError struct {
|
||||||
|
error
|
||||||
|
Type string `json:"type"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
Detail string `json:"detail"`
|
||||||
|
Instance string `json:"instance"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
ServerIP string `json:"serverIp"`
|
||||||
|
ClientIP string `json:"clientIp"`
|
||||||
|
RequestID string `json:"requestId"`
|
||||||
|
RequestTime string `json:"requestTime"`
|
||||||
|
Response *http.Response `json:"-"`
|
||||||
|
RawBody string `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (error APIError) Error() string {
|
||||||
|
return strings.TrimSpace(fmt.Sprintf("API Error: %d %s %s More Info %s", error.Status, error.Title, error.Detail, error.Type))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAPIError creates a new API error based on a Response,
|
||||||
|
// or http.Response-like.
|
||||||
|
func NewAPIError(response *http.Response) APIError {
|
||||||
|
// TODO: handle this error
|
||||||
|
body, _ := ioutil.ReadAll(response.Body)
|
||||||
|
|
||||||
|
return NewAPIErrorFromBody(response, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAPIErrorFromBody creates a new API error, allowing you to pass in a body
|
||||||
|
//
|
||||||
|
// This function is intended to be used after the body has already been read for
|
||||||
|
// other purposes.
|
||||||
|
func NewAPIErrorFromBody(response *http.Response, body []byte) APIError {
|
||||||
|
error := APIError{}
|
||||||
|
|
||||||
|
if err := jsonhooks.Unmarshal(body, &error); err == nil {
|
||||||
|
error.Status = response.StatusCode
|
||||||
|
error.Title = response.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
error.Response = response
|
||||||
|
error.RawBody = string(body)
|
||||||
|
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInformational determines if a response was informational (1XX status)
|
||||||
|
func IsInformational(r *http.Response) bool {
|
||||||
|
return r.StatusCode > 99 && r.StatusCode < 200
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSuccess determines if a response was successful (2XX status)
|
||||||
|
func IsSuccess(r *http.Response) bool {
|
||||||
|
return r.StatusCode > 199 && r.StatusCode < 300
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRedirection determines if a response was a redirect (3XX status)
|
||||||
|
func IsRedirection(r *http.Response) bool {
|
||||||
|
return r.StatusCode > 299 && r.StatusCode < 400
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsClientError determines if a response was a client error (4XX status)
|
||||||
|
func IsClientError(r *http.Response) bool {
|
||||||
|
return r.StatusCode > 399 && r.StatusCode < 500
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsServerError determines if a response was a server error (5XX status)
|
||||||
|
func IsServerError(r *http.Response) bool {
|
||||||
|
return r.StatusCode > 499 && r.StatusCode < 600
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsError determines if the response was a client or server error (4XX or 5XX status)
|
||||||
|
func IsError(r *http.Response) bool {
|
||||||
|
return r.StatusCode > 399 && r.StatusCode < 600
|
||||||
|
}
|
125
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1/errors.go
generated
vendored
Normal file
125
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigDNSError interface {
|
||||||
|
error
|
||||||
|
Network() bool
|
||||||
|
NotFound() bool
|
||||||
|
FailedToSave() bool
|
||||||
|
ValidationFailed() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsConfigDNSError(e error) bool {
|
||||||
|
_, ok := e.(ConfigDNSError)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
type ZoneError struct {
|
||||||
|
zoneName string
|
||||||
|
httpErrorMessage string
|
||||||
|
apiErrorMessage string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ZoneError) Network() bool {
|
||||||
|
if e.httpErrorMessage != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ZoneError) NotFound() bool {
|
||||||
|
if e.err == nil && e.httpErrorMessage == "" && e.apiErrorMessage == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ZoneError) FailedToSave() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ZoneError) ValidationFailed() bool {
|
||||||
|
if e.apiErrorMessage != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ZoneError) Error() string {
|
||||||
|
if e.Network() {
|
||||||
|
return fmt.Sprintf("Zone \"%s\" network error: [%s]", e.zoneName, e.httpErrorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.NotFound() {
|
||||||
|
return fmt.Sprintf("Zone \"%s\" not found.", e.zoneName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.FailedToSave() {
|
||||||
|
return fmt.Sprintf("Zone \"%s\" failed to save: [%s]", e.zoneName, e.err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.ValidationFailed() {
|
||||||
|
return fmt.Sprintf("Zone \"%s\" validation failed: [%s]", e.zoneName, e.apiErrorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.err != nil {
|
||||||
|
return e.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecordError struct {
|
||||||
|
fieldName string
|
||||||
|
httpErrorMessage string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RecordError) Network() bool {
|
||||||
|
if e.httpErrorMessage != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RecordError) NotFound() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RecordError) FailedToSave() bool {
|
||||||
|
if e.fieldName == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RecordError) ValidationFailed() bool {
|
||||||
|
if e.fieldName != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RecordError) Error() string {
|
||||||
|
if e.Network() {
|
||||||
|
return fmt.Sprintf("Record network error: [%s]", e.httpErrorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.NotFound() {
|
||||||
|
return fmt.Sprintf("Record not found.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.FailedToSave() {
|
||||||
|
return fmt.Sprintf("Record failed to save: [%s]", e.err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.ValidationFailed() {
|
||||||
|
return fmt.Sprintf("Record validation failed for field [%s]", e.fieldName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<nil>"
|
||||||
|
}
|
1738
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1/record.go
generated
vendored
Normal file
1738
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1/record.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
16
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1/service.go
generated
vendored
Normal file
16
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1/service.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Config contains the Akamai OPEN Edgegrid API credentials
|
||||||
|
// for automatic signing of requests
|
||||||
|
Config edgegrid.Config
|
||||||
|
)
|
||||||
|
|
||||||
|
// Init sets the FastDNS edgegrid Config
|
||||||
|
func Init(config edgegrid.Config) {
|
||||||
|
Config = config
|
||||||
|
}
|
1557
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1/zone.go
generated
vendored
Normal file
1557
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1/zone.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
181
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid/config.go
generated
vendored
Normal file
181
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid/config.go
generated
vendored
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
package edgegrid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-ini/ini"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config struct provides all the necessary fields to
|
||||||
|
// create authorization header, debug is optional
|
||||||
|
type Config struct {
|
||||||
|
Host string `ini:"host"`
|
||||||
|
ClientToken string `ini:"client_token"`
|
||||||
|
ClientSecret string `ini:"client_secret"`
|
||||||
|
AccessToken string `ini:"access_token"`
|
||||||
|
HeaderToSign []string `ini:"headers_to_sign"`
|
||||||
|
MaxBody int `ini:"max_body"`
|
||||||
|
Debug bool `ini:"debug"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes by first attempting to use ENV vars, with .edgerc as a fallback
|
||||||
|
//
|
||||||
|
// See: InitEnv()
|
||||||
|
// See: InitEdgeRc()
|
||||||
|
func Init(filepath string, section string) (Config, error) {
|
||||||
|
if section == "" {
|
||||||
|
section = defaultSection
|
||||||
|
} else {
|
||||||
|
section = strings.ToUpper(section)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, exists := os.LookupEnv("AKAMAI_" + section + "_HOST")
|
||||||
|
if !exists && section == defaultSection {
|
||||||
|
_, exists := os.LookupEnv("AKAMAI_HOST")
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
return InitEnv("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
return InitEnv(section)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := InitEdgeRc(filepath, strings.ToLower(section))
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if section != defaultSection {
|
||||||
|
_, ok := os.LookupEnv("AKAMAI_HOST")
|
||||||
|
if ok {
|
||||||
|
return InitEnv("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, fmt.Errorf("Unable to create instance using environment or .edgerc file")
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitEdgeRc initializes using a configuration file in standard INI format
|
||||||
|
//
|
||||||
|
// By default, it uses the .edgerc found in the users home directory, and the
|
||||||
|
// "default" section.
|
||||||
|
func InitEdgeRc(filepath string, section string) (Config, error) {
|
||||||
|
var (
|
||||||
|
c Config
|
||||||
|
requiredOptions = []string{"host", "client_token", "client_secret", "access_token"}
|
||||||
|
missing []string
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check if filepath is empty
|
||||||
|
if filepath == "" {
|
||||||
|
filepath = "~/.edgerc"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if section is empty
|
||||||
|
if section == "" {
|
||||||
|
section = "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tilde seems to be not working when passing ~/.edgerc as file
|
||||||
|
// Takes current user and use home dir instead
|
||||||
|
|
||||||
|
path, err := homedir.Expand(filepath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return c, fmt.Errorf(errorMap[ErrHomeDirNotFound], err)
|
||||||
|
}
|
||||||
|
|
||||||
|
edgerc, err := ini.Load(path)
|
||||||
|
if err != nil {
|
||||||
|
return c, fmt.Errorf(errorMap[ErrConfigFile], err)
|
||||||
|
}
|
||||||
|
err = edgerc.Section(section).MapTo(&c)
|
||||||
|
if err != nil {
|
||||||
|
return c, fmt.Errorf(errorMap[ErrConfigFileSection], err)
|
||||||
|
}
|
||||||
|
for _, opt := range requiredOptions {
|
||||||
|
if !(edgerc.Section(section).HasKey(opt)) {
|
||||||
|
missing = append(missing, opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(missing) > 0 {
|
||||||
|
return c, fmt.Errorf(errorMap[ErrConfigMissingOptions], missing)
|
||||||
|
}
|
||||||
|
if c.MaxBody == 0 {
|
||||||
|
c.MaxBody = 131072
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitEnv initializes using the Environment (ENV)
|
||||||
|
//
|
||||||
|
// By default, it uses AKAMAI_HOST, AKAMAI_CLIENT_TOKEN, AKAMAI_CLIENT_SECRET,
|
||||||
|
// AKAMAI_ACCESS_TOKEN, and AKAMAI_MAX_BODY variables.
|
||||||
|
//
|
||||||
|
// You can define multiple configurations by prefixing with the section name specified, e.g.
|
||||||
|
// passing "ccu" will cause it to look for AKAMAI_CCU_HOST, etc.
|
||||||
|
//
|
||||||
|
// If AKAMAI_{SECTION} does not exist, it will fall back to just AKAMAI_.
|
||||||
|
func InitEnv(section string) (Config, error) {
|
||||||
|
var (
|
||||||
|
c Config
|
||||||
|
requiredOptions = []string{"HOST", "CLIENT_TOKEN", "CLIENT_SECRET", "ACCESS_TOKEN"}
|
||||||
|
missing []string
|
||||||
|
prefix string
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check if section is empty
|
||||||
|
if section == "" {
|
||||||
|
section = defaultSection
|
||||||
|
} else {
|
||||||
|
section = strings.ToUpper(section)
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix = "AKAMAI_"
|
||||||
|
_, ok := os.LookupEnv("AKAMAI_" + section + "_HOST")
|
||||||
|
if ok {
|
||||||
|
prefix = "AKAMAI_" + section + "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range requiredOptions {
|
||||||
|
val, ok := os.LookupEnv(prefix + opt)
|
||||||
|
if !ok {
|
||||||
|
missing = append(missing, prefix+opt)
|
||||||
|
} else {
|
||||||
|
switch {
|
||||||
|
case opt == "HOST":
|
||||||
|
c.Host = val
|
||||||
|
case opt == "CLIENT_TOKEN":
|
||||||
|
c.ClientToken = val
|
||||||
|
case opt == "CLIENT_SECRET":
|
||||||
|
c.ClientSecret = val
|
||||||
|
case opt == "ACCESS_TOKEN":
|
||||||
|
c.AccessToken = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missing) > 0 {
|
||||||
|
return c, fmt.Errorf(errorMap[ErrMissingEnvVariables], missing)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.MaxBody = 0
|
||||||
|
|
||||||
|
val, ok := os.LookupEnv(prefix + "MAX_BODY")
|
||||||
|
if i, err := strconv.Atoi(val); err == nil {
|
||||||
|
c.MaxBody = i
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok || c.MaxBody == 0 {
|
||||||
|
c.MaxBody = 131072
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
22
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid/errors.go
generated
vendored
Normal file
22
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package edgegrid
|
||||||
|
|
||||||
|
// Error constants
|
||||||
|
const (
|
||||||
|
ErrUUIDGenerateFailed = 500
|
||||||
|
ErrHomeDirNotFound = 501
|
||||||
|
ErrConfigFile = 502
|
||||||
|
ErrConfigFileSection = 503
|
||||||
|
ErrConfigMissingOptions = 504
|
||||||
|
ErrMissingEnvVariables = 505
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errorMap = map[int]string{
|
||||||
|
ErrUUIDGenerateFailed: "Generate UUID failed: %s",
|
||||||
|
ErrHomeDirNotFound: "Fatal could not find home dir from user: %s",
|
||||||
|
ErrConfigFile: "Fatal error edgegrid file: %s",
|
||||||
|
ErrConfigFileSection: "Could not map section: %s",
|
||||||
|
ErrConfigMissingOptions: "Fatal missing required options: %s",
|
||||||
|
ErrMissingEnvVariables: "Fatal missing required environment variables: %s",
|
||||||
|
}
|
||||||
|
)
|
195
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid/signer.go
generated
vendored
Normal file
195
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid/signer.go
generated
vendored
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
// Package edgegrid allows you to sign http.Request's using the Akamai OPEN Edgegrid Signing Scheme
|
||||||
|
package edgegrid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultSection = "DEFAULT"
|
||||||
|
|
||||||
|
// AddRequestHeader sets the Authorization header to use Akamai Open API
|
||||||
|
func AddRequestHeader(config Config, req *http.Request) *http.Request {
|
||||||
|
if config.Debug {
|
||||||
|
log.SetLevel(log.DebugLevel)
|
||||||
|
}
|
||||||
|
timestamp := makeEdgeTimeStamp()
|
||||||
|
nonce := createNonce()
|
||||||
|
|
||||||
|
if req.Header.Get("Content-Type") == "" {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", createAuthHeader(config, req, timestamp, nonce))
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be assigned the UTC time when the request is signed.
|
||||||
|
// Format of “yyyyMMddTHH:mm:ss+0000”
|
||||||
|
func makeEdgeTimeStamp() string {
|
||||||
|
local := time.FixedZone("GMT", 0)
|
||||||
|
t := time.Now().In(local)
|
||||||
|
return fmt.Sprintf("%d%02d%02dT%02d:%02d:%02d+0000",
|
||||||
|
t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be assigned a nonce (number used once) for the request.
|
||||||
|
// It is a random string used to detect replayed request messages.
|
||||||
|
// A GUID is recommended.
|
||||||
|
func createNonce() string {
|
||||||
|
uuid, err := uuid.NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(errorMap[ErrUUIDGenerateFailed], err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return uuid.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringMinifier(in string) (out string) {
|
||||||
|
white := false
|
||||||
|
for _, c := range in {
|
||||||
|
if unicode.IsSpace(c) {
|
||||||
|
if !white {
|
||||||
|
out = out + " "
|
||||||
|
}
|
||||||
|
white = true
|
||||||
|
} else {
|
||||||
|
out = out + string(c)
|
||||||
|
white = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func concatPathQuery(path, query string) string {
|
||||||
|
if query == "" {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s?%s", path, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// createSignature is the base64-encoding of the SHA–256 HMAC of the data to sign with the signing key.
|
||||||
|
func createSignature(message string, secret string) string {
|
||||||
|
key := []byte(secret)
|
||||||
|
h := hmac.New(sha256.New, key)
|
||||||
|
h.Write([]byte(message))
|
||||||
|
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func createHash(data string) string {
|
||||||
|
h := sha256.Sum256([]byte(data))
|
||||||
|
return base64.StdEncoding.EncodeToString(h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func canonicalizeHeaders(config Config, req *http.Request) string {
|
||||||
|
var unsortedHeader []string
|
||||||
|
var sortedHeader []string
|
||||||
|
for k := range req.Header {
|
||||||
|
unsortedHeader = append(unsortedHeader, k)
|
||||||
|
}
|
||||||
|
sort.Strings(unsortedHeader)
|
||||||
|
for _, k := range unsortedHeader {
|
||||||
|
for _, sign := range config.HeaderToSign {
|
||||||
|
if sign == k {
|
||||||
|
v := strings.TrimSpace(req.Header.Get(k))
|
||||||
|
sortedHeader = append(sortedHeader, fmt.Sprintf("%s:%s", strings.ToLower(k), strings.ToLower(stringMinifier(v))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(sortedHeader, "\t")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// signingKey is derived from the client secret.
|
||||||
|
// The signing key is computed as the base64 encoding of the SHA–256 HMAC of the timestamp string
|
||||||
|
// (the field value included in the HTTP authorization header described above) with the client secret as the key.
|
||||||
|
func signingKey(config Config, timestamp string) string {
|
||||||
|
key := createSignature(timestamp, config.ClientSecret)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
// The content hash is the base64-encoded SHA–256 hash of the POST body.
|
||||||
|
// For any other request methods, this field is empty. But the tac separator (\t) must be included.
|
||||||
|
// The size of the POST body must be less than or equal to the value specified by the service.
|
||||||
|
// Any request that does not meet this criteria SHOULD be rejected during the signing process,
|
||||||
|
// as the request will be rejected by EdgeGrid.
|
||||||
|
func createContentHash(config Config, req *http.Request) string {
|
||||||
|
var (
|
||||||
|
contentHash string
|
||||||
|
preparedBody string
|
||||||
|
bodyBytes []byte
|
||||||
|
)
|
||||||
|
if req.Body != nil {
|
||||||
|
bodyBytes, _ = ioutil.ReadAll(req.Body)
|
||||||
|
req.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||||
|
preparedBody = string(bodyBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Body is %s", preparedBody)
|
||||||
|
if req.Method == "POST" && len(preparedBody) > 0 {
|
||||||
|
log.Debugf("Signing content: %s", preparedBody)
|
||||||
|
if len(preparedBody) > config.MaxBody {
|
||||||
|
log.Debugf("Data length %d is larger than maximum %d",
|
||||||
|
len(preparedBody), config.MaxBody)
|
||||||
|
|
||||||
|
preparedBody = preparedBody[0:config.MaxBody]
|
||||||
|
log.Debugf("Data truncated to %d for computing the hash", len(preparedBody))
|
||||||
|
}
|
||||||
|
contentHash = createHash(preparedBody)
|
||||||
|
}
|
||||||
|
log.Debugf("Content hash is '%s'", contentHash)
|
||||||
|
return contentHash
|
||||||
|
}
|
||||||
|
|
||||||
|
// The data to sign includes the information from the HTTP request that is relevant to ensuring that the request is authentic.
|
||||||
|
// This data set comprised of the request data combined with the authorization header value (excluding the signature field,
|
||||||
|
// but including the ; right before the signature field).
|
||||||
|
func signingData(config Config, req *http.Request, authHeader string) string {
|
||||||
|
|
||||||
|
dataSign := []string{
|
||||||
|
req.Method,
|
||||||
|
req.URL.Scheme,
|
||||||
|
req.URL.Host,
|
||||||
|
concatPathQuery(req.URL.Path, req.URL.RawQuery),
|
||||||
|
canonicalizeHeaders(config, req),
|
||||||
|
createContentHash(config, req),
|
||||||
|
authHeader,
|
||||||
|
}
|
||||||
|
log.Debugf("Data to sign %s", strings.Join(dataSign, "\t"))
|
||||||
|
return strings.Join(dataSign, "\t")
|
||||||
|
}
|
||||||
|
|
||||||
|
func signingRequest(config Config, req *http.Request, authHeader string, timestamp string) string {
|
||||||
|
return createSignature(signingData(config, req, authHeader),
|
||||||
|
signingKey(config, timestamp))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Authorization header starts with the signing algorithm moniker (name of the algorithm) used to sign the request.
|
||||||
|
// The moniker below identifies EdgeGrid V1, hash message authentication code, SHA–256 as the hash standard.
|
||||||
|
// This moniker is then followed by a space and an ordered list of name value pairs with each field separated by a semicolon.
|
||||||
|
func createAuthHeader(config Config, req *http.Request, timestamp string, nonce string) string {
|
||||||
|
authHeader := fmt.Sprintf("EG1-HMAC-SHA256 client_token=%s;access_token=%s;timestamp=%s;nonce=%s;",
|
||||||
|
config.ClientToken,
|
||||||
|
config.AccessToken,
|
||||||
|
timestamp,
|
||||||
|
nonce,
|
||||||
|
)
|
||||||
|
log.Debugf("Unsigned authorization header: '%s'", authHeader)
|
||||||
|
|
||||||
|
signedAuthHeader := fmt.Sprintf("%ssignature=%s", authHeader, signingRequest(config, req, authHeader, timestamp))
|
||||||
|
|
||||||
|
log.Debugf("Signed authorization header: '%s'", signedAuthHeader)
|
||||||
|
return signedAuthHeader
|
||||||
|
}
|
1
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1/errors.go
generated
vendored
Normal file
1
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1/errors.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package jsonhooks
|
69
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1/jsonhooks.go
generated
vendored
Normal file
69
vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/jsonhooks-v1/jsonhooks.go
generated
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// Package jsonhooks adds hooks that are automatically called before JSON marshaling (PreMarshalJSON) and
|
||||||
|
// after JSON unmarshaling (PostUnmarshalJSON). It does not do so recursively.
|
||||||
|
package jsonhooks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Marshal wraps encoding/json.Marshal, calls v.PreMarshalJSON() if it exists
|
||||||
|
func Marshal(v interface{}) ([]byte, error) {
|
||||||
|
if ImplementsPreJSONMarshaler(v) {
|
||||||
|
err := v.(PreJSONMarshaler).PreMarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal wraps encoding/json.Unmarshal, calls v.PostUnmarshalJSON() if it exists
|
||||||
|
func Unmarshal(data []byte, v interface{}) error {
|
||||||
|
err := json.Unmarshal(data, v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ImplementsPostJSONUnmarshaler(v) {
|
||||||
|
err := v.(PostJSONUnmarshaler).PostUnmarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreJSONMarshaler infers support for the PreMarshalJSON pre-hook
|
||||||
|
type PreJSONMarshaler interface {
|
||||||
|
PreMarshalJSON() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImplementsPreJSONMarshaler checks for support for the PreMarshalJSON pre-hook
|
||||||
|
func ImplementsPreJSONMarshaler(v interface{}) bool {
|
||||||
|
value := reflect.ValueOf(v)
|
||||||
|
if value.Kind() == reflect.Ptr && value.IsNil() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := value.Interface().(PreJSONMarshaler)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostJSONUnmarshaler infers support for the PostUnmarshalJSON post-hook
|
||||||
|
type PostJSONUnmarshaler interface {
|
||||||
|
PostUnmarshalJSON() error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImplementsPostJSONUnmarshaler checks for support for the PostUnmarshalJSON post-hook
|
||||||
|
func ImplementsPostJSONUnmarshaler(v interface{}) bool {
|
||||||
|
value := reflect.ValueOf(v)
|
||||||
|
if value.Kind() == reflect.Ptr && value.IsNil() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := value.Interface().(PostJSONUnmarshaler)
|
||||||
|
return ok
|
||||||
|
}
|
202
vendor/github.com/aws/aws-sdk-go/LICENSE.txt
generated
vendored
Normal file
202
vendor/github.com/aws/aws-sdk-go/LICENSE.txt
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
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(request.NamedHandler{Name: "awssdk.client.LogRequest", Fn: logRequest})
|
||||||
|
c.Handlers.Send.PushBackNamed(request.NamedHandler{Name: "awssdk.client.LogResponse", Fn: logResponse})
|
||||||
|
}
|
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
|
||||||
|
}
|
112
vendor/github.com/aws/aws-sdk-go/aws/client/logger.go
generated
vendored
Normal file
112
vendor/github.com/aws/aws-sdk-go/aws/client/logger.go
generated
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
func logRequest(r *request.Request) {
|
||||||
|
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
|
||||||
|
bodySeekable := aws.IsReaderSeekable(r.Body)
|
||||||
|
dumpedBody, err := httputil.DumpRequestOut(r.HTTPRequest, logBody)
|
||||||
|
if err != nil {
|
||||||
|
r.Config.Logger.Log(fmt.Sprintf(logReqErrMsg, r.ClientInfo.ServiceName, r.Operation.Name, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if logBody {
|
||||||
|
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(dumpedBody)))
|
||||||
|
}
|
||||||
|
|
||||||
|
const logRespMsg = `DEBUG: Response %s/%s Details:
|
||||||
|
---[ RESPONSE ]--------------------------------------
|
||||||
|
%s
|
||||||
|
-----------------------------------------------------`
|
||||||
|
|
||||||
|
const logRespErrMsg = `DEBUG ERROR: Response %s/%s:
|
||||||
|
---[ RESPONSE DUMP ERROR ]-----------------------------
|
||||||
|
%s
|
||||||
|
-----------------------------------------------------`
|
||||||
|
|
||||||
|
func logResponse(r *request.Request) {
|
||||||
|
lw := &logWriter{r.Config.Logger, bytes.NewBuffer(nil)}
|
||||||
|
r.HTTPResponse.Body = &teeReaderCloser{
|
||||||
|
Reader: io.TeeReader(r.HTTPResponse.Body, lw),
|
||||||
|
Source: r.HTTPResponse.Body,
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerFn := func(req *request.Request) {
|
||||||
|
body, err := httputil.DumpResponse(req.HTTPResponse, false)
|
||||||
|
if err != nil {
|
||||||
|
lw.Logger.Log(fmt.Sprintf(logRespErrMsg, req.ClientInfo.ServiceName, req.Operation.Name, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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(fmt.Sprintf(logRespMsg, req.ClientInfo.ServiceName, req.Operation.Name, string(body)))
|
||||||
|
if req.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody) {
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
12
vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
12
vendor/github.com/aws/aws-sdk-go/aws/client/metadata/client_info.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package metadata
|
||||||
|
|
||||||
|
// ClientInfo wraps immutable data from the client.Client structure.
|
||||||
|
type ClientInfo struct {
|
||||||
|
ServiceName string
|
||||||
|
APIVersion string
|
||||||
|
Endpoint string
|
||||||
|
SigningName string
|
||||||
|
SigningRegion string
|
||||||
|
JSONVersion string
|
||||||
|
TargetPrefix string
|
||||||
|
}
|
492
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
Normal file
492
vendor/github.com/aws/aws-sdk-go/aws/config.go
generated
vendored
Normal file
|
@ -0,0 +1,492 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UseServiceDefaultRetries instructs the config to use the service's own
|
||||||
|
// default number of retries. This will be the default action if
|
||||||
|
// Config.MaxRetries is nil also.
|
||||||
|
const UseServiceDefaultRetries = -1
|
||||||
|
|
||||||
|
// RequestRetryer is an alias for a type that implements the request.Retryer
|
||||||
|
// interface.
|
||||||
|
type RequestRetryer interface{}
|
||||||
|
|
||||||
|
// A Config provides service configuration for service clients. By default,
|
||||||
|
// all clients will use the defaults.DefaultConfig tructure.
|
||||||
|
//
|
||||||
|
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||||
|
// // service clients.
|
||||||
|
// sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
// MaxRetries: aws.Int(3),
|
||||||
|
// }))
|
||||||
|
//
|
||||||
|
// // Create S3 service client with a specific Region.
|
||||||
|
// svc := s3.New(sess, &aws.Config{
|
||||||
|
// Region: aws.String("us-west-2"),
|
||||||
|
// })
|
||||||
|
type Config struct {
|
||||||
|
// Enables verbose error printing of all credential chain errors.
|
||||||
|
// Should be used when wanting to see all errors while attempting to
|
||||||
|
// retrieve credentials.
|
||||||
|
CredentialsChainVerboseErrors *bool
|
||||||
|
|
||||||
|
// The credentials object to use when signing requests. Defaults to a
|
||||||
|
// chain of credential providers to search for credentials in environment
|
||||||
|
// variables, shared credential file, and EC2 Instance Roles.
|
||||||
|
Credentials *credentials.Credentials
|
||||||
|
|
||||||
|
// An optional endpoint URL (hostname only or fully qualified URI)
|
||||||
|
// that overrides the default generated endpoint for a client. Set this
|
||||||
|
// to `""` to use the default generated endpoint.
|
||||||
|
//
|
||||||
|
// @note You must still provide a `Region` value when specifying an
|
||||||
|
// endpoint for a client.
|
||||||
|
Endpoint *string
|
||||||
|
|
||||||
|
// The resolver to use for looking up endpoints for AWS service clients
|
||||||
|
// to use based on region.
|
||||||
|
EndpointResolver endpoints.Resolver
|
||||||
|
|
||||||
|
// EnforceShouldRetryCheck is used in the AfterRetryHandler to always call
|
||||||
|
// ShouldRetry regardless of whether or not if request.Retryable is set.
|
||||||
|
// This will utilize ShouldRetry method of custom retryers. If EnforceShouldRetryCheck
|
||||||
|
// is not set, then ShouldRetry will only be called if request.Retryable is nil.
|
||||||
|
// Proper handling of the request.Retryable field is important when setting this field.
|
||||||
|
EnforceShouldRetryCheck *bool
|
||||||
|
|
||||||
|
// The region to send requests to. This parameter is required and must
|
||||||
|
// be configured globally or on a per-client basis unless otherwise
|
||||||
|
// noted. A full list of regions is found in the "Regions and Endpoints"
|
||||||
|
// document.
|
||||||
|
//
|
||||||
|
// @see http://docs.aws.amazon.com/general/latest/gr/rande.html
|
||||||
|
// AWS Regions and Endpoints
|
||||||
|
Region *string
|
||||||
|
|
||||||
|
// Set this to `true` to disable SSL when sending requests. Defaults
|
||||||
|
// to `false`.
|
||||||
|
DisableSSL *bool
|
||||||
|
|
||||||
|
// The HTTP client to use when sending requests. Defaults to
|
||||||
|
// `http.DefaultClient`.
|
||||||
|
HTTPClient *http.Client
|
||||||
|
|
||||||
|
// An integer value representing the logging level. The default log level
|
||||||
|
// is zero (LogOff), which represents no logging. To enable logging set
|
||||||
|
// to a LogLevel Value.
|
||||||
|
LogLevel *LogLevelType
|
||||||
|
|
||||||
|
// The logger writer interface to write logging messages to. Defaults to
|
||||||
|
// standard out.
|
||||||
|
Logger Logger
|
||||||
|
|
||||||
|
// The maximum number of times that a request will be retried for failures.
|
||||||
|
// Defaults to -1, which defers the max retry setting to the service
|
||||||
|
// specific configuration.
|
||||||
|
MaxRetries *int
|
||||||
|
|
||||||
|
// Retryer guides how HTTP requests should be retried in case of
|
||||||
|
// recoverable failures.
|
||||||
|
//
|
||||||
|
// When nil or the value does not implement the request.Retryer interface,
|
||||||
|
// the client.DefaultRetryer will be used.
|
||||||
|
//
|
||||||
|
// When both Retryer and MaxRetries are non-nil, the former is used and
|
||||||
|
// the latter ignored.
|
||||||
|
//
|
||||||
|
// To set the Retryer field in a type-safe manner and with chaining, use
|
||||||
|
// the request.WithRetryer helper function:
|
||||||
|
//
|
||||||
|
// cfg := request.WithRetryer(aws.NewConfig(), myRetryer)
|
||||||
|
//
|
||||||
|
Retryer RequestRetryer
|
||||||
|
|
||||||
|
// Disables semantic parameter validation, which validates input for
|
||||||
|
// missing required fields and/or other semantic request input errors.
|
||||||
|
DisableParamValidation *bool
|
||||||
|
|
||||||
|
// Disables the computation of request and response checksums, e.g.,
|
||||||
|
// CRC32 checksums in Amazon DynamoDB.
|
||||||
|
DisableComputeChecksums *bool
|
||||||
|
|
||||||
|
// Set this to `true` to force the request to use path-style addressing,
|
||||||
|
// i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client
|
||||||
|
// will use virtual hosted bucket addressing when possible
|
||||||
|
// (`http://BUCKET.s3.amazonaws.com/KEY`).
|
||||||
|
//
|
||||||
|
// @note This configuration option is specific to the Amazon S3 service.
|
||||||
|
// @see http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html
|
||||||
|
// Amazon S3: Virtual Hosting of Buckets
|
||||||
|
S3ForcePathStyle *bool
|
||||||
|
|
||||||
|
// Set this to `true` to disable the SDK adding the `Expect: 100-Continue`
|
||||||
|
// header to PUT requests over 2MB of content. 100-Continue instructs the
|
||||||
|
// HTTP client not to send the body until the service responds with a
|
||||||
|
// `continue` status. This is useful to prevent sending the request body
|
||||||
|
// until after the request is authenticated, and validated.
|
||||||
|
//
|
||||||
|
// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html
|
||||||
|
//
|
||||||
|
// 100-Continue is only enabled for Go 1.6 and above. See `http.Transport`'s
|
||||||
|
// `ExpectContinueTimeout` for information on adjusting the continue wait
|
||||||
|
// timeout. https://golang.org/pkg/net/http/#Transport
|
||||||
|
//
|
||||||
|
// You should use this flag to disble 100-Continue if you experience issues
|
||||||
|
// with proxies or third party S3 compatible services.
|
||||||
|
S3Disable100Continue *bool
|
||||||
|
|
||||||
|
// Set this to `true` to enable S3 Accelerate feature. For all operations
|
||||||
|
// compatible with S3 Accelerate will use the accelerate endpoint for
|
||||||
|
// requests. Requests not compatible will fall back to normal S3 requests.
|
||||||
|
//
|
||||||
|
// The bucket must be enable for accelerate to be used with S3 client with
|
||||||
|
// accelerate enabled. If the bucket is not enabled for accelerate an error
|
||||||
|
// will be returned. The bucket name must be DNS compatible to also work
|
||||||
|
// with accelerate.
|
||||||
|
S3UseAccelerate *bool
|
||||||
|
|
||||||
|
// S3DisableContentMD5Validation config option is temporarily disabled,
|
||||||
|
// For S3 GetObject API calls, #1837.
|
||||||
|
//
|
||||||
|
// Set this to `true` to disable the S3 service client from automatically
|
||||||
|
// adding the ContentMD5 to S3 Object Put and Upload API calls. This option
|
||||||
|
// will also disable the SDK from performing object ContentMD5 validation
|
||||||
|
// on GetObject API calls.
|
||||||
|
S3DisableContentMD5Validation *bool
|
||||||
|
|
||||||
|
// Set this to `true` to disable the EC2Metadata client from overriding the
|
||||||
|
// default http.Client's Timeout. This is helpful if you do not want the
|
||||||
|
// EC2Metadata client to create a new http.Client. This options is only
|
||||||
|
// meaningful if you're not already using a custom HTTP client with the
|
||||||
|
// SDK. Enabled by default.
|
||||||
|
//
|
||||||
|
// Must be set and provided to the session.NewSession() in order to disable
|
||||||
|
// the EC2Metadata overriding the timeout for default credentials chain.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// sess := session.Must(session.NewSession(aws.NewConfig()
|
||||||
|
// .WithEC2MetadataDiableTimeoutOverride(true)))
|
||||||
|
//
|
||||||
|
// svc := s3.New(sess)
|
||||||
|
//
|
||||||
|
EC2MetadataDisableTimeoutOverride *bool
|
||||||
|
|
||||||
|
// Instructs the endpoint to be generated for a service client to
|
||||||
|
// be the dual stack endpoint. The dual stack endpoint will support
|
||||||
|
// both IPv4 and IPv6 addressing.
|
||||||
|
//
|
||||||
|
// Setting this for a service which does not support dual stack will fail
|
||||||
|
// to make requets. It is not recommended to set this value on the session
|
||||||
|
// as it will apply to all service clients created with the session. Even
|
||||||
|
// services which don't support dual stack endpoints.
|
||||||
|
//
|
||||||
|
// If the Endpoint config value is also provided the UseDualStack flag
|
||||||
|
// will be ignored.
|
||||||
|
//
|
||||||
|
// Only supported with.
|
||||||
|
//
|
||||||
|
// sess := session.Must(session.NewSession())
|
||||||
|
//
|
||||||
|
// svc := s3.New(sess, &aws.Config{
|
||||||
|
// UseDualStack: aws.Bool(true),
|
||||||
|
// })
|
||||||
|
UseDualStack *bool
|
||||||
|
|
||||||
|
// SleepDelay is an override for the func the SDK will call when sleeping
|
||||||
|
// during the lifecycle of a request. Specifically this will be used for
|
||||||
|
// request delays. This value should only be used for testing. To adjust
|
||||||
|
// the delay of a request see the aws/client.DefaultRetryer and
|
||||||
|
// aws/request.Retryer.
|
||||||
|
//
|
||||||
|
// SleepDelay will prevent any Context from being used for canceling retry
|
||||||
|
// delay of an API operation. It is recommended to not use SleepDelay at all
|
||||||
|
// and specify a Retryer instead.
|
||||||
|
SleepDelay func(time.Duration)
|
||||||
|
|
||||||
|
// DisableRestProtocolURICleaning will not clean the URL path when making rest protocol requests.
|
||||||
|
// Will default to false. This would only be used for empty directory names in s3 requests.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// sess := session.Must(session.NewSession(&aws.Config{
|
||||||
|
// DisableRestProtocolURICleaning: aws.Bool(true),
|
||||||
|
// }))
|
||||||
|
//
|
||||||
|
// svc := s3.New(sess)
|
||||||
|
// out, err := svc.GetObject(&s3.GetObjectInput {
|
||||||
|
// Bucket: aws.String("bucketname"),
|
||||||
|
// Key: aws.String("//foo//bar//moo"),
|
||||||
|
// })
|
||||||
|
DisableRestProtocolURICleaning *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConfig returns a new Config pointer that can be chained with builder
|
||||||
|
// methods to set multiple configuration values inline without using pointers.
|
||||||
|
//
|
||||||
|
// // Create Session with MaxRetry configuration to be shared by multiple
|
||||||
|
// // service clients.
|
||||||
|
// sess := session.Must(session.NewSession(aws.NewConfig().
|
||||||
|
// WithMaxRetries(3),
|
||||||
|
// ))
|
||||||
|
//
|
||||||
|
// // Create S3 service client with a specific Region.
|
||||||
|
// svc := s3.New(sess, aws.NewConfig().
|
||||||
|
// WithRegion("us-west-2"),
|
||||||
|
// )
|
||||||
|
func NewConfig() *Config {
|
||||||
|
return &Config{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCredentialsChainVerboseErrors sets a config verbose errors boolean and returning
|
||||||
|
// a Config pointer.
|
||||||
|
func (c *Config) WithCredentialsChainVerboseErrors(verboseErrs bool) *Config {
|
||||||
|
c.CredentialsChainVerboseErrors = &verboseErrs
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCredentials sets a config Credentials value returning a Config pointer
|
||||||
|
// for chaining.
|
||||||
|
func (c *Config) WithCredentials(creds *credentials.Credentials) *Config {
|
||||||
|
c.Credentials = creds
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEndpoint sets a config Endpoint value returning a Config pointer for
|
||||||
|
// chaining.
|
||||||
|
func (c *Config) WithEndpoint(endpoint string) *Config {
|
||||||
|
c.Endpoint = &endpoint
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEndpointResolver sets a config EndpointResolver value returning a
|
||||||
|
// Config pointer for chaining.
|
||||||
|
func (c *Config) WithEndpointResolver(resolver endpoints.Resolver) *Config {
|
||||||
|
c.EndpointResolver = resolver
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithRegion sets a config Region value returning a Config pointer for
|
||||||
|
// chaining.
|
||||||
|
func (c *Config) WithRegion(region string) *Config {
|
||||||
|
c.Region = ®ion
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDisableSSL sets a config DisableSSL value returning a Config pointer
|
||||||
|
// for chaining.
|
||||||
|
func (c *Config) WithDisableSSL(disable bool) *Config {
|
||||||
|
c.DisableSSL = &disable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithHTTPClient sets a config HTTPClient value returning a Config pointer
|
||||||
|
// for chaining.
|
||||||
|
func (c *Config) WithHTTPClient(client *http.Client) *Config {
|
||||||
|
c.HTTPClient = client
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxRetries sets a config MaxRetries value returning a Config pointer
|
||||||
|
// for chaining.
|
||||||
|
func (c *Config) WithMaxRetries(max int) *Config {
|
||||||
|
c.MaxRetries = &max
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDisableParamValidation sets a config DisableParamValidation value
|
||||||
|
// returning a Config pointer for chaining.
|
||||||
|
func (c *Config) WithDisableParamValidation(disable bool) *Config {
|
||||||
|
c.DisableParamValidation = &disable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDisableComputeChecksums sets a config DisableComputeChecksums value
|
||||||
|
// returning a Config pointer for chaining.
|
||||||
|
func (c *Config) WithDisableComputeChecksums(disable bool) *Config {
|
||||||
|
c.DisableComputeChecksums = &disable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLogLevel sets a config LogLevel value returning a Config pointer for
|
||||||
|
// chaining.
|
||||||
|
func (c *Config) WithLogLevel(level LogLevelType) *Config {
|
||||||
|
c.LogLevel = &level
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLogger sets a config Logger value returning a Config pointer for
|
||||||
|
// chaining.
|
||||||
|
func (c *Config) WithLogger(logger Logger) *Config {
|
||||||
|
c.Logger = logger
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3ForcePathStyle sets a config S3ForcePathStyle value returning a Config
|
||||||
|
// pointer for chaining.
|
||||||
|
func (c *Config) WithS3ForcePathStyle(force bool) *Config {
|
||||||
|
c.S3ForcePathStyle = &force
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3Disable100Continue sets a config S3Disable100Continue value returning
|
||||||
|
// a Config pointer for chaining.
|
||||||
|
func (c *Config) WithS3Disable100Continue(disable bool) *Config {
|
||||||
|
c.S3Disable100Continue = &disable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3UseAccelerate sets a config S3UseAccelerate value returning a Config
|
||||||
|
// pointer for chaining.
|
||||||
|
func (c *Config) WithS3UseAccelerate(enable bool) *Config {
|
||||||
|
c.S3UseAccelerate = &enable
|
||||||
|
return c
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithS3DisableContentMD5Validation sets a config
|
||||||
|
// S3DisableContentMD5Validation value returning a Config pointer for chaining.
|
||||||
|
func (c *Config) WithS3DisableContentMD5Validation(enable bool) *Config {
|
||||||
|
c.S3DisableContentMD5Validation = &enable
|
||||||
|
return c
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithUseDualStack sets a config UseDualStack value returning a Config
|
||||||
|
// pointer for chaining.
|
||||||
|
func (c *Config) WithUseDualStack(enable bool) *Config {
|
||||||
|
c.UseDualStack = &enable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithEC2MetadataDisableTimeoutOverride sets a config EC2MetadataDisableTimeoutOverride value
|
||||||
|
// returning a Config pointer for chaining.
|
||||||
|
func (c *Config) WithEC2MetadataDisableTimeoutOverride(enable bool) *Config {
|
||||||
|
c.EC2MetadataDisableTimeoutOverride = &enable
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSleepDelay overrides the function used to sleep while waiting for the
|
||||||
|
// next retry. Defaults to time.Sleep.
|
||||||
|
func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config {
|
||||||
|
c.SleepDelay = fn
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeIn merges the passed in configs into the existing config object.
|
||||||
|
func (c *Config) MergeIn(cfgs ...*Config) {
|
||||||
|
for _, other := range cfgs {
|
||||||
|
mergeInConfig(c, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeInConfig(dst *Config, other *Config) {
|
||||||
|
if other == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.CredentialsChainVerboseErrors != nil {
|
||||||
|
dst.CredentialsChainVerboseErrors = other.CredentialsChainVerboseErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Credentials != nil {
|
||||||
|
dst.Credentials = other.Credentials
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Endpoint != nil {
|
||||||
|
dst.Endpoint = other.Endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.EndpointResolver != nil {
|
||||||
|
dst.EndpointResolver = other.EndpointResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Region != nil {
|
||||||
|
dst.Region = other.Region
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableSSL != nil {
|
||||||
|
dst.DisableSSL = other.DisableSSL
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.HTTPClient != nil {
|
||||||
|
dst.HTTPClient = other.HTTPClient
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.LogLevel != nil {
|
||||||
|
dst.LogLevel = other.LogLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Logger != nil {
|
||||||
|
dst.Logger = other.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.MaxRetries != nil {
|
||||||
|
dst.MaxRetries = other.MaxRetries
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.Retryer != nil {
|
||||||
|
dst.Retryer = other.Retryer
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableParamValidation != nil {
|
||||||
|
dst.DisableParamValidation = other.DisableParamValidation
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableComputeChecksums != nil {
|
||||||
|
dst.DisableComputeChecksums = other.DisableComputeChecksums
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3ForcePathStyle != nil {
|
||||||
|
dst.S3ForcePathStyle = other.S3ForcePathStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3Disable100Continue != nil {
|
||||||
|
dst.S3Disable100Continue = other.S3Disable100Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3UseAccelerate != nil {
|
||||||
|
dst.S3UseAccelerate = other.S3UseAccelerate
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.S3DisableContentMD5Validation != nil {
|
||||||
|
dst.S3DisableContentMD5Validation = other.S3DisableContentMD5Validation
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.UseDualStack != nil {
|
||||||
|
dst.UseDualStack = other.UseDualStack
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.EC2MetadataDisableTimeoutOverride != nil {
|
||||||
|
dst.EC2MetadataDisableTimeoutOverride = other.EC2MetadataDisableTimeoutOverride
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.SleepDelay != nil {
|
||||||
|
dst.SleepDelay = other.SleepDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.DisableRestProtocolURICleaning != nil {
|
||||||
|
dst.DisableRestProtocolURICleaning = other.DisableRestProtocolURICleaning
|
||||||
|
}
|
||||||
|
|
||||||
|
if other.EnforceShouldRetryCheck != nil {
|
||||||
|
dst.EnforceShouldRetryCheck = other.EnforceShouldRetryCheck
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy will return a shallow copy of the Config object. If any additional
|
||||||
|
// configurations are provided they will be merged into the new config returned.
|
||||||
|
func (c *Config) Copy(cfgs ...*Config) *Config {
|
||||||
|
dst := &Config{}
|
||||||
|
dst.MergeIn(c)
|
||||||
|
|
||||||
|
for _, cfg := range cfgs {
|
||||||
|
dst.MergeIn(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
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
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue