mirror of
https://github.com/vxcontrol/rancher-letsencrypt.git
synced 2026-07-01 00:08:01 -04:00
Bump version of lego to 1.0.1
This commit is contained in:
Executable → Regular
+1
-1
@@ -2,7 +2,7 @@ FROM alpine:3.5
|
||||
|
||||
RUN apk add --no-cache ca-certificates openssl bash
|
||||
|
||||
ENV LETSENCRYPT_RELEASE v0.5.0
|
||||
ENV LETSENCRYPT_RELEASE v1.0.0
|
||||
ENV SSL_SCRIPT_COMMIT 08278ace626ada71384fc949bd637f4c15b03b53
|
||||
|
||||
RUN wget -O /usr/bin/update-rancher-ssl https://raw.githubusercontent.com/rancher/rancher/${SSL_SCRIPT_COMMIT}/server/bin/update-rancher-ssl && \
|
||||
|
||||
+14
-19
@@ -13,11 +13,12 @@ import (
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
lego "github.com/xenolf/lego/acme"
|
||||
loge "github.com/xenolf/lego/log"
|
||||
)
|
||||
|
||||
const (
|
||||
StorageDir = "/etc/letsencrypt"
|
||||
ProductionApiUri = "https://acme-v01.api.letsencrypt.org/directory"
|
||||
ProductionApiUri = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
StagingApiUri = "https://acme-staging.api.letsencrypt.org/directory"
|
||||
)
|
||||
|
||||
@@ -97,23 +98,16 @@ func NewClient(email string, kt KeyType, apiVer ApiVersion, dnsResolvers []strin
|
||||
return nil, fmt.Errorf("Could not create client: %v", err)
|
||||
}
|
||||
|
||||
lego.Logger = log.New(ioutil.Discard, "", 0)
|
||||
loge.Logger = log.New(ioutil.Discard, "", 0)
|
||||
|
||||
if acc.Registration == nil {
|
||||
logrus.Infof("Creating Let's Encrypt account for %s", email)
|
||||
reg, err := client.Register()
|
||||
reg, err := client.Register(true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to register account: %v", err)
|
||||
}
|
||||
|
||||
acc.Registration = reg
|
||||
if acc.Registration.Body.Agreement == "" {
|
||||
err = client.AgreeToTOS()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Could not agree to TOS: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = acc.Save()
|
||||
if err != nil {
|
||||
logrus.Errorf("Could not save account data: %v", err)
|
||||
@@ -133,9 +127,9 @@ func NewClient(email string, kt KeyType, apiVer ApiVersion, dnsResolvers []strin
|
||||
}
|
||||
|
||||
if challenge == lego.DNS01 {
|
||||
client.ExcludeChallenges([]lego.Challenge{lego.HTTP01, lego.TLSSNI01})
|
||||
client.ExcludeChallenges([]lego.Challenge{lego.HTTP01})
|
||||
} else if challenge == lego.HTTP01 {
|
||||
client.ExcludeChallenges([]lego.Challenge{lego.TLSSNI01, lego.DNS01})
|
||||
client.ExcludeChallenges([]lego.Challenge{lego.DNS01})
|
||||
}
|
||||
|
||||
if len(dnsResolvers) > 0 {
|
||||
@@ -153,20 +147,21 @@ func NewClient(email string, kt KeyType, apiVer ApiVersion, dnsResolvers []strin
|
||||
func (c *Client) EnableLogs() {
|
||||
logger := logrus.New()
|
||||
logger.Out = os.Stdout
|
||||
lego.Logger = log.New(logger.Writer(), "", 0)
|
||||
loge.Logger = log.New(logger.Writer(), "", 0)
|
||||
}
|
||||
|
||||
// Issue obtains a new SAN certificate from the Lets Encrypt CA
|
||||
func (c *Client) Issue(certName string, domains []string) (*AcmeCertificate, map[string]error) {
|
||||
certRes, failures := c.client.ObtainCertificate(domains, true, nil, false)
|
||||
if len(failures) > 0 {
|
||||
return nil, failures
|
||||
func (c *Client) Issue(certName string, domains []string) (*AcmeCertificate, error) {
|
||||
certRes, err := c.client.ObtainCertificate(domains, true, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dnsNames := dnsNamesIdentifier(domains)
|
||||
acmeCert, err := c.saveCertificate(certName, dnsNames, certRes)
|
||||
if err != nil {
|
||||
logrus.Fatalf("Error saving certificate '%s': %v", certName, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return acmeCert, nil
|
||||
@@ -261,7 +256,7 @@ func (c *Client) loadCertificateByName(certName string) (AcmeCertificate, error)
|
||||
return acmeCert, nil
|
||||
}
|
||||
|
||||
func (c *Client) saveCertificate(certName, dnsNames string, certRes lego.CertificateResource) (*AcmeCertificate, error) {
|
||||
func (c *Client) saveCertificate(certName, dnsNames string, certRes *lego.CertificateResource) (*AcmeCertificate, error) {
|
||||
expiryDate, err := lego.GetPEMCertExpiration(certRes.Certificate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read certificate expiry date: %v", err)
|
||||
@@ -272,7 +267,7 @@ func (c *Client) saveCertificate(certName, dnsNames string, certRes lego.Certifi
|
||||
}
|
||||
|
||||
acmeCert := AcmeCertificate{
|
||||
CertificateResource: certRes,
|
||||
CertificateResource: *certRes,
|
||||
ExpiryDate: expiryDate,
|
||||
SerialNumber: serialNumber,
|
||||
DnsNames: dnsNames,
|
||||
|
||||
+3
-5
@@ -73,11 +73,9 @@ func (c *Context) startup() {
|
||||
|
||||
logrus.Infof("Trying to obtain SSL certificate (%s) from Let's Encrypt %s CA", strings.Join(c.Domains, ","), c.Acme.ApiVersion())
|
||||
|
||||
acmeCert, failures := c.Acme.Issue(c.CertificateName, c.Domains)
|
||||
if len(failures) > 0 {
|
||||
for k, v := range failures {
|
||||
logrus.Errorf("[%s] Error obtaining certificate: %s", k, v.Error())
|
||||
}
|
||||
acmeCert, err = c.Acme.Issue(c.CertificateName, c.Domains)
|
||||
if err != nil {
|
||||
logrus.Errorf("[%s] Error obtaining certificate: %s", err, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ FROM alpine:3.5
|
||||
|
||||
RUN apk add --no-cache ca-certificates openssl bash
|
||||
|
||||
ENV LETSENCRYPT_RELEASE v0.5.0
|
||||
ENV LETSENCRYPT_RELEASE v1.0.0
|
||||
ENV SSL_SCRIPT_COMMIT 08278ace626ada71384fc949bd637f4c15b03b53
|
||||
|
||||
RUN wget -O /usr/bin/update-rancher-ssl https://raw.githubusercontent.com/rancher/rancher/${SSL_SCRIPT_COMMIT}/server/bin/update-rancher-ssl && \
|
||||
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
make deps && make -j 4 build
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
env
|
||||
exec "$@" &
|
||||
wait
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package: github.com/vxcontrol/rancher-letsencrypt
|
||||
import:
|
||||
- package: github.com/Azure/azure-sdk-for-go
|
||||
version: v17.3.0
|
||||
- package: github.com/Azure/go-autorest
|
||||
version: v10.10.0
|
||||
- package: github.com/JamesClonk/vultr
|
||||
version: 1.13.0
|
||||
- package: github.com/Sirupsen/logrus
|
||||
version: v1.0.5
|
||||
- package: github.com/aws/aws-sdk-go
|
||||
version: v1.14.3
|
||||
- package: github.com/dgrijalva/jwt-go
|
||||
version: 6c8dedd
|
||||
- package: github.com/dnsimple/dnsimple-go
|
||||
version: 5a5b427
|
||||
- package: github.com/edeckers/auroradnsclient
|
||||
version: 8b777c1
|
||||
- package: github.com/go-ini/ini
|
||||
version: e7fea39
|
||||
- package: github.com/google/go-querystring
|
||||
version: 53e6ce1
|
||||
- package: github.com/gorilla/websocket
|
||||
version: a91eba7
|
||||
- package: github.com/jmespath/go-jmespath
|
||||
version: bd40a43
|
||||
- package: github.com/juju/ratelimit
|
||||
version: 77ed1c8
|
||||
- package: github.com/miekg/dns
|
||||
version: f282f80
|
||||
- package: github.com/ovh/go-ovh
|
||||
version: d220717
|
||||
- package: github.com/pkg/errors
|
||||
version: c605e28
|
||||
- package: github.com/rancher/go-rancher/v2
|
||||
version: 939fd85
|
||||
- package: github.com/xenolf/lego
|
||||
version: 7fedfd1
|
||||
- package: golang.org/x/crypto
|
||||
version: ab89591
|
||||
- package: golang.org/x/sys
|
||||
version: f845067
|
||||
- package: gopkg.in/ini.v1
|
||||
version: e7fea39
|
||||
- package: gopkg.in/ns1/ns1-go.v2
|
||||
version: c563826
|
||||
- package: gopkg.in/square/go-jose.v2
|
||||
version: v2.1.6
|
||||
+23
-25
@@ -1,28 +1,26 @@
|
||||
# package
|
||||
github.com/vxcontrol/rancher-letsencrypt
|
||||
|
||||
github.com/aws/aws-sdk-go v1.8.6
|
||||
github.com/Azure/azure-sdk-for-go v10.0.2-beta
|
||||
github.com/Azure/go-autorest v8.0.0
|
||||
github.com/dgrijalva/jwt-go 6c8dedd
|
||||
github.com/dnsimple/dnsimple-go 5a5b427
|
||||
github.com/edeckers/auroradnsclient 8b777c1
|
||||
github.com/go-ini/ini e7fea39
|
||||
github.com/google/go-querystring 53e6ce1
|
||||
github.com/gorilla/websocket a91eba7
|
||||
github.com/JamesClonk/vultr 1.13.0
|
||||
github.com/jmespath/go-jmespath bd40a43
|
||||
github.com/juju/ratelimit 77ed1c8
|
||||
github.com/miekg/dns f282f80
|
||||
github.com/ovh/go-ovh d220717
|
||||
github.com/pkg/errors c605e28
|
||||
github.com/rancher/go-rancher/v2 939fd85
|
||||
github.com/Sirupsen/logrus v0.11.5
|
||||
github.com/xenolf/lego aaa8e70
|
||||
golang.org/x/crypto ab89591
|
||||
golang.org/x/net 84f0e6f
|
||||
golang.org/x/sys f845067
|
||||
golang.org/x/text 767daa1
|
||||
gopkg.in/ini.v1 e7fea39
|
||||
gopkg.in/ns1/ns1-go.v2 c563826
|
||||
gopkg.in/square/go-jose.v1 aa2e30f
|
||||
github.com/aws/aws-sdk-go v1.14.3
|
||||
github.com/Azure/azure-sdk-for-go v17.3.0
|
||||
github.com/Azure/go-autorest v10.10.0
|
||||
github.com/dgrijalva/jwt-go 6c8dedd
|
||||
github.com/dnsimple/dnsimple-go 5a5b427
|
||||
github.com/edeckers/auroradnsclient 8b777c1
|
||||
github.com/go-ini/ini e7fea39
|
||||
github.com/google/go-querystring 53e6ce1
|
||||
github.com/gorilla/websocket a91eba7
|
||||
github.com/JamesClonk/vultr 1.13.0
|
||||
github.com/jmespath/go-jmespath bd40a43
|
||||
github.com/juju/ratelimit 77ed1c8
|
||||
github.com/miekg/dns f282f80
|
||||
github.com/ovh/go-ovh d220717
|
||||
github.com/pkg/errors c605e28
|
||||
github.com/rancher/go-rancher/v2 939fd85
|
||||
github.com/Sirupsen/logrus v1.0.5
|
||||
github.com/xenolf/lego 7fedfd1
|
||||
golang.org/x/crypto ab89591
|
||||
golang.org/x/sys f845067
|
||||
gopkg.in/ini.v1 e7fea39
|
||||
gopkg.in/ns1/ns1-go.v2 c563826
|
||||
gopkg.in/square/go-jose.v2 v2.1.6
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ _obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
# *.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
|
||||
+24
-22
@@ -1,32 +1,34 @@
|
||||
sudo: false
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.7
|
||||
- 1.8
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- master
|
||||
|
||||
env:
|
||||
global:
|
||||
- DEP_VERSION="0.4.1"
|
||||
- DEP_SHA=31144e465e52ffbc0035248a10ddea61a09bf28b00784fd3fdd9882c8cbb2315
|
||||
- IGNORE_BREAKING_CHANGES=true
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: master
|
||||
|
||||
before_install:
|
||||
- curl -fL -o $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v$DEP_VERSION/dep-linux-amd64 && echo "$DEP_SHA $GOPATH/bin/dep" | sha256sum -c - && chmod +x $GOPATH/bin/dep
|
||||
|
||||
install:
|
||||
- go get -u github.com/golang/lint/golint
|
||||
- go get -u github.com/Masterminds/glide
|
||||
- go get -u golang.org/x/net/context
|
||||
- go get -u gopkg.in/godo.v2/cmd/godo
|
||||
- export GO15VENDOREXPERIMENT=1
|
||||
- glide install
|
||||
- dep ensure
|
||||
|
||||
script:
|
||||
- bash rungas.sh
|
||||
- test -z "$(gofmt -s -l $(find ./arm/* -type d -print) | tee /dev/stderr)"
|
||||
- test -z "$(gofmt -s -l -w management | tee /dev/stderr)"
|
||||
- test -z "$(gofmt -s -l -w storage | tee /dev/stderr)"
|
||||
- test -z "$(gofmt -s -l -w Gododir | tee /dev/stderr)"
|
||||
- test -z "$(go build $(find ./* -type d -print | grep -v '^./vendor$' | grep -v '^./storage$') | tee /dev/stderr)"
|
||||
- test -z "$(go vet $(find ./arm/* -type d -print) | tee /dev/stderr)"
|
||||
- test -z "$(golint ./arm/... | tee /dev/stderr)"
|
||||
- go test -v ./management/...
|
||||
- go test -v ./storage/...
|
||||
- test -z "$(golint ./management/... | grep -v 'should have comment' | grep -v 'stutters' | tee /dev/stderr)"
|
||||
- go vet ./management/...
|
||||
- go vet ./storage/...
|
||||
- test -z "$(golint ./Gododir/... | tee /dev/stderr)"
|
||||
- go vet ./Gododir/...
|
||||
- grep -L -r --include *.go --exclude-dir vendor -P "Copyright (\d{4}|\(c\)) Microsoft" ./ | tee /dev/stderr | test -z "$(< /dev/stdin)"
|
||||
- go build $(go list ./... | grep -v vendor)
|
||||
- test -z "$(go fmt $(go list ./... | grep -v vendor) | tee /dev/stderr)"
|
||||
- go vet $(go list ./... | grep -v vendor)
|
||||
- go test $(sh ./findTestedPackages.sh)
|
||||
- go run ./tools/apidiff/main.go packages ./services FETCH_HEAD~1 FETCH_HEAD --copyrepo --breakingchanges || $IGNORE_BREAKING_CHANGES
|
||||
|
||||
+429
-393
@@ -1,484 +1,520 @@
|
||||
# CHANGELOG
|
||||
|
||||
-----
|
||||
## `v10.0.0-beta`
|
||||
### ARM
|
||||
In addition to the tabulated changes below, each package had the following updates:
|
||||
- Long running operations now run inside a goroutine and return channels for the response and the errors.
|
||||
- Some functions changed from returning `autorest.Response` to return the already unmarshaled struct.
|
||||
- Uses go-autorest v8.0.0.
|
||||
## `v17.3.0`
|
||||
|
||||
| api | version | note |
|
||||
|:------------------------------------|:-------------------|:------------------------------------|
|
||||
| arm/advisor | 2017-04-19 | new |
|
||||
| arm/analysisservices | 2016-05-16 | refactor |
|
||||
| arm/apimanagement | 2016-10-10 | update to latest swagger & refactor |
|
||||
| arm/appinsights | 2015-05-01 | new |
|
||||
| arm/automation | 2015-10-31 | new |
|
||||
| arm/billing | 2017-04-24-preview | update to latest swagger & refactor |
|
||||
| arm/cdn | 2016-10-02 | refactor |
|
||||
| arm/commerce | 2015-06-01-preview | refactor |
|
||||
| arm/compute | 2016-04-30-preview | refactor |
|
||||
| arm/consumption | 2017-04-24-preview | new |
|
||||
| arm/containerregistry | 2017-03-01 | update to latest swagger & refactor |
|
||||
| arm/containerservice | 2017-01-31 | update to latest swagger & refactor |
|
||||
| arm/customer-insights | 2017-01-01 | refactor |
|
||||
| arm/datalake-analytics/account | 2016-11-01 | refactor |
|
||||
| arm/datalake-store/account | 2016-11-01 | refactor |
|
||||
| arm/devtestlabs | 2016-05-15 | refactor |
|
||||
| arm/disk | 2016-04-30-preview | refactor |
|
||||
| arm/dns | 2016-04-01 | refactor |
|
||||
| arm/documentdb | 2015-04-08 | refactor |
|
||||
| arm/eventhub | 2015-08-01 | refactor |
|
||||
| arm/graphrbac | 1.6 | refactor |
|
||||
| arm/hdinsight | 2015-03-01-preview | new |
|
||||
| arm/insights | multiple | new |
|
||||
| arm/intune | 2015-01-14-preview | refactor |
|
||||
| arm/iothub | 2016-02-03 | refactor |
|
||||
| arm/machinelearning/commitmentplans | 2016-05-01-preview | refactor |
|
||||
| arm/machinelearning/webservices | 2017-01-01 | update to latest swagger & refactor |
|
||||
| arm/monitor | multiple | new |
|
||||
| arm/network | 2017-03-01 | update to latest swagger & refactor |
|
||||
| arm/notificationhubs | 2017-04-01 | update to latest swagger & refactor |
|
||||
| arm/operationalinsights | 2015-11-01-preview | update to latest swagger & refactor |
|
||||
| arm/powerbiembedded | 2016-01-29 | refactor |
|
||||
| arm/recoveryservices | 2016-12-01 | refactor |
|
||||
| arm/recoveryservicesbackup | 2016-12-01 | new |
|
||||
| arm/redis | 2016-04-01 | refactor |
|
||||
| arm/relay | 2016-07-01 | new |
|
||||
| arm/resourcehealth | 2015-01-01 | new |
|
||||
| arm/resources/features | 2015-12-01 | refactor |
|
||||
| arm/resources/links | 2016-09-01 | refactor |
|
||||
| arm/resources/resources | 2016-09-01 | refactor |
|
||||
| arm/resources/subscriptions | 2016-06-01 | refactor |
|
||||
| arm/scheduler | 2016-03-01 | refactor |
|
||||
| arm/servermanagement | 2016-07-01-preview | refactor |
|
||||
| arm/servicebus | 2015-08-01 | refactor |
|
||||
| arm/servicefabric | 2016-09-01 | new |
|
||||
| arm/service-map | 2015-11-01-preview | refactor |
|
||||
| arm/sql | multiple | update to latest swagger & refactor |
|
||||
| arm/storage | 2016-12-01 | update to latest swagger & refactor |
|
||||
| arm/storageimportexport | 2016-11-01 | refactor |
|
||||
| arm/web | multiple | refactor |
|
||||
### New Services
|
||||
|
||||
### Data plane
|
||||
| api | version | note |
|
||||
|:------------------------------------|:-------------------|:------------------------------------|
|
||||
| dataplane/keyvault | 2016-10-01 | refactor |
|
||||
| Package Name | API Version |
|
||||
| --------------------: | :-----------------: |
|
||||
| containerinstance | 2018-06-01 |
|
||||
| reservations | 2018-06-01 |
|
||||
|
||||
### Storage
|
||||
Storage has returned to this repo.
|
||||
It has also been refactored:
|
||||
- Blobs, containers, tables, etc are now method receivers. These structs are the ones being
|
||||
updated with each operation.
|
||||
- When creating a client, the SDK checks if the storage account provided is valid.
|
||||
- Added retry logic. It provides the flexibility for user to provide their own retry logic.
|
||||
- Added operations:
|
||||
- Get table
|
||||
- Get entity
|
||||
- Get and set queue ACL
|
||||
- Table batch
|
||||
- Page blob incremental copy
|
||||
- All operations that previously had `extraHeaders` as parameter now recieve a struct with well
|
||||
defined possible headers and other options. Some functions are easier to use.
|
||||
- Storage tests now use HTTP recordings.
|
||||
### Updated Services
|
||||
|
||||
### Generated code notes
|
||||
- [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) commit: 519980465d9c195622d466dc4601b1999a448ed5
|
||||
- [AutoRest](https://github.com/Azure/autorest) commit: ced950d64e39735b84d41876a56b54b27c227dc7
|
||||
| Package Name | API Version |
|
||||
| --------------------: | :-----------------: |
|
||||
| datafactory | 2017-09-01 |
|
||||
| network | 2015-06-15 |
|
||||
|
||||
## `v9.0.0-beta`
|
||||
### ARM
|
||||
In addition to the tabulated changes below, each package had the following updates:
|
||||
- API Version is now associated with individual methods, instead of the client. This was done to
|
||||
support composite swaggers, which logically may contain more than one API Version.
|
||||
- Version numbers are now calculated in the generator instead of at runtime. This keeps us from
|
||||
adding new allocations, while removing the race-conditions that were added.
|
||||
## `v17.2.0`
|
||||
|
||||
| api | version | note |
|
||||
|:------------------------------------|:-------------------|:-----------------------------------|
|
||||
| arm/analysisservices | 2016-05-16 | update to latest swagger |
|
||||
| arm/authorization | 2015-07-01 | refactoring |
|
||||
| arm/batch | 2017-01-01 | update to latest swagger &refactor |
|
||||
| arm/cdn | 2016-10-02 | update to latest swagger |
|
||||
| arm/compute | 2016-04-30-preview | update to latest swagger |
|
||||
| arm/dns | 2016-04-01 | update to latest swagger &refactor |
|
||||
| arm/eventhub | 2015-08-01 | refactoring |
|
||||
| arm/logic | 2016-06-01 | update to latest swagger &refactor |
|
||||
| arm/notificationshub | 2016-03-01 | update to latest swagger &refactor |
|
||||
| arm/redis | 2016-04-01 | update to latest swagger &refactor |
|
||||
| arm/resources/resources | 2016-09-01 | update to latest swagger |
|
||||
| arm/servicebus | 2015-08-01 | update to latest swagger |
|
||||
| arm/sql | 2014-04-01 | update to latest swagger |
|
||||
| arm/web | multiple | generating from composite |
|
||||
| datalake-analytics/account | 2016-11-01 | update to latest swagger |
|
||||
| datalake-store/filesystem | 2016-11-01 | update to latest swagger |
|
||||
### New Services
|
||||
|
||||
### Storage
|
||||
Storage has been moved to its own repository which can be found here:
|
||||
https://github.com/Azure/azure-storage-go
|
||||
| Package Name | API Version |
|
||||
| --------------------: | :-----------------: |
|
||||
| managedapplications | 2018-06-01 |
|
||||
| resources | 2018-05-01 |
|
||||
|
||||
For backwards compatibility, a submodule has been added to this repo. However, consuming storage
|
||||
via this repository is deprecated and may be deleted in future versions.
|
||||
### Updated Services
|
||||
|
||||
## `v8.1.0-beta`
|
||||
### ARM
|
||||
| api | version | note |
|
||||
|:------------------------------------|:-------------------|:-----------------------------------|
|
||||
| arm/apimanagement | 2016-07-07 | new |
|
||||
| arm/apideployment | 2016-07-07 | new |
|
||||
| arm/billing | 2017-02-27-preview | new |
|
||||
| arm/compute | 2016-04-30-preview | update to latest swagger |
|
||||
| arm/containerservice | 2017-01-31 | update to latest swagger |
|
||||
| arm/customer-insights | 2017-01-01 | new |
|
||||
| arm/graphrbac | 1.6 | new |
|
||||
| arm/networkwatcher | 2016-12-01 | new |
|
||||
| arm/operationalinsights | 2015-11-01-preview | new |
|
||||
| arm/service-map | 2015-11-01-preview | new |
|
||||
| arm/storageimportexport | 2016-11-01 | new |
|
||||
| Package Name | API Version |
|
||||
| --------------------: | :-----------------: |
|
||||
| networksecuritygroup | classic |
|
||||
|
||||
### Data plane
|
||||
| api | version | note |
|
||||
|:------------------------------------|:-------------------|:-----------------------------------|
|
||||
| dataplane/keyvault | 2016-10-01 | new |
|
||||
## `v17.1.0`
|
||||
|
||||
- Uses go-autorest v7.3.0
|
||||
### New Services
|
||||
|
||||
| Package Name | API Version |
|
||||
| --------------------: | :-----------------: |
|
||||
| iotcentral | 2017-07-01-privatepreview |
|
||||
|
||||
## `v8.0.0-beta`
|
||||
### ARM
|
||||
- In addition to the tablulated changes below, all updated packages received performance
|
||||
improvements to their Version() method.
|
||||
- Some validation that was taking place in the runtime was erroneously blocking calls.
|
||||
all packages have been updated to take that bug fix.
|
||||
## `v17.0.0`
|
||||
|
||||
| api | version | note |
|
||||
|:------------------------------------|:-------------------|:-----------------------------------|
|
||||
| arm/analysisservices | 2016-05-16 | update to latest swagger |
|
||||
| arm/cdn | 2016-10-02 | update to latest swagger |
|
||||
| arm/cognitiveservices | 2016-02-01-preview | update to latest swagger |
|
||||
| arm/compute | 2016-03-30 | update to latest swagger, refactor |
|
||||
| arm/containerregistry | 2016-06-27-preview | update to latest swagger |
|
||||
| arm/containerservice | 2016-09-30 | update to latest swagger |
|
||||
| arm/datalake-analytics | 2016-11-01 | update to latest swagger |
|
||||
| arm/datalake-store | 2016-11-01 | update to latest swagger |
|
||||
| arm/disk | 2016-04-30-preview | new |
|
||||
| arm/documentdb | 2015-04-08 | update to latest swagger |
|
||||
| arm/iothub | 2016-02-03 | update to latest swagger |
|
||||
| arm/keyvault | 2015-06-01 | update to latest swagger |
|
||||
| arm/logic | 2016-06-01 | update to latest swagger |
|
||||
| arm/machinelearning | 2016-05-01-preview | update to latest swagger |
|
||||
| arm/mobileengagement | 2014-12-01 | update to latest swagger, refactor |
|
||||
| arm/redis | 2016-04-01 | update to latest swagger |
|
||||
| arm/resources/locks | 2016-09-01 | refactor |
|
||||
| arm/resources/policy | 2016-12-01 | previous version was deleted |
|
||||
| arm/resources/resources | 2016-09-01 | update to latest swagger, refactor |
|
||||
| arm/scheduler | 2016-03-01 | refactor |
|
||||
| arm/search | 2015-08-19 | refactor |
|
||||
| arm/web | 2015-08-01 | refactor |
|
||||
### New Services
|
||||
|
||||
## `v7.0.0-beta`
|
||||
| Package Name | API Version |
|
||||
| --------------------: | :-----------------: |
|
||||
| batchai | 2018-05-01 |
|
||||
| adhybridhealthservice | 2014-01-01 |
|
||||
| consumption | 2018-05-31 |
|
||||
| customimagesearch | v1.0 |
|
||||
| luis/authoring | v2.0 |
|
||||
| management | 2018-03-01-preview |
|
||||
| maps | 2017-01-01-preview |
|
||||
| maps | 2018-05-01 |
|
||||
| network | 2018-05-01 |
|
||||
| policy | "2018-03-01 |
|
||||
| servicefabric | "2018-02-01 |
|
||||
| services | "2018-03-01-preview |
|
||||
| storage | 2018-03-01-preview |
|
||||
| trafficmanager | 2018-02-01 |
|
||||
| workspaces | 2016-04-01 |
|
||||
|
||||
| api | version | note |
|
||||
|:------------------------------------|:-------------------|:-----------------------------------|
|
||||
| arm/analysisservices | 2016-05-16 | new |
|
||||
| arm/cdn | 2016-10-02 | update to latest swagger |
|
||||
| arm/commerce | 2015-06-01-preview | new |
|
||||
| arm/containerservice | 2016-09-30 | update to latest swagger |
|
||||
| arm/containerregistry | 2016-06-27-preview | new |
|
||||
| arm/datalake-analytics/account | 2016-11-01 | update to latest swagger |
|
||||
| arm/datalake-store/account | 2016-11-01 | update to latest swagger |
|
||||
| arm/datalake-store/filesystem | 2016-11-01 | update to latest swagger |
|
||||
| arm/documentdb | 2015-04-08 | new |
|
||||
| arm/machinelearning/commitmentplans | 2016-05-01-preview | new |
|
||||
| arm/recoveryservices | 2016-06-01 | new |
|
||||
| arm/resources/subscriptions | 2016-06-01 | new |
|
||||
| arm/search | 2015-08-19 | update to latest swagger |
|
||||
| arm/sql | 2014-04-01 | previous version was deleted |
|
||||
### Updated Services
|
||||
|
||||
### Storage
|
||||
- Can now update messages in storage queues.
|
||||
- Added support for blob snapshots and aborting blob copy operations.
|
||||
- Added support for getting and setting ACLs on containers.
|
||||
- Added various APIs for file and directory manipulation.
|
||||
| Package Name | API Version |
|
||||
| ------------------: | :----------------: |
|
||||
| aad | 2017-01-01 |
|
||||
| aad | 2017-06-01 |
|
||||
| account | 2016-11-01 |
|
||||
| advisor | 2017-04-19 |
|
||||
| analysisservices | 2016-05-16 |
|
||||
| analysisservices | 2017-07-14 |
|
||||
| analysisservices | 2017-08-01 |
|
||||
| apimanagement | 2016-07-07 |
|
||||
| apimanagement | 2016-10-10 |
|
||||
| apimanagement | 2017-03-01 |
|
||||
| apimanagement | 2018-01-01 |
|
||||
| batch | 2015-12-01 |
|
||||
| batch | 2017-01-01 |
|
||||
| batch | 2017-05-01 |
|
||||
| batch | 2017-09-01 |
|
||||
| batchai | 2018-03-01 |
|
||||
| batchai | 2018-05-01 |
|
||||
| botservices | 2017-12-01 |
|
||||
| catalog | 2016-11-01-preview |
|
||||
| cdn | 2015-06-01 |
|
||||
| cdn | 2016-04-02 |
|
||||
| cdn | 2016-10-02 |
|
||||
| cdn | 2017-04-02 |
|
||||
| cdn | 2017-10-12 |
|
||||
| compute | 2015-06-15 |
|
||||
| compute | 2016-03-30 |
|
||||
| compute | 2017-03-30 |
|
||||
| compute | 2018-04-01 |
|
||||
| computervision | v1.0 |
|
||||
| consumption | 2018-03-31 |
|
||||
| containerinstance | 2018-04-01 |
|
||||
| containerregistry | 2017-03-01 |
|
||||
| containerregistry | 2017-10-01 |
|
||||
| containerregistry | 2018-02-01 |
|
||||
| containerservice | 2016-03-30 |
|
||||
| containerservice | 2016-09-30 |
|
||||
| containerservice | 2017-01-31 |
|
||||
| containerservice | 2017-07-01 |
|
||||
| containerservice | 2017-08-31 |
|
||||
| containerservice | 2017-09-30 |
|
||||
| customerinsights | 2017-01-01 |
|
||||
| customerinsights | 2017-04-26 |
|
||||
| databox | 2018-01-01 |
|
||||
| databricks | 2018-04-01 |
|
||||
| datacatalog | 2016-03-30 |
|
||||
| datafactory | 2017-09-01-preview |
|
||||
| datamigration | 2018-03-31-preview |
|
||||
| devices | 2016-02-03 |
|
||||
| devices | 2017-01-19 |
|
||||
| devices | 2017-07-01 |
|
||||
| devices | 2018-01-22 |
|
||||
| devices | 2018-04-01 |
|
||||
| dns | 2016-04-01 |
|
||||
| dns | 2017-09-01 |
|
||||
| dns | 2017-10-01 |
|
||||
| documentdb | 2015-04-08 |
|
||||
| dtl | 2016-05-15 |
|
||||
| eventgrid | 2018-01-01 |
|
||||
| eventgrid | 2018-05-01-preview |
|
||||
| eventhub | 2015-08-01 |
|
||||
| eventhub | 2017-04-01 |
|
||||
| eventhub | 2018-01-01-preview |
|
||||
| insights | 2015-05-01 |
|
||||
| iothub | 2017-08-21-preview |
|
||||
| iothub | 2017-11-15 |
|
||||
| iothub | 2018-01-22 |
|
||||
| iotspaces | 2017-10-01-preview |
|
||||
| logic | 2016-06-01 |
|
||||
| managedapplications | 2016-09-01-preview |
|
||||
| managedapplications | 2017-09-01 |
|
||||
| management | 2018-01-01-preview |
|
||||
| media | 2018-03-30-preview |
|
||||
| mysql | 2017-12-01 |
|
||||
| network | 2015-06-15 |
|
||||
| network | 2016-03-30 |
|
||||
| network | 2016-06-01 |
|
||||
| network | 2016-09-01 |
|
||||
| network | 2016-12-01 |
|
||||
| network | 2017-03-01 |
|
||||
| network | 2017-06-01 |
|
||||
| network | 2017-08-01 |
|
||||
| network | 2017-09-01 |
|
||||
| network | 2017-10-01 |
|
||||
| network | 2017-11-01 |
|
||||
| network | 2018-01-01 |
|
||||
| network | 2018-02-01 |
|
||||
| network | 2018-04-01 |
|
||||
| notificationhubs | 2014-09-01 |
|
||||
| notificationhubs | 2016-03-01 |
|
||||
| notificationhubs | 2017-04-01 |
|
||||
| operationalinsights | 2015-03-20 |
|
||||
| operationalinsights | v1 |
|
||||
| postgresql | 2017-12-01 |
|
||||
| powerbidedicated | 2017-10-01 |
|
||||
| powerbiembedded | 2016-01-29 |
|
||||
| prediction | customvision |
|
||||
| luis/programmatic | v2.0 |
|
||||
| redis | 2016-04-01 |
|
||||
| redis | 2017-02-01 |
|
||||
| redis | 2017-10-01 |
|
||||
| redis | 2018-03-01 |
|
||||
| relay | 2016-07-01 |
|
||||
| relay | 2017-04-01 |
|
||||
| reservations | 2017-11-01 |
|
||||
| resources | 2015-11-01 |
|
||||
| resources | 2016-02-01 |
|
||||
| resources | 2016-07-01 |
|
||||
| resources | 2016-09-01 |
|
||||
| resources | 2017-05-10 |
|
||||
| resources | 2018-02-01 |
|
||||
| luis/runtime | v2.0 |
|
||||
| scheduler | 2016-03-01 |
|
||||
| search | 2015-08-19 |
|
||||
| servermanagement | 2015-07-01-preview |
|
||||
| servermanagement | 2016-07-01-preview |
|
||||
| servicebus | 2015-08-01 |
|
||||
| servicebus | 2017-04-01 |
|
||||
| servicefabric | 2016-09-01 |
|
||||
| servicefabric | 2017-07-01-preview |
|
||||
| signalr | 2018-03-01-preview |
|
||||
| siterecovery | 2016-08-10 |
|
||||
| siterecovery | 2018-01-10 |
|
||||
| sql | 2014-04-01 |
|
||||
| sql | 2015-05-01-preview |
|
||||
| sql | 2017-03-01-preview |
|
||||
| sql | 2017-10-01-preview |
|
||||
| storage | 2015-05-01-preview |
|
||||
| storage | 2015-06-15 |
|
||||
| storage | 2016-01-01 |
|
||||
| storage | 2016-05-01 |
|
||||
| storage | 2016-12-01 |
|
||||
| storage | 2017-06-01 |
|
||||
| storage | 2017-10-01 |
|
||||
| storage | 2018-02-01 |
|
||||
| storsimple | 2017-06-01 |
|
||||
| streamanalytics | 2016-03-01 |
|
||||
| subscription | 2017-11-01-preview |
|
||||
| subscription | 2018-03-01-preview |
|
||||
| timeseriesinsights | 2017-02-28-preview |
|
||||
| timeseriesinsights | 2017-11-15 |
|
||||
| trafficmanager | 2018-03-01 |
|
||||
| training | customvision |
|
||||
| visualstudio | 2014-04-01-preview |
|
||||
| web | 2015-08-preview |
|
||||
| web | 2016-09-01 |
|
||||
| web | 2018-02-01 |
|
||||
| webservices | 2017-01-01 |
|
||||
|
||||
### Support for the following swagger extensions was added to the Go generator which affected codegen.
|
||||
- x-ms-client-flatten
|
||||
- x-ms-paramater-location
|
||||
## `v16.2.2`
|
||||
|
||||
## `v6.0.0-beta`
|
||||
### Updated Services
|
||||
|
||||
| api | version | note |
|
||||
|:-------------------------------|:-------------------|:-----------------------------------|
|
||||
| arm/authorization | no change | code refactoring |
|
||||
| arm/batch | no change | code refactoring |
|
||||
| arm/compute | no change | code refactoring |
|
||||
| arm/containerservice | 2016-03-30 | return |
|
||||
| arm/datalake-analytics/account | 2015-10-01-preview | new |
|
||||
| arm/datalake-store/filesystem | no change | moved to datalake-store/filesystem |
|
||||
| arm/eventhub | no change | code refactoring |
|
||||
| arm/intune | no change | code refactoring |
|
||||
| arm/iothub | no change | code refactoring |
|
||||
| arm/keyvault | no change | code refactoring |
|
||||
| arm/mediaservices | no change | code refactoring |
|
||||
| arm/network | no change | code refactoring |
|
||||
| arm/notificationhubs | no change | code refactoring |
|
||||
| arm/redis | no change | code refactoring |
|
||||
| arm/resources/resources | no change | code refactoring |
|
||||
| arm/resources/links | 2016-09-01 | new |
|
||||
| arm/resources/locks | 2016-09-01 | updated |
|
||||
| arm/resources/policy | no change | code refactoring |
|
||||
| arm/resources/resources | 2016-09-01 | updated |
|
||||
| arm/servermanagement | 2016-07-01-preview | updated |
|
||||
| arm/web | no change | code refactoring |
|
||||
| Package Name | API Version |
|
||||
| -----------: | :----------------: |
|
||||
| signalr | 2018-03-01-preview |
|
||||
|
||||
- storage: Added blob lease functionality and tests
|
||||
## `v16.2.1`
|
||||
|
||||
## `v5.0.0-beta`
|
||||
### Updated Services
|
||||
|
||||
| api | version | note |
|
||||
|:------------------------------|:--------------------|:-----------------|
|
||||
| arm/network | 2016-09-01 | updated |
|
||||
| arm/servermanagement | 2015-07-01-preview | new |
|
||||
| arm/eventhub | 2015-08-01 | new |
|
||||
| arm/containerservice | -- | removed |
|
||||
| arm/resources/subscriptions | no change | code refactoring |
|
||||
| arm/resources/features | no change | code refactoring |
|
||||
| arm/resources/resources | no change | code refactoring |
|
||||
| arm/datalake-store/accounts | no change | code refactoring |
|
||||
| arm/datalake-store/filesystem | no change | code refactoring |
|
||||
| arm/notificationhubs | no change | code refactoring |
|
||||
| arm/redis | no change | code refactoring |
|
||||
| Package Name | API Version |
|
||||
| -----------: | :-----------------------: |
|
||||
| web | 2016-09-01<br/>2018-02-01 |
|
||||
|
||||
- storage: Add more file storage share operations.
|
||||
- azure-rest-api-specs/commit/b8cdc2c50a0872fc0039f20c2b6b33aa0c2af4bf
|
||||
- Uses go-autorest v7.2.1
|
||||
## `v16.2.0`
|
||||
|
||||
## `v4.0.0-beta`
|
||||
### New Services
|
||||
|
||||
- arm/logic: breaking change in package logic.
|
||||
- arm: parameter validation code added in all arm packages.
|
||||
- Uses go-autorest v7.2.0.
|
||||
| Package Name | API Version |
|
||||
| -------------: | :----------------: |
|
||||
| eventgrid | 2018-05-01-preview |
|
||||
| trafficmanager | 2018-03-01 |
|
||||
|
||||
### Updated Services
|
||||
|
||||
## `v3.2.0-beta`
|
||||
| Package Name | API Version |
|
||||
| ------------: | :-----------------------: |
|
||||
| redis | 2017-10-01<br/>2018-03-01 |
|
||||
| textanalytics | v2.0 |
|
||||
| web | 2016-09-01<br/>2018-02-01 |
|
||||
|
||||
| api | version | note |
|
||||
|:----------------------------|:--------------------|:----------|
|
||||
| arm/mediaservices | 2015-10-01 | new |
|
||||
| arm/keyvault | 2015-06-01 | new |
|
||||
| arm/iothub | 2016-02-03 | new |
|
||||
| arm/datalake-store | 2015-12-01 | new |
|
||||
| arm/network | 2016-06-01 | updated |
|
||||
| arm/resources/resources | 2016-07-01 | updated |
|
||||
| arm/resources/policy | 2016-04-01 | updated |
|
||||
| arm/servicebus | 2015-08-01 | updated |
|
||||
## `v16.1.0`
|
||||
|
||||
- arm: uses go-autorest version v7.1.0.
|
||||
- storage: fix for operating on blobs names containing special characters.
|
||||
- storage: add SetBlobProperties(), update BlobProperties response fields.
|
||||
- storage: make storage client work correctly with read-only secondary account.
|
||||
- storage: add Azure Storage Emulator support.
|
||||
* Added a `NewAuthorizerFromEnvironment()` function for the keyvault service.
|
||||
|
||||
## `v16.0.0`
|
||||
|
||||
## `v3.1.0-beta`
|
||||
### New Services
|
||||
|
||||
- Added a new arm/compute/containerservice (2016-03-30) package
|
||||
- Reintroduced NewxxClientWithBaseURI method.
|
||||
- Uses go-autorest version - v7.0.7.
|
||||
| Package Name | API Version |
|
||||
| ------------------: | :----------------: |
|
||||
| batchai | 2018-05-01 |
|
||||
| botservices | 2017-12-01 |
|
||||
| containerinstance | 2018-04-01 |
|
||||
| containerregistry | 2018-02-01 |
|
||||
| keyvault | v7.0 |
|
||||
| managedapplications | 2017-09-01 |
|
||||
| network | 2018-04-01 |
|
||||
| policyinsights | 2018-04-04 |
|
||||
| signalr | 2018-03-01-preview |
|
||||
| storage | 2018-02-0 |
|
||||
| visualsearch | v1.0 |
|
||||
| web | 2018-02-01 |
|
||||
|
||||
### Updated Services
|
||||
|
||||
## `v3.0.0-beta`
|
||||
| Package Name | API Version |
|
||||
| ------------------: | :--------------------------------------------------------------: |
|
||||
| apimanagement | 2018-01-01 |
|
||||
| automation | 2015-10-31<br/>2017-05-15-preview |
|
||||
| billing | 2018-03-01-preview |
|
||||
| botservices | 2017-12-01 |
|
||||
| catalog | 2016-11-01-preview |
|
||||
| cognitiveservices | 2017-04-18 |
|
||||
| commerce | 2015-06-01-preview |
|
||||
| compute | 2018-04-01 |
|
||||
| consumption | 2018-03-31 |
|
||||
| contentmoderator | v1.0 |
|
||||
| datafactory | 2017-09-01-preview |
|
||||
| datamigration | 2017-11-15-preview |
|
||||
| eventhub | 2017-04-01 |
|
||||
| insights | 2015-05-0 |
|
||||
| iothub | 2017-11-15 |
|
||||
| network | 2018-02-01 |
|
||||
| operationalinsights | 2015-03-20<br/>2015-11-01-preview |
|
||||
| servicebus | 2017-04-01 |
|
||||
| siterecovery | 2018-01-10 |
|
||||
| sql | 2017-03-01-preview<br/>2017-10-01-preview<br/>2015-05-01-preview |
|
||||
| timeseriesinsights | 2017-11-15 |
|
||||
| luis/runtime | v2.0 |
|
||||
| web | 2016-09-01 |
|
||||
|
||||
This release brings the Go SDK ARM packages up-to-date with Azure ARM Swagger files for most
|
||||
services. Since the underlying [Swagger files](https://github.com/Azure/azure-rest-api-specs)
|
||||
continue to change substantially, the ARM packages are still in *beta* status.
|
||||
## `v15.3.0`
|
||||
|
||||
The ARM packages now align with the following API versions (*highlighted* packages are new or
|
||||
updated in this release):
|
||||
### New Services
|
||||
|
||||
| api | version | note |
|
||||
|:----------------------------|:--------------------|:----------|
|
||||
| arm/authorization | 2015-07-01 | no change |
|
||||
| arm/intune | 2015-01-14-preview | no change |
|
||||
| arm/notificationhubs | 2014-09-01 | no change |
|
||||
| arm/resources/features | 2015-12-01 | no change |
|
||||
| arm/resources/subscriptions | 2015-11-01 | no change |
|
||||
| arm/web | 2015-08-01 | no change |
|
||||
| arm/cdn | 2016-04-02 | updated |
|
||||
| arm/compute | 2016-03-30 | updated |
|
||||
| arm/dns | 2016-04-01 | updated |
|
||||
| arm/logic | 2015-08-01-preview | updated |
|
||||
| arm/network | 2016-03-30 | updated |
|
||||
| arm/redis | 2016-04-01 | updated |
|
||||
| arm/resources/resources | 2016-02-01 | updated |
|
||||
| arm/resources/policy | 2015-10-01-preview | updated |
|
||||
| arm/resources/locks | 2015-01-01 | updated (resources/authorization earlier)|
|
||||
| arm/scheduler | 2016-03-01 | updated |
|
||||
| arm/storage | 2016-01-01 | updated |
|
||||
| arm/search | 2015-02-28 | updated |
|
||||
| arm/batch | 2015-12-01 | new |
|
||||
| arm/cognitiveservices | 2016-02-01-preview | new |
|
||||
| arm/devtestlabs | 2016-05-15 | new |
|
||||
| arm/machinelearning | 2016-05-01-preview | new |
|
||||
| arm/powerbiembedded | 2016-01-29 | new |
|
||||
| arm/mobileengagement | 2014-12-01 | new |
|
||||
| arm/servicebus | 2014-09-01 | new |
|
||||
| arm/sql | 2015-05-01 | new |
|
||||
| arm/trafficmanager | 2015-11-01 | new |
|
||||
| Package Name | API Version |
|
||||
| ------------: | :----------------: |
|
||||
| databox | 2018-01-01 |
|
||||
| devices | 2018-04-01 |
|
||||
| media | 2018-03-30-preview |
|
||||
| servicefabric | 6.2 |
|
||||
|
||||
### Updated Services
|
||||
|
||||
Below are some design changes.
|
||||
- Removed Api version from method arguments.
|
||||
- Removed New...ClientWithBaseURI() method in all clients. BaseURI value is set in client.go.
|
||||
- Uses go-autorest version v7.0.6.
|
||||
| Package Name | API Version |
|
||||
| ----------------: | :------------: |
|
||||
| apimanagement | 2018-01-01 |
|
||||
| batch | 2018-03-01.6.1 |
|
||||
| containerregistry | 2017-10-01 |
|
||||
| documentdb | 2015-04-08 |
|
||||
| servicebus | 2017-04-01 |
|
||||
|
||||
## `v15.2.0`
|
||||
|
||||
## `v2.2.0-beta`
|
||||
### New Services
|
||||
|
||||
- Uses go-autorest version v7.0.5.
|
||||
- Update version of pacakges "jwt-go" and "crypto" in glide.lock.
|
||||
| Package Name | API Version |
|
||||
| -----------: | :---------: |
|
||||
| addons | 2017-05-15 |
|
||||
| addons | 2018-03-01 |
|
||||
|
||||
### Updated Services
|
||||
|
||||
## `v2.1.1-beta`
|
||||
| Package Name | API Version |
|
||||
| ------------: | :---------: |
|
||||
| apimanagement | 2017-03-01 |
|
||||
| apimanagement | 2018-01-01 |
|
||||
| insights | 2015-05-01 |
|
||||
|
||||
- arm: Better error messages for long running operation failures (Uses go-autorest version v7.0.4).
|
||||
## `v15.1.1`
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
## `v2.1.0-beta`
|
||||
* Drain the response body when retrying a request.
|
||||
* Avoid allocating when draining a response body.
|
||||
|
||||
- arm: Uses go-autorest v7.0.3 (polling related updates).
|
||||
- arm: Cancel channel argument added in long-running calls.
|
||||
- storage: Allow caller to provide headers for DeleteBlob methods.
|
||||
- storage: Enables connection sharing with http keepalive.
|
||||
- storage: Add BlobPrefixes and Delimiter to BlobListResponse
|
||||
## `v15.1.0`
|
||||
|
||||
### New Services
|
||||
|
||||
## `v2.0.0-beta`
|
||||
| Package Name | API Version |
|
||||
| ----------------: | :----------------: |
|
||||
| datamigration | 2018-03-31-preview |
|
||||
| devices | 2018-01-22 |
|
||||
| network | 2018-02-01 |
|
||||
| cognitiveservices | customvision |
|
||||
|
||||
- Uses go-autorest v6.0.0 (Polling and Asynchronous requests related changes).
|
||||
## Updated Services
|
||||
|
||||
|
||||
## `v0.5.0-beta`
|
||||
| Package Name | API Version |
|
||||
| -----------: | :----------------------------------------------------------------------------: |
|
||||
| compute | 2015-06-15<br/>2016-03-30<br/>2016-04-30-preview<br/>2017-03-30<br/>2018-04-01 |
|
||||
| datafactory | 2017-09-01-preview |
|
||||
| insights | 2018-03-01 |
|
||||
| mysql | 2017-12-01 |
|
||||
| postgresql | 2017-12-01 |
|
||||
| web | 2016-09-01 |
|
||||
|
||||
Updated following packages to new API versions:
|
||||
- arm/resources/features 2015-12-01
|
||||
- arm/resources/resources 2015-11-01
|
||||
- arm/resources/subscriptions 2015-11-01
|
||||
## `v15.0.1`
|
||||
|
||||
Fixing some build issues, and temporarily reverting CI.
|
||||
|
||||
### Changes
|
||||
## `v15.0.0`
|
||||
|
||||
- SDK now uses go-autorest v3.0.0.
|
||||
NOTE: There is a new subdirectory, ./services/preview, which going forward will be used for segregating pre-GA packages.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added helper func per enum type that returns a slice of all possible values for that type.
|
||||
|
||||
## `v0.4.0-beta`
|
||||
### Bug Fixes
|
||||
|
||||
This release brings the Go SDK ARM packages up-to-date with Azure ARM Swagger files for most
|
||||
services. Since the underlying [Swagger files](https://github.com/Azure/azure-rest-api-specs)
|
||||
continue to change substantially, the ARM packages are still in *beta* status.
|
||||
* Removed the "arm-" prefix from user-agent strings as not all services are for ARM.
|
||||
* Fixed missing marshaller for structs with flattened fields.
|
||||
* Fixed an issue where the incorrect content MIME type was being specified.
|
||||
* Marshalling of empty values for enum types now works as expected.
|
||||
|
||||
The ARM packages now align with the following API versions (*highlighted* packages are new or
|
||||
updated in this release):
|
||||
### New Services
|
||||
|
||||
- *arm/authorization 2015-07-01*
|
||||
- *arm/cdn 2015-06-01*
|
||||
- arm/compute 2015-06-15
|
||||
- arm/dns 2015-05-04-preview
|
||||
- *arm/intune 2015-01-14-preview*
|
||||
- arm/logic 2015-02-01-preview
|
||||
- *arm/network 2015-06-15*
|
||||
- *arm/notificationhubs 2014-09-01*
|
||||
- arm/redis 2015-08-01
|
||||
- *arm/resources/authorization 2015-01-01*
|
||||
- *arm/resources/features 2014-08-01-preview*
|
||||
- *arm/resources/resources 2014-04-01-preview*
|
||||
- *arm/resources/subscriptions 2014-04-01-preview*
|
||||
- *arm/scheduler 2016-01-01*
|
||||
- arm/storage 2015-06-15
|
||||
- arm/web 2015-08-01
|
||||
| Package Name | API Version |
|
||||
| -------------: | :--------------------------------------------------------------: |
|
||||
| apimanagement | 2017-03-01 |
|
||||
| azurestack | 2017-06-01 |
|
||||
| billing | 2018-03-01-preview |
|
||||
| compute | 2018-04-01 |
|
||||
| consumption | 2018-03-31 |
|
||||
| databricks | 2018-04-01 |
|
||||
| dns | 2017-10-01 |
|
||||
| insights | 2018-03-01 |
|
||||
| iothub | 2018-01-22 |
|
||||
| iotspaces | 2017-10-01-preview |
|
||||
| management | 2018-01-01-preview |
|
||||
| migrate | 2018-02-02 |
|
||||
| policyinsights | 2017-08-09-preview<br/>2017-10-17-preview<br/>2017-12-12-preview |
|
||||
| resources | 2018-02-01 |
|
||||
| siterecovery | 2018-01-10 |
|
||||
| sql | 2017-10-01-preview |
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
| Package Name | API Version |
|
||||
| ------------------: | :----------------------------------------: |
|
||||
| automation | 2017-05-15-preview |
|
||||
| advisor | 2017-04-19 |
|
||||
| cognitiveservices | 2017-04-18 |
|
||||
| compute | 2017-03-30<br/>2017-12-01 |
|
||||
| consumption | 2018-01-31 |
|
||||
| containerinstance | 2018-02-01-preview |
|
||||
| containerservice | 2017-08-31<br/>2017-09-30 |
|
||||
| customsearch | v1.0 |
|
||||
| datafactory | 2017-09-01-preview |
|
||||
| datamigration | 2017-11-15-preview |
|
||||
| dns | 2018-03-01-preview |
|
||||
| entitysearch | v1.0 |
|
||||
| imagesearch | v1.0 |
|
||||
| insights | 2017-05-01-preview |
|
||||
| iothub | 2017-11-15 |
|
||||
| management | 2017-08-31-preview<br/>2017-11-01-preview |
|
||||
| mysql | 2017-12-01-preview |
|
||||
| newssearch | v1.0 |
|
||||
| operationalinsights | 2015-03-20 |
|
||||
| postgresql | 2017-12-01-preview |
|
||||
| servicebus | 2015-08-01 |
|
||||
| servicefabric | 2017-07-01-preview<br/>5.6<br/>6.0<br/>6.1 |
|
||||
| servicemap | 2015-11-01-preview |
|
||||
| spellcheck | v1.0 |
|
||||
| timeseriesinsights | 2017-02-28-preview<br/>2017-11-15 |
|
||||
| videosearch | v1.0 |
|
||||
| web | 2016-09-01 |
|
||||
| websearch | v1.0 |
|
||||
|
||||
## `v14.6.0`
|
||||
|
||||
### New Services
|
||||
|
||||
* Batch 2018-03-01.6.1
|
||||
* BatchAI 2018-03-01
|
||||
* Cognitive services custom vision prediction v1.1
|
||||
* Eventhub 2018-01-01-preview
|
||||
* MySQL 2017-12-01
|
||||
* PostgreSQL 2017-12-01
|
||||
* Redis 2018-03-01
|
||||
* Subscription 2018-03-01-preview
|
||||
|
||||
## `v14.5.0`
|
||||
|
||||
### Changes
|
||||
|
||||
- Moved the arm/authorization, arm/features, arm/resources, and arm/subscriptions packages under a new, resources, package (to reflect the corresponding Swagger structure)
|
||||
- Added a new arm/authoriation (2015-07-01) package
|
||||
- Added a new arm/cdn (2015-06-01) package
|
||||
- Added a new arm/intune (2015-01-14-preview) package
|
||||
- Udated arm/network (2015-06-01)
|
||||
- Added a new arm/notificationhubs (2014-09-01) package
|
||||
- Updated arm/scheduler (2016-01-01) package
|
||||
* Added new preview packages for apimanagement and dns.
|
||||
|
||||
## `v14.4.0`
|
||||
|
||||
-----
|
||||
### Changes
|
||||
|
||||
## `v0.3.0-beta`
|
||||
* Added new preview API versions for mysql and postgresql.
|
||||
|
||||
- Corrected unintentional struct field renaming and client renaming in v0.2.0-beta
|
||||
## `v14.3.0`
|
||||
|
||||
-----
|
||||
### Changes
|
||||
|
||||
## `v0.2.0-beta`
|
||||
* Add exports for max file range and sizes for files in storage.
|
||||
* Updated README regarding blob storage support.
|
||||
* Add godoc indexer tool.
|
||||
* Add apidiff tool.
|
||||
|
||||
- Added support for DNS, Redis, and Web site services
|
||||
- Updated Storage service to API version 2015-06-15
|
||||
- Updated Network to include routing table support
|
||||
- Address https://github.com/Azure/azure-sdk-for-go/issues/232
|
||||
- Address https://github.com/Azure/azure-sdk-for-go/issues/231
|
||||
- Address https://github.com/Azure/azure-sdk-for-go/issues/230
|
||||
- Address https://github.com/Azure/azure-sdk-for-go/issues/224
|
||||
- Address https://github.com/Azure/azure-sdk-for-go/issues/184
|
||||
- Address https://github.com/Azure/azure-sdk-for-go/issues/183
|
||||
## `v14.2.0`
|
||||
|
||||
------
|
||||
### Changes
|
||||
|
||||
## `v0.1.1-beta`
|
||||
* For blob storage, added GetProperties() method to Container.
|
||||
* Added PublicAccess field to ContainerProperties struct.
|
||||
|
||||
- Improves the UserAgent string to disambiguate arm packages from others in the SDK
|
||||
- Improves setting the http.Response into generated results (reduces likelihood of a nil reference)
|
||||
- Adds gofmt, golint, and govet to Travis CI for the arm packages
|
||||
## `v14.1.1`
|
||||
|
||||
##### Fixed Issues
|
||||
* Fixing timestamp marshalling bug in the `storage` package.
|
||||
* Updating `profileBuilder` to clear-output folders when it is run by `go generate`.
|
||||
* Tweaking Swagger -> SDK config to use "latest" instead of "nightly" and be tied to a particular version of autorest.go.
|
||||
|
||||
- https://github.com/Azure/azure-sdk-for-go/issues/196
|
||||
- https://github.com/Azure/azure-sdk-for-go/issues/213
|
||||
## `v14.1.0`
|
||||
|
||||
------
|
||||
### Changes
|
||||
|
||||
## v0.1.0-beta
|
||||
* Update README with details on new authentication helpers.
|
||||
* Update `latest` profile to point to latest stable API versions.
|
||||
* Add new API version for Azure Monitoring service and for Batch Data plane service.
|
||||
|
||||
This release addresses the issues raised against the alpha release and adds more features. Most
|
||||
notably, to address the challenges of encoding JSON
|
||||
(see the [comments](https://github.com/Azure/go-autorest#handling-empty-values) in the
|
||||
[go-autorest](https://github.com/Azure/go-autorest) package) by using pointers for *all* structure
|
||||
fields (with the exception of enumerations). The
|
||||
[go-autorest/autorest/to](https://github.com/Azure/go-autorest/tree/master/autorest/to) package
|
||||
provides helpers to convert to / from pointers. The examples demonstrate their usage.
|
||||
## `v14.0.2`
|
||||
|
||||
Additionally, the packages now align with Go coding standards and pass both `golint` and `govet`.
|
||||
Accomplishing this required renaming various fields and parameters (such as changing Url to URL).
|
||||
### Changes
|
||||
|
||||
##### Changes
|
||||
* Updating `profileBuilder list` to accept an `input` flag instead of reading from `stdin`.
|
||||
* Simplifying CI to have less chatter, be faster, and have no special cases.
|
||||
|
||||
- Changed request / response structures to use pointer fields.
|
||||
- Changed methods to return `error` instead of `autorest.Error`.
|
||||
- Re-divided methods to ease asynchronous requests.
|
||||
- Added paged results support.
|
||||
- Added a UserAgent string.
|
||||
- Added changes necessary to pass golint and govet.
|
||||
- Updated README.md with details on asynchronous requests and paging.
|
||||
- Saved package dependencies through Godep (for the entire SDK).
|
||||
## `v14.0.1`
|
||||
|
||||
##### Fixed Issues:
|
||||
### Changes
|
||||
|
||||
- https://github.com/Azure/azure-sdk-for-go/issues/205
|
||||
- https://github.com/Azure/azure-sdk-for-go/issues/206
|
||||
- https://github.com/Azure/azure-sdk-for-go/issues/211
|
||||
- https://github.com/Azure/azure-sdk-for-go/issues/212
|
||||
* Removed the ./services/search/2016-09-01/search package, it was never intended to be included and doesn't work.
|
||||
|
||||
-----
|
||||
## `v14.0.0`
|
||||
|
||||
## v0.1.0-alpha
|
||||
### Breaking Changes
|
||||
|
||||
This release introduces the Azure Resource Manager packages generated from the corresponding
|
||||
[Swagger API](http://swagger.io) [definitions](https://github.com/Azure/azure-rest-api-specs).
|
||||
* Removed the ./arm, ./datalake-store and ./dataplane directories. You can find the same packages under ./services
|
||||
* The management package was moved to ./services/classic/management
|
||||
* Renamed package ./services/redis/mgmt/2017-10-01/cache to ./services/redis/mgmt/2017-10-01/redis
|
||||
|
||||
### Changes
|
||||
|
||||
* Removed the "-beta" suffix.
|
||||
* Added various new services.
|
||||
* Added ./version package for centralized SDK versioning.
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
/documentation/ @mcardosos @marstr @joshgav
|
||||
/profiles/ @marstr @jhendrixMSFT
|
||||
/services/ @jhendrixMSFT @marstr @mcardosos @vladbarosan
|
||||
/storage/ @mcardosos @jhendrixMSFT
|
||||
/tools/apidiff/ @jhendrixMSFT
|
||||
/tools/generator/ @marstr
|
||||
/tools/indexer/ @jhendrixMSFT
|
||||
/tools/profileBuilder/ @marstr @jhendrixMSFT
|
||||
/version/ @jhendrixMSFT @marstr @mcardosos @vladbarosan
|
||||
.travis.yml @marstr @jhendrixMSFT @mcardosos @vladbarosan
|
||||
doc.go @joshgav
|
||||
findTestedPackages.sh @marstr
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# Contributing
|
||||
|
||||
While in preview we maintain only a `master` branch for releases and `dev` branch for development.
|
||||
|
||||
After release we will maintain a branch for each major version to backport important fixes.
|
||||
|
||||
Please submit pull requests to `dev` to update the latest version or to a version branch for backports.
|
||||
|
||||
Also see these [guidelines][] about contributing to Azure projects.
|
||||
|
||||
This project follows the [Microsoft Open Source Code of Conduct][CoC]. For more information see the [Code of Conduct FAQ][CoCfaq]. Contact [opencode@microsoft.com][CoCmail] with questions and comments.
|
||||
|
||||
[guidelines]: http://azure.github.io/guidelines/
|
||||
[CoC]: https://opensource.microsoft.com/codeofconduct/
|
||||
[CoCfaq]: https://opensource.microsoft.com/codeofconduct/faq/
|
||||
[CoCmail]: mailto:opencode@microsoft.com
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Azure/go-autorest"
|
||||
packages = [
|
||||
"autorest",
|
||||
"autorest/adal",
|
||||
"autorest/azure",
|
||||
"autorest/azure/auth",
|
||||
"autorest/date",
|
||||
"autorest/to",
|
||||
"autorest/validation"
|
||||
]
|
||||
revision = "4de44cd533576f3c7b44dcb08dc03754d217144d"
|
||||
version = "v10.9.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/dimchansky/utfbom"
|
||||
packages = ["."]
|
||||
revision = "6c6132ff69f0f6c088739067407b5d32c52e1d0f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/dnaeon/go-vcr"
|
||||
packages = [
|
||||
"cassette",
|
||||
"recorder"
|
||||
]
|
||||
revision = "f8a7e8b9c630b486df74145bb887793a1b85459b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
packages = ["."]
|
||||
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
|
||||
version = "v1.4.7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/globalsign/mgo"
|
||||
packages = [
|
||||
".",
|
||||
"bson",
|
||||
"internal/json",
|
||||
"internal/sasl",
|
||||
"internal/scram"
|
||||
]
|
||||
revision = "efe0945164a7e582241f37ae8983c075f8f2e870"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
"json/parser",
|
||||
"json/scanner",
|
||||
"json/token"
|
||||
]
|
||||
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/marstr/collection"
|
||||
packages = ["."]
|
||||
revision = "871b1cfa2ab97d3d8f54a034280907896190c346"
|
||||
version = "v0.3.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/marstr/goalias"
|
||||
packages = ["model"]
|
||||
revision = "8dff9a14db648bfdd58d45515d3eaaee23aad078"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/marstr/guid"
|
||||
packages = ["."]
|
||||
revision = "8bd9a64bf37eb297b492a4101fb28e80ac0b290f"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/marstr/randname"
|
||||
packages = ["."]
|
||||
revision = "3ef1f47af99e66171417047e6f6fa334345e95e7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pelletier/go-toml"
|
||||
packages = ["."]
|
||||
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/satori/go.uuid"
|
||||
packages = ["."]
|
||||
revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/shopspring/decimal"
|
||||
packages = ["."]
|
||||
revision = "69b3a8ad1f5f2c8bd855cb6506d18593064a346b"
|
||||
version = "1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem"
|
||||
]
|
||||
revision = "63644898a8da0bc22138abf860edaf5277b6102e"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"pkcs12",
|
||||
"pkcs12/internal/rc2"
|
||||
]
|
||||
revision = "5ba7f63082460102a45837dbd1827e10f9479ac0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"internal/gen",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"transform",
|
||||
"unicode/cldr",
|
||||
"unicode/norm"
|
||||
]
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/tools"
|
||||
packages = [
|
||||
"go/ast/astutil",
|
||||
"imports",
|
||||
"internal/fastwalk"
|
||||
]
|
||||
revision = "a5b4c53f6e8bdcafa95a94671bf2d1203365858b"
|
||||
|
||||
[[projects]]
|
||||
branch = "v1"
|
||||
name = "gopkg.in/check.v1"
|
||||
packages = ["."]
|
||||
revision = "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "3ba7e7e6599059a0ac88f854eca95495c02501ebe2e0be13b38e4f2b823d5c53"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
# 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"
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/Azure/go-autorest"
|
||||
version = "10.9.2"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/dnaeon/go-vcr"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/globalsign/mgo"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/marstr/collection"
|
||||
version = "0.3.3"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/marstr/goalias"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/marstr/guid"
|
||||
version = "1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/marstr/randname"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/satori/go.uuid"
|
||||
version = "1.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/shopspring/decimal"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/tools"
|
||||
|
||||
[[constraint]]
|
||||
branch = "v1"
|
||||
name = "gopkg.in/check.v1"
|
||||
+5
@@ -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).
|
||||
+282
-40
@@ -1,59 +1,301 @@
|
||||
# Microsoft Azure SDK for Go
|
||||
[](https://godoc.org/github.com/Azure/azure-sdk-for-go)
|
||||
[](https://travis-ci.org/Azure/azure-sdk-for-go)
|
||||
# Azure SDK for Go
|
||||
|
||||
[](https://godoc.org/github.com/Azure/azure-sdk-for-go)
|
||||
[](https://travis-ci.org/Azure/azure-sdk-for-go)
|
||||
[](https://goreportcard.com/report/github.com/Azure/azure-sdk-for-go)
|
||||
|
||||
This is Microsoft Azure's core repository for hosting Go packages which offer a more convenient way of targeting Azure
|
||||
REST endpoints. Here, you'll find a mix of code generated by [Autorest](https://github.com/Azure/autorest) and hand
|
||||
maintained packages.
|
||||
azure-sdk-for-go provides Go packages for managing and using Azure services. It has been
|
||||
tested with Go 1.8, 1.9 and 1.10.
|
||||
|
||||
> **NOTE:** This repository is under heavy ongoing development and should be considered a preview. Vendoring your
|
||||
dependencies is always a good idea, but it is doubly important if you're consuming this library.
|
||||
To be notified about updates and changes, subscribe to the [Azure update
|
||||
feed](https://azure.microsoft.com/updates/).
|
||||
|
||||
# Installation
|
||||
- If you don't already have it, install [the Go Programming Language](https://golang.org/dl/).
|
||||
- Go get the SDK:
|
||||
Users of the SDK may prefer to jump right in to our samples repo at
|
||||
[github.com/Azure-Samples/azure-sdk-for-go-samples][samples_repo].
|
||||
|
||||
```
|
||||
$ go get -u github.com/Azure/azure-sdk-for-go
|
||||
### Build Details
|
||||
|
||||
Most packages in the SDK are generated from [Azure API specs][azure_rest_specs]
|
||||
using [Azure/autorest.go][] and [Azure/autorest][]. These generated packages
|
||||
depend on the HTTP client implemented at [Azure/go-autorest][].
|
||||
|
||||
[azure_rest_specs]: https://github.com/Azure/azure-rest-api-specs
|
||||
[Azure/autorest]: https://github.com/Azure/autorest
|
||||
[Azure/autorest.go]: https://github.com/Azure/autorest.go
|
||||
[Azure/go-autorest]: https://github.com/Azure/go-autorest
|
||||
|
||||
The SDK codebase adheres to [semantic versioning](https://semver.org) and thus
|
||||
avoids breaking changes other than at major (x.0.0) releases. However,
|
||||
occasionally Azure API fixes require breaking updates within an individual
|
||||
package; these exceptions are noted in release changelogs.
|
||||
|
||||
To more reliably manage dependencies like the Azure SDK in your applications we
|
||||
recommend [golang/dep](https://github.com/golang/dep).
|
||||
|
||||
# Install and Use:
|
||||
|
||||
### Install
|
||||
|
||||
```sh
|
||||
$ go get -u github.com/Azure/azure-sdk-for-go/...
|
||||
```
|
||||
|
||||
> **IMPORTANT:** We highly suggest vendoring Azure SDK for Go as a dependency. For vendoring dependencies, Azure SDK
|
||||
for Go uses [glide](https://github.com/Masterminds/glide).
|
||||
or if you use dep, within your repo run:
|
||||
|
||||
```sh
|
||||
$ dep ensure -add github.com/Azure/azure-sdk-for-go
|
||||
```
|
||||
|
||||
If you need to install Go, follow [the official instructions](https://golang.org/dl/).
|
||||
|
||||
### Use
|
||||
|
||||
For complete examples of many scenarios see [Azure-Samples/azure-sdk-for-go-samples][samples_repo].
|
||||
|
||||
1. Import a package from the [services][services_dir] directory.
|
||||
2. Create and authenticate a client with a `New*Client` func, e.g.
|
||||
`c := compute.NewVirtualMachinesClient(...)`.
|
||||
3. Invoke API methods using the client, e.g. `c.CreateOrUpdate(...)`.
|
||||
4. Handle responses.
|
||||
|
||||
[services_dir]: https://github.com/Azure/azure-sdk-for-go/tree/master/services
|
||||
|
||||
For example, to create a new virtual network (substitute your own values for
|
||||
strings in angle brackets):
|
||||
|
||||
Note: For more on authentication and the `Authorizer` interface see [the next
|
||||
section](#authentication).
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network"
|
||||
"github.com/Azure/go-autorest/autorest/azure/auth"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
)
|
||||
|
||||
func main() {
|
||||
vnetClient := network.NewVirtualNetworksClient("<subscriptionID>")
|
||||
authorizer, err := auth.NewAuthorizerFromEnvironment()
|
||||
|
||||
if err == nil {
|
||||
vnetClient.Authorizer = authorizer
|
||||
}
|
||||
|
||||
vnetClient.CreateOrUpdate(context.Background(),
|
||||
"<resourceGroupName>",
|
||||
"<vnetName>",
|
||||
network.VirtualNetwork{
|
||||
Location: to.StringPtr("<azureRegion>"),
|
||||
VirtualNetworkPropertiesFormat: &network.VirtualNetworkPropertiesFormat{
|
||||
AddressSpace: &network.AddressSpace{
|
||||
AddressPrefixes: &[]string{"10.0.0.0/8"},
|
||||
},
|
||||
Subnets: &[]network.Subnet{
|
||||
{
|
||||
Name: to.StringPtr("<subnet1Name>"),
|
||||
SubnetPropertiesFormat: &network.SubnetPropertiesFormat{
|
||||
AddressPrefix: to.StringPtr("10.0.0.0/16"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: to.StringPtr("<subnet2Name>"),
|
||||
SubnetPropertiesFormat: &network.SubnetPropertiesFormat{
|
||||
AddressPrefix: to.StringPtr("10.1.0.0/16"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
Most SDK operations require an OAuth token for authentication and authorization. These are
|
||||
made available in the Go SDK For Azure through types implementing the `Authorizer` interface.
|
||||
You can get one from Azure Active Directory using the SDK's
|
||||
[authentication](https://godoc.org/github.com/Azure/go-autorest/autorest/azure/auth) package. The `Authorizer` returned should
|
||||
be set as the authorizer for the resource client, as shown in the [previous section](#use).
|
||||
|
||||
You can get an authorizer in the following ways:
|
||||
1. From the **Environment**:
|
||||
- Use `auth.auth.NewAuthorizerFromEnvironment()`. This call will try to get an authorizer based on the environment
|
||||
variables with different types of credentials in the following order:
|
||||
1. **Client Credentials**: Uses the AAD App Secret for auth.
|
||||
- `AZURE_TENANT_ID`: Specifies the Tenant to which to authenticate.
|
||||
- `AZURE_CLIENT_ID`: Specifies the app client ID to use.
|
||||
- `AZURE_CLIENT_SECRET`: Specifies the app secret to use.
|
||||
2. **Client Certificate**: Uses a certificate that was configured on the AAD Service Principal.
|
||||
- `AZURE_TENANT_ID`: Specifies the Tenant to which to authenticate.
|
||||
- `AZURE_CLIENT_ID`: Specifies the app client ID to use.
|
||||
- `AZURE_CERTIFICATE_PATH`: Specifies the certificate Path to use.
|
||||
- `AZURE_CERTIFICATE_PASSWORD`: Specifies the certificate password to use.
|
||||
3. **Username Pasword**: Uses a username and a password for auth. This is not recommended. Use `Device Flow` Auth instead for user interactive acccess.
|
||||
- `AZURE_TENANT_ID`: Specifies the Tenant to which to authenticate.
|
||||
- `AZURE_CLIENT_ID`: Specifies the app client ID to use.
|
||||
- `AZURE_USERNAME`: Specifies the username to use.
|
||||
- `AZURE_PASSWORD`: Specifies the password to use.
|
||||
4. **MSI**: Only available for apps running in Azure. No configuration needed as it leverages the fact that the app is running in Azure. See [Azure Managed Service Identity](https://docs.microsoft.com/en-us/azure/active-directory/msi-overview).
|
||||
|
||||
- Optionally, the following environment variables can be defined:
|
||||
- `AZURE_ENVIRONMENT`: Specifies the Azure Environment to use. If not set, it defaults to `AzurePublicCloud`. (Not applicable to MSI based auth)
|
||||
- `AZURE_AD_RESOURCE`: Specifies the AAD resource ID to use. If not set, it defaults to `ResourceManagerEndpoint`which allows management operations against Azure Resource Manager.
|
||||
|
||||
2. From an **Auth File**:
|
||||
- Create a service principal and output the file content using `az ad sp create-for-rbac --sdk-auth` from the Azure CLI.For more details see [az ad sp](https://docs.microsoft.com/en-us/cli/azure/ad/sp).
|
||||
- Set environment variable `AZURE_AUTH_LOCATION` for finding the file.
|
||||
- Use `auth.NewAuthorizerFromFile()` for getting the `Authorizer` based on the auth file.
|
||||
|
||||
3. From **Device Flow** by configuring `auth.DeviceFlowConfig` and calling the `Authorizer()` method.
|
||||
|
||||
Note: To authenticate you first need to create a service principal in Azure. To create a new service principal, run
|
||||
`az ad sp create-for-rbac -n "<app_name>"` in the
|
||||
[azure-cli](https://github.com/Azure/azure-cli). See
|
||||
[these docs](https://docs.microsoft.com/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest)
|
||||
for more info. Copy the new principal's ID, secret, and tenant ID for use in your app.
|
||||
|
||||
Alternatively, if your apps are running in Azure, you can now leverage the [Managed Service Identity](https://docs.microsoft.com/en-us/azure/active-directory/msi-overview).
|
||||
|
||||
# Versioning
|
||||
## SDK Versions
|
||||
The tags in this repository are based on, but do not conform to [SemVer.org's recommendations](http://semver.org/).
|
||||
For now, the "-beta" tag is an indicator that we are still in preview and still are planning on releasing some breaking
|
||||
changes.
|
||||
|
||||
## Azure Versions
|
||||
Azure services _mostly_ do not use SemVer based versions. Rather, they use profiles identified by dates. One will often
|
||||
see this casually referred to as an "APIVersion". At the moment, our SDK only supports the most recent profiles. In
|
||||
order to lock to an API version, one must also lock to an SDK version. However, as discussed in
|
||||
[#517](https://github.com/Azure/azure-sdk-for-go/issues/517), our objective is to reorganize and publish independent
|
||||
packages for each profile. In that way, we'll be able to have parallel support in a single SDK version for all
|
||||
APIVersions supported by Azure.
|
||||
azure-sdk-for-go provides at least a basic Go binding for every Azure API. To
|
||||
provide maximum flexibility to users, the SDK even includes previous versions of
|
||||
Azure APIs which are still in use. This enables us to support users of the
|
||||
most updated Azure datacenters, regional datacenters with earlier APIs, and
|
||||
even on-premises installations of Azure Stack.
|
||||
|
||||
# Documentation
|
||||
**SDK versions** apply globally and are tracked by git
|
||||
[tags](https://github.com/Azure/azure-sdk-for-go/tags). These are in x.y.z form
|
||||
and generally adhere to [semantic versioning](https://semver.org) specifications.
|
||||
|
||||
- Azure SDK for Go Documentation is available at [GoDoc.org](http://godoc.org/github.com/Azure/azure-sdk-for-go/).
|
||||
- Azure REST APIs used by packages in this repository are documented at [Microsoft Docs, Azure REST](https://docs.microsoft.com/en-us/rest/api/).
|
||||
- Azure Services are discussed in detail at [Microsoft Docs, Azure Services](https://docs.microsoft.com/en-us/azure/#pivot=services).
|
||||
**Service API versions** are generally represented by a date string and are
|
||||
tracked by offering separate packages for each version. For example, to choose the
|
||||
latest API versions for Compute and Network, use the following imports:
|
||||
|
||||
# Code samples
|
||||
```go
|
||||
import (
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2017-12-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2017-09-01/network"
|
||||
)
|
||||
```
|
||||
|
||||
- [Getting Started with Azure Blob Service in Go](https://github.com/Azure-Samples/storage-blob-go-getting-started)
|
||||
Occasionally service-side changes require major changes to existing versions.
|
||||
These cases are noted in the changelog.
|
||||
|
||||
# License
|
||||
All avilable services and versions are listed under the `services/` path in
|
||||
this repo and in [GoDoc][services_godoc]. Run `find ./services -type d
|
||||
-mindepth 3` to list all available service packages.
|
||||
|
||||
This project is published under [Apache 2.0 License](LICENSE).
|
||||
[services_godoc]: https://godoc.org/github.com/Azure/azure-sdk-for-go/services
|
||||
|
||||
# Contribute
|
||||
### Profiles
|
||||
|
||||
If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft
|
||||
Azure Projects Contribution Guidelines](http://azure.github.io/guidelines/).
|
||||
Azure **API profiles** specify subsets of Azure APIs and versions. Profiles can provide:
|
||||
|
||||
* **stability** for your application by locking to specific API versions; and/or
|
||||
* **compatibility** for your application with Azure Stack and regional Azure datacenters.
|
||||
|
||||
In the Go SDK, profiles are available under the `profiles/` path and their
|
||||
component API versions are aliases to the true service package under
|
||||
`services/`. You can use them as follows:
|
||||
|
||||
```go
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/compute/mgmt/compute"
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/network/mgmt/network"
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/storage/mgmt/storage"
|
||||
```
|
||||
|
||||
The 2017-03-09 profile is the only one currently available and is for use in
|
||||
hybrid Azure and Azure Stack environments. More profiles are under development.
|
||||
|
||||
In addition to versioned profiles, we also provide two special profiles
|
||||
`latest` and `preview`. These *always* include the most recent respective stable or
|
||||
preview API versions for each service, even when updating them to do so causes
|
||||
breaking changes. That is, these do *not* adhere to semantic versioning rules.
|
||||
|
||||
The `latest` and `preview` profiles can help you stay up to date with API
|
||||
updates as you build applications. Since they are by definition not stable,
|
||||
however, they **should not** be used in production apps. Instead, choose the
|
||||
latest specific API version (or an older one if necessary) from the `services/`
|
||||
path.
|
||||
|
||||
As an example, to automatically use the most recent Compute APIs, use one of
|
||||
the following imports:
|
||||
|
||||
```go
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute"
|
||||
import "github.com/Azure/azure-sdk-for-go/profiles/preview/compute/mgmt/compute"
|
||||
```
|
||||
|
||||
## Inspecting and Debugging
|
||||
|
||||
All clients implement some handy hooks to help inspect the underlying requests being made to Azure.
|
||||
|
||||
- `RequestInspector`: View and manipulate the go `http.Request` before it's sent
|
||||
- `ResponseInspector`: View the `http.Response` received
|
||||
|
||||
Here is an example of how these can be used with `net/http/httputil` to see requests and responses.
|
||||
|
||||
```go
|
||||
|
||||
vnetClient := network.NewVirtualNetworksClient("<subscriptionID>")
|
||||
vnetClient.RequestInspector = LogRequest()
|
||||
vnetClient.ResponseInspector = LogResponse()
|
||||
|
||||
...
|
||||
|
||||
func LogRequest() autorest.PrepareDecorator {
|
||||
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 {
|
||||
log.Println(err)
|
||||
}
|
||||
dump, _ := httputil.DumpRequestOut(r, true)
|
||||
log.Println(string(dump))
|
||||
return r, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func LogResponse() autorest.RespondDecorator {
|
||||
return func(p autorest.Responder) autorest.Responder {
|
||||
return autorest.ResponderFunc(func(r *http.Response) error {
|
||||
err := p.Respond(r)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
dump, _ := httputil.DumpResponse(r, true)
|
||||
log.Println(string(dump))
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Resources
|
||||
|
||||
- SDK docs are at [godoc.org](https://godoc.org/github.com/Azure/azure-sdk-for-go/).
|
||||
- SDK samples are at [Azure-Samples/azure-sdk-for-go-samples](https://github.com/Azure-Samples/azure-sdk-for-go-samples).
|
||||
- SDK notifications are published via the [Azure update feed](https://azure.microsoft.com/updates/).
|
||||
- Azure API docs are at [docs.microsoft.com/rest/api](https://docs.microsoft.com/rest/api/).
|
||||
- General Azure docs are at [docs.microsoft.com/azure](https://docs.microsoft.com/azure).
|
||||
|
||||
### Other Azure packages for Go
|
||||
|
||||
- [Azure Storage Blobs](https://azure.microsoft.com/services/storage/blobs) - [github.com/Azure/azure-storage-blob-go](https://github.com/Azure/azure-storage-blob-go)
|
||||
- [Azure Applications Insights](https://azure.microsoft.com/en-us/services/application-insights/) - [github.com/Microsoft/ApplicationInsights-Go](https://github.com/Microsoft/ApplicationInsights-Go)
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0, see [LICENSE](./LICENSE).
|
||||
|
||||
## Contribute
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
[samples_repo]: https://github.com/Azure-Samples/azure-sdk-for-go-samples
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
|
||||
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
-285
@@ -1,285 +0,0 @@
|
||||
# Introducing the Azure Resource Manager packages for Go
|
||||
|
||||
The `github.com/Azure/azure-sdk-for-go/arm` packages are used to perform operations using the Azure Resource Manager (ARM). Read more about [Azure Resource Manager vs. classic deployment](https://azure.microsoft.com/documentation/articles/resource-manager-deployment-model/). Packages for Azure Service Manager or classic deployment are in the [management](https://github.com/Azure/azure-sdk-for-go/tree/master/management) folder.
|
||||
|
||||
|
||||
## How Did We Get Here?
|
||||
|
||||
Azure is growing rapidly, regularly adding new services and features. While rapid growth
|
||||
is good for users, it is hard on SDKs. Each new service and each new feature requires someone to
|
||||
learn the details and add the needed code to the SDK. As a result, the
|
||||
[Azure SDK for Go](https://github.com/Azure/azure-sdk-for-go)
|
||||
has lagged behind Azure. It is missing
|
||||
entire services and has not kept current with features. There is simply too much change to maintain
|
||||
a hand-written SDK.
|
||||
|
||||
For this reason, the
|
||||
[Azure SDK for Go](https://github.com/Azure/azure-sdk-for-go),
|
||||
with the release of the Azure Resource Manager (ARM)
|
||||
packages, is transitioning to a generated-code model. Other Azure SDKs, notably the
|
||||
[Azure SDK for .NET](https://github.com/Azure/azure-sdk-for-net), have successfully adopted a
|
||||
generated-code strategy. Recently, Microsoft published the
|
||||
[AutoRest](https://github.com/Azure/autorest) tool used to create these SDKs and we have been adding support for Go. The ARM packages are
|
||||
the first set generated using this new toolchain. The input for AutoRest are the [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs), files in Swagger JSON format.
|
||||
|
||||
There are a couple of items to note. First, since both the tooling and the underlying support
|
||||
packages are new, the code is not yet "production ready". Treat these packages as of
|
||||
***beta*** quality.
|
||||
That's not to say we don't believe in the code, but we want to see what others think and how well
|
||||
they work in a variety of environments before settling down into an official, first release. If you
|
||||
find problems or have suggestions, please submit a pull request to document what you find. However,
|
||||
since the code is generated, we'll use your pull request to guide changes we make to the underlying
|
||||
generator versus merging the pull request itself.
|
||||
|
||||
The second item of note is that, to keep the generated code clean and reliable, it depends on
|
||||
another new package [go-autorest](https://github.com/Azure/go-autorest).
|
||||
Though part of the SDK, we separated the code to better control versioning and maintain agility.
|
||||
Since
|
||||
[go-autorest](https://github.com/Azure/go-autorest)
|
||||
is hand-crafted, we will take pull requests in the same manner as for our other repositories.
|
||||
|
||||
We intend to rapidly improve these packages until they are "production ready".
|
||||
So, try them out and give us your thoughts.
|
||||
|
||||
## What Have We Done?
|
||||
|
||||
Creating new frameworks is hard and often leads to "cliffs": The code is easy to use until some
|
||||
special case or tweak arises and then, well, then you're stuck. Often times small differences in
|
||||
requirements can lead to forking the code and investing a lot of time. Cliffs occur even more
|
||||
frequently in generated code. We wanted to avoid them and believe the new model does. Our initial
|
||||
goals were:
|
||||
|
||||
* Easy-to-use out of the box. It should be "clone and go" for straight-forward use.
|
||||
* Easy composition to handle the majority of complex cases.
|
||||
* Easy to integrate with existing frameworks, fit nicely with channels, supporting fan-out /
|
||||
fan-in set ups.
|
||||
|
||||
These are best shown in a series of examples, all of which are included in the
|
||||
[examples](/arm/examples) sub-folder.
|
||||
|
||||
## How is the SDK tested?
|
||||
|
||||
Testing the SDK is currently a work in progress. It includes three different points:
|
||||
|
||||
* Test the [Azure REST API specs](https://github.com/Azure/azure-rest-api-specs) against the APIs themselves. This way we can find if the specs are reflecting correctly the API behavior. All Azure SDKs can benefit from this tests.
|
||||
* Add [acceptance tests](https://github.com/Azure/autorest/blob/master/docs/developer/guide/writing-tests.md) to AutoRest.
|
||||
* Test the generated SDK with code samples. This would catch bugs that escaped the previous tests, and provide some documentation.
|
||||
|
||||
|
||||
## First a Sidenote: Authentication and the Azure Resource Manager
|
||||
|
||||
Before using the Azure Resource Manager packages, you need to understand how it authenticates and
|
||||
authorizes requests.
|
||||
Azure Resource Manager requests can be authorized through [OAuth2](http://oauth.net). While OAuth2 provides many advantages over
|
||||
certificates, programmatic use, such as for scripts on headless servers, requires understanding and
|
||||
creating one or more *Service Principals.*
|
||||
|
||||
The Azure-SDK-for-Node has an excellent tutorial that includes instructions for how to create Service Principals in the Portal and using the Azure CLI, both of which are applicable to Go.
|
||||
Find that documentation here: [Authenticaion, Azure/azure-sdk-for-node](https://github.com/Azure/azure-sdk-for-node/blob/master/Documentation/Authentication.md)
|
||||
|
||||
In addition, there are several good blog posts, such as
|
||||
[Automating Azure on your CI server using a Service Principal](http://blog.davidebbo.com/2014/12/azure-service-principal.html)
|
||||
and
|
||||
[Microsoft Azure REST API + OAuth 2.0](https://ahmetalpbalkan.com/blog/azure-rest-api-with-oauth2/),
|
||||
that describe what this means.
|
||||
For details on creating and authorizing Service Principals, see the MSDN articles
|
||||
[Azure API Management REST API Authentication](https://msdn.microsoft.com/library/azure/5b13010a-d202-4af5-aabf-7ebc26800b3d)
|
||||
and
|
||||
[Create a new Azure Service Principal using the Azure portal](https://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/).
|
||||
Dushyant Gill, a Senior Program Manager for Azure Active Directory, has written an extensive blog
|
||||
post,
|
||||
[Developer's Guide to Auth with Azure Resource Manager API](http://www.dushyantgill.com/blog/2015/05/23/developers-guide-to-auth-with-azure-resource-manager-api/),
|
||||
that is also quite helpful.
|
||||
|
||||
### Complete source code
|
||||
|
||||
Get code for a full example of [authenticating to Azure via certificate or device authorization](https://github.com/Azure/go-autorest/tree/master/autorest/azure/example).
|
||||
|
||||
## A Simple Example: Checking availability of name within Azure Storage
|
||||
|
||||
Each ARM provider, such as
|
||||
[Azure Storage](http://azure.microsoft.com/documentation/services/storage/)
|
||||
or
|
||||
[Azure Compute](https://azure.microsoft.com/documentation/services/virtual-machines/),
|
||||
has its own package. Start by importing
|
||||
the packages for the providers you need. Next, most packages divide their APIs across multiple
|
||||
clients to avoid name collision and improve usability. For example, the
|
||||
[Azure Storage](http://azure.microsoft.com/documentation/services/storage/)
|
||||
package has
|
||||
two clients:
|
||||
[storage.AccountsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient)
|
||||
and
|
||||
[storage.UsageOperationsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#UsageOperationsClient).
|
||||
To check if a name is available, use the
|
||||
[storage.AccountsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient).
|
||||
|
||||
Each ARM client composes with [autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client).
|
||||
[autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client)
|
||||
enables altering the behavior of the API calls by leveraging the decorator pattern of
|
||||
[go-autorest](https://github.com/Azure/go-autorest). For example, in the code above, the
|
||||
[azure.ServicePrincipalToken](https://godoc.org/github.com/Azure/go-autorest/autorest/azure#ServicePrincipalToken)
|
||||
includes a
|
||||
[WithAuthorization](https://godoc.org/github.com/Azure/go-autorest/autorest#Client.WithAuthorization)
|
||||
[autorest.PrepareDecorator](https://godoc.org/github.com/Azure/go-autorest/autorest#PrepareDecorator)
|
||||
that applies the OAuth2 authorization token to the request. It will, as needed, refresh the token
|
||||
using the supplied credentials.
|
||||
|
||||
Providing a decorated
|
||||
[autorest.Sender](https://godoc.org/github.com/Azure/go-autorest/autorest#Sender) or populating
|
||||
the [autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client)
|
||||
with a custom
|
||||
[autorest.PrepareDecorator](https://godoc.org/github.com/Azure/go-autorest/autorest#PrepareDecorator)
|
||||
or
|
||||
[autorest.RespondDecorator](https://godoc.org/github.com/Azure/go-autorest/autorest#RespondDecorator)
|
||||
enables more control. See the included example file
|
||||
[check.go](/arm/examples/check/check.go)
|
||||
for more details. Through these you can modify the outgoing request, inspect the incoming response,
|
||||
or even go so far as to provide a
|
||||
[circuit breaker](https://msdn.microsoft.com/library/dn589784.aspx)
|
||||
to protect your service from unexpected latencies.
|
||||
|
||||
Lastly, all Azure ARM API calls return an instance of
|
||||
[autorest.DetailedError](https://godoc.org/github.com/Azure/go-autorest/autorest#DetailedError).
|
||||
Not only DetailedError gives anonymous access to the original
|
||||
[error](http://golang.org/ref/spec#Errors),
|
||||
but provides the package type (e.g.,
|
||||
[storage.AccountsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient)),
|
||||
the failing method (e.g.,
|
||||
[CheckNameAvailability](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient.CheckNameAvailability)),
|
||||
and a detailed error message.
|
||||
|
||||
### Complete source code
|
||||
|
||||
Complete source code for this example can be found in [check.go](/arm/examples/check/check.go).
|
||||
|
||||
1. Create a [service principal](https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/). You will need the Tenant ID, Client ID and Client Secret for [authentication](#first-a-sidenote-authentication-and-the-azure-resource-manager), so keep them as soon as you get them.
|
||||
2. Get your Azure Subscription ID using either of the methods mentioned below:
|
||||
- Get it through the [portal](portal.azure.com) in the subscriptions section.
|
||||
- Get it using the [Azure CLI](https://azure.microsoft.com/documentation/articles/xplat-cli-install/) with command `azure account show`.
|
||||
- Get it using [Azure Powershell](https://azure.microsoft.com/documentation/articles/powershell-install-configure/) with cmdlet `Get-AzureRmSubscription`.
|
||||
3. Set environment variables `AZURE_TENANT_ID = <TENANT_ID>`, `AZURE_CLIENT_ID = <CLIENT_ID>`, `AZURE_CLIENT_SECRET = <CLIENT_SECRET>` and `AZURE_SUBSCRIPTION_ID = <SUBSCRIPTION_ID>`.
|
||||
4. Run the sample with commands:
|
||||
|
||||
```
|
||||
$ cd arm/examples/check
|
||||
$ go run check.go
|
||||
```
|
||||
|
||||
## Something a Bit More Complex: Creating a new Azure Storage account
|
||||
|
||||
Redundancy, both local and across regions, and service load affect service responsiveness. Some
|
||||
API calls will return before having completed the request. An Azure ARM API call indicates the
|
||||
request is incomplete (versus the request failed for some reason) by returning HTTP status code
|
||||
'202 Accepted.' The
|
||||
[autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client)
|
||||
composed into
|
||||
all of the Azure ARM clients, provides support for basic request polling. The default is to
|
||||
poll until a specified duration has passed (with polling frequency determined by the
|
||||
HTTP [Retry-After](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.37)
|
||||
header in the response). By changing the
|
||||
[autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client)
|
||||
settings, you can poll for a fixed number of attempts or elect to not poll at all.
|
||||
|
||||
Whether you elect to poll or not, all Azure ARM client responses compose with an instance of
|
||||
[autorest.Response](https://godoc.org/github.com/Azure/go-autorest/autorest#Response).
|
||||
At present,
|
||||
[autorest.Response](https://godoc.org/github.com/Azure/go-autorest/autorest#Response)
|
||||
only composes over the standard
|
||||
[http.Response](https://golang.org/pkg/net/http/#Response)
|
||||
object (that may change as we implement more features). When your code receives an error from an
|
||||
Azure ARM API call, you may find it useful to inspect the HTTP status code contained in the returned
|
||||
[autorest.Response](https://godoc.org/github.com/Azure/go-autorest/autorest#Response).
|
||||
If, for example, it is an HTTP 202, then you can use the
|
||||
[GetPollingLocation](https://godoc.org/github.com/Azure/go-autorest/autorest#Response.GetPollingLocation)
|
||||
response method to extract the URL at which to continue polling. Similarly, the
|
||||
[GetPollingDelay](https://godoc.org/github.com/Azure/go-autorest/autorest#Response.GetPollingDelay)
|
||||
response method returns, as a
|
||||
[time.Duration](http://golang.org/pkg/time/#Duration),
|
||||
the service suggested minimum polling delay.
|
||||
|
||||
Creating a new Azure storage account is a straight-forward way to see these concepts.
|
||||
|
||||
[autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client)
|
||||
portion of the
|
||||
[storage.AccountsClient](https://godoc.org/github.com/Azure/azure-sdk-for-go/arm/storage#AccountsClient)
|
||||
to poll for a fixed number of attempts versus polling for a set duration (which is the default).
|
||||
If an error occurs creating the storage account, the code inspects the HTTP status code and
|
||||
prints the URL the
|
||||
[Azure Storage](http://azure.microsoft.com/documentation/services/storage/)
|
||||
service returned for polling.
|
||||
|
||||
### Complete source for the example
|
||||
More details, including deleting the created account, are in the example code file [create.go](/arm/examples/create/create.go)
|
||||
|
||||
1. Create a [service principal](https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/). You will need the Tenant ID, Client ID and Client Secret for [authentication](#first-a-sidenote-authentication-and-the-azure-resource-manager), so keep them as soon as you get them.
|
||||
2. Get your Azure Subscription ID using either of the methods mentioned below:
|
||||
- Get it through the [portal](portal.azure.com) in the subscriptions section.
|
||||
- Get it using the [Azure CLI](https://azure.microsoft.com/documentation/articles/xplat-cli-install/) with command `azure account show`.
|
||||
- Get it using [Azure Powershell](https://azure.microsoft.com/documentation/articles/powershell-install-configure/) with cmdlet `Get-AzureRmSubscription`.
|
||||
3. Set environment variables `AZURE_TENANT_ID = <TENANT_ID>`, `AZURE_CLIENT_ID = <CLIENT_ID>`, `AZURE_CLIENT_SECRET = <CLIENT_SECRET>` and `AZURE_SUBSCRIPTION_ID = <SUBSCRIPTION_ID>`.
|
||||
4. Create a resource group and add its name in the first line of the main function.
|
||||
5. Run the example with commands:
|
||||
|
||||
```
|
||||
$ cd arm/examples/create
|
||||
$ go run create.go
|
||||
```
|
||||
|
||||
|
||||
## Making Asynchronous Requests
|
||||
|
||||
One of Go's many strong points is how natural it makes sending and managing asynchronous requests
|
||||
by means of goroutines. We wanted the ARM packages to fit naturally in the variety of asynchronous
|
||||
patterns used in Go code, but also be straight-forward for simple use cases. We accomplished both
|
||||
by adopting a pattern for all APIs. Each package API includes (at least) four methods
|
||||
(more if the API returns a paged result set). For example, for an API call named `Foo` the package
|
||||
defines:
|
||||
|
||||
- `FooPreparer`: This method accepts the arguments for the API and returns a prepared
|
||||
`http.Request`.
|
||||
- `FooSender`: This method sends the prepared `http.Request`. It handles the possible status codes
|
||||
and will, unless the disabled in the [autorest.Client](https://godoc.org/github.com/Azure/go-autorest/autorest#Client), handling polling.
|
||||
- `FooResponder`: This method accepts and handles the `http.Response` returned by the sender
|
||||
and unmarshals the JSON, if any, into the result.
|
||||
- `Foo`: This method accepts the arguments for the API and returns the result. It is a wrapper
|
||||
around the `FooPreparer`, `FooSender`, and `FooResponder`.
|
||||
|
||||
By using the preparer, sender, and responder methods, package users can spread request and
|
||||
response handling across goroutines as needed. Further, adding a cancel channel to the
|
||||
`http.Response` (most easily through a
|
||||
[PrepareDecorator](https://godoc.org/github.com/Azure/go-autorest/autorest#PrepareDecorator)),
|
||||
enables canceling sent requests (see the documentation on
|
||||
[http.Request](https://golang.org/pkg/net/http/#Request)) for details.
|
||||
|
||||
## Paged Result Sets
|
||||
|
||||
Some API calls return partial results. Typically, when they do, the result structure will include
|
||||
a `Value` array and a `NextLink` URL. The `NextLink` URL is used to retrieve the next page or
|
||||
block of results.
|
||||
|
||||
The packages add two methods to make working with and retrieving paged results natural. First,
|
||||
on paged result structures, the packages include a preparer method that returns an `http.Request`
|
||||
for the next set of results. For a result set returned in a structure named `FooResults`, the
|
||||
package will include a method named `FooResultsPreparer`. If the `NextLink` is `nil` or empty, the
|
||||
method returns `nil`.
|
||||
|
||||
The corresponding API (which typically includes "List" in the name) has a method to ease retrieving
|
||||
the next result set given a result set. For example, for an API named `FooList`, the package will
|
||||
include `FooListNextResults` that accepts the results of the last call and returns the next set.
|
||||
|
||||
## Summing Up
|
||||
|
||||
The new Azure Resource Manager packages for the Azure SDK for Go are a big step toward keeping the
|
||||
SDK current with Azure's rapid growth.
|
||||
As mentioned, we intend to rapidly stabilize these packages for production use.
|
||||
We'll also add more examples, including some highlighting the
|
||||
[Azure Resource Manager Templates](https://msdn.microsoft.com/library/azure/dn790568.aspx)
|
||||
and the other providers.
|
||||
|
||||
So, give the packages a try, explore the various ARM providers, and let us know what you think.
|
||||
|
||||
We look forward to hearing from you!
|
||||
|
||||
## License
|
||||
|
||||
See the Azure SDK for Go LICENSE file.
|
||||
-360
@@ -1,360 +0,0 @@
|
||||
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 1.0.1.0
|
||||
// Changes may cause incorrect behavior and will be lost if the code is
|
||||
// regenerated.
|
||||
|
||||
import (
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HTTPStatusCode enumerates the values for http status code.
|
||||
type HTTPStatusCode string
|
||||
|
||||
const (
|
||||
// Accepted specifies the accepted state for http status code.
|
||||
Accepted HTTPStatusCode = "Accepted"
|
||||
// Ambiguous specifies the ambiguous state for http status code.
|
||||
Ambiguous HTTPStatusCode = "Ambiguous"
|
||||
// BadGateway specifies the bad gateway state for http status code.
|
||||
BadGateway HTTPStatusCode = "BadGateway"
|
||||
// BadRequest specifies the bad request state for http status code.
|
||||
BadRequest HTTPStatusCode = "BadRequest"
|
||||
// Conflict specifies the conflict state for http status code.
|
||||
Conflict HTTPStatusCode = "Conflict"
|
||||
// Continue specifies the continue state for http status code.
|
||||
Continue HTTPStatusCode = "Continue"
|
||||
// Created specifies the created state for http status code.
|
||||
Created HTTPStatusCode = "Created"
|
||||
// ExpectationFailed specifies the expectation failed state for http status
|
||||
// code.
|
||||
ExpectationFailed HTTPStatusCode = "ExpectationFailed"
|
||||
// Forbidden specifies the forbidden state for http status code.
|
||||
Forbidden HTTPStatusCode = "Forbidden"
|
||||
// Found specifies the found state for http status code.
|
||||
Found HTTPStatusCode = "Found"
|
||||
// GatewayTimeout specifies the gateway timeout state for http status code.
|
||||
GatewayTimeout HTTPStatusCode = "GatewayTimeout"
|
||||
// Gone specifies the gone state for http status code.
|
||||
Gone HTTPStatusCode = "Gone"
|
||||
// HTTPVersionNotSupported specifies the http version not supported state
|
||||
// for http status code.
|
||||
HTTPVersionNotSupported HTTPStatusCode = "HttpVersionNotSupported"
|
||||
// InternalServerError specifies the internal server error state for http
|
||||
// status code.
|
||||
InternalServerError HTTPStatusCode = "InternalServerError"
|
||||
// LengthRequired specifies the length required state for http status code.
|
||||
LengthRequired HTTPStatusCode = "LengthRequired"
|
||||
// MethodNotAllowed specifies the method not allowed state for http status
|
||||
// code.
|
||||
MethodNotAllowed HTTPStatusCode = "MethodNotAllowed"
|
||||
// Moved specifies the moved state for http status code.
|
||||
Moved HTTPStatusCode = "Moved"
|
||||
// MovedPermanently specifies the moved permanently state for http status
|
||||
// code.
|
||||
MovedPermanently HTTPStatusCode = "MovedPermanently"
|
||||
// MultipleChoices specifies the multiple choices state for http status
|
||||
// code.
|
||||
MultipleChoices HTTPStatusCode = "MultipleChoices"
|
||||
// NoContent specifies the no content state for http status code.
|
||||
NoContent HTTPStatusCode = "NoContent"
|
||||
// NonAuthoritativeInformation specifies the non authoritative information
|
||||
// state for http status code.
|
||||
NonAuthoritativeInformation HTTPStatusCode = "NonAuthoritativeInformation"
|
||||
// NotAcceptable specifies the not acceptable state for http status code.
|
||||
NotAcceptable HTTPStatusCode = "NotAcceptable"
|
||||
// NotFound specifies the not found state for http status code.
|
||||
NotFound HTTPStatusCode = "NotFound"
|
||||
// NotImplemented specifies the not implemented state for http status code.
|
||||
NotImplemented HTTPStatusCode = "NotImplemented"
|
||||
// NotModified specifies the not modified state for http status code.
|
||||
NotModified HTTPStatusCode = "NotModified"
|
||||
// OK specifies the ok state for http status code.
|
||||
OK HTTPStatusCode = "OK"
|
||||
// PartialContent specifies the partial content state for http status code.
|
||||
PartialContent HTTPStatusCode = "PartialContent"
|
||||
// PaymentRequired specifies the payment required state for http status
|
||||
// code.
|
||||
PaymentRequired HTTPStatusCode = "PaymentRequired"
|
||||
// PreconditionFailed specifies the precondition failed state for http
|
||||
// status code.
|
||||
PreconditionFailed HTTPStatusCode = "PreconditionFailed"
|
||||
// ProxyAuthenticationRequired specifies the proxy authentication required
|
||||
// state for http status code.
|
||||
ProxyAuthenticationRequired HTTPStatusCode = "ProxyAuthenticationRequired"
|
||||
// Redirect specifies the redirect state for http status code.
|
||||
Redirect HTTPStatusCode = "Redirect"
|
||||
// RedirectKeepVerb specifies the redirect keep verb state for http status
|
||||
// code.
|
||||
RedirectKeepVerb HTTPStatusCode = "RedirectKeepVerb"
|
||||
// RedirectMethod specifies the redirect method state for http status code.
|
||||
RedirectMethod HTTPStatusCode = "RedirectMethod"
|
||||
// RequestedRangeNotSatisfiable specifies the requested range not
|
||||
// satisfiable state for http status code.
|
||||
RequestedRangeNotSatisfiable HTTPStatusCode = "RequestedRangeNotSatisfiable"
|
||||
// RequestEntityTooLarge specifies the request entity too large state for
|
||||
// http status code.
|
||||
RequestEntityTooLarge HTTPStatusCode = "RequestEntityTooLarge"
|
||||
// RequestTimeout specifies the request timeout state for http status code.
|
||||
RequestTimeout HTTPStatusCode = "RequestTimeout"
|
||||
// RequestURITooLong specifies the request uri too long state for http
|
||||
// status code.
|
||||
RequestURITooLong HTTPStatusCode = "RequestUriTooLong"
|
||||
// ResetContent specifies the reset content state for http status code.
|
||||
ResetContent HTTPStatusCode = "ResetContent"
|
||||
// SeeOther specifies the see other state for http status code.
|
||||
SeeOther HTTPStatusCode = "SeeOther"
|
||||
// ServiceUnavailable specifies the service unavailable state for http
|
||||
// status code.
|
||||
ServiceUnavailable HTTPStatusCode = "ServiceUnavailable"
|
||||
// SwitchingProtocols specifies the switching protocols state for http
|
||||
// status code.
|
||||
SwitchingProtocols HTTPStatusCode = "SwitchingProtocols"
|
||||
// TemporaryRedirect specifies the temporary redirect state for http status
|
||||
// code.
|
||||
TemporaryRedirect HTTPStatusCode = "TemporaryRedirect"
|
||||
// Unauthorized specifies the unauthorized state for http status code.
|
||||
Unauthorized HTTPStatusCode = "Unauthorized"
|
||||
// UnsupportedMediaType specifies the unsupported media type state for http
|
||||
// status code.
|
||||
UnsupportedMediaType HTTPStatusCode = "UnsupportedMediaType"
|
||||
// Unused specifies the unused state for http status code.
|
||||
Unused HTTPStatusCode = "Unused"
|
||||
// UpgradeRequired specifies the upgrade required state for http status
|
||||
// code.
|
||||
UpgradeRequired HTTPStatusCode = "UpgradeRequired"
|
||||
// UseProxy specifies the use proxy state for http status code.
|
||||
UseProxy HTTPStatusCode = "UseProxy"
|
||||
)
|
||||
|
||||
// OperationStatus enumerates the values for operation status.
|
||||
type OperationStatus string
|
||||
|
||||
const (
|
||||
// Failed specifies the failed state for operation status.
|
||||
Failed OperationStatus = "Failed"
|
||||
// InProgress specifies the in progress state for operation status.
|
||||
InProgress OperationStatus = "InProgress"
|
||||
// Succeeded specifies the succeeded state for operation status.
|
||||
Succeeded OperationStatus = "Succeeded"
|
||||
)
|
||||
|
||||
// RecordType enumerates the values for record type.
|
||||
type RecordType string
|
||||
|
||||
const (
|
||||
// A specifies the a state for record type.
|
||||
A RecordType = "A"
|
||||
// AAAA specifies the aaaa state for record type.
|
||||
AAAA RecordType = "AAAA"
|
||||
// CNAME specifies the cname state for record type.
|
||||
CNAME RecordType = "CNAME"
|
||||
// MX specifies the mx state for record type.
|
||||
MX RecordType = "MX"
|
||||
// NS specifies the ns state for record type.
|
||||
NS RecordType = "NS"
|
||||
// PTR specifies the ptr state for record type.
|
||||
PTR RecordType = "PTR"
|
||||
// SOA specifies the soa state for record type.
|
||||
SOA RecordType = "SOA"
|
||||
// SRV specifies the srv state for record type.
|
||||
SRV RecordType = "SRV"
|
||||
// TXT specifies the txt state for record type.
|
||||
TXT RecordType = "TXT"
|
||||
)
|
||||
|
||||
// AaaaRecord is an AAAA record.
|
||||
type AaaaRecord struct {
|
||||
Ipv6Address *string `json:"ipv6Address,omitempty"`
|
||||
}
|
||||
|
||||
// ARecord is an A record.
|
||||
type ARecord struct {
|
||||
Ipv4Address *string `json:"ipv4Address,omitempty"`
|
||||
}
|
||||
|
||||
// CloudError is
|
||||
type CloudError struct {
|
||||
Error *CloudErrorBody `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// CloudErrorBody is
|
||||
type CloudErrorBody struct {
|
||||
Code *string `json:"code,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
Target *string `json:"target,omitempty"`
|
||||
Details *[]CloudErrorBody `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// CnameRecord is a CNAME record.
|
||||
type CnameRecord struct {
|
||||
Cname *string `json:"cname,omitempty"`
|
||||
}
|
||||
|
||||
// MxRecord is an MX record.
|
||||
type MxRecord struct {
|
||||
Preference *int32 `json:"preference,omitempty"`
|
||||
Exchange *string `json:"exchange,omitempty"`
|
||||
}
|
||||
|
||||
// NsRecord is an NS record.
|
||||
type NsRecord struct {
|
||||
Nsdname *string `json:"nsdname,omitempty"`
|
||||
}
|
||||
|
||||
// PtrRecord is a PTR record.
|
||||
type PtrRecord struct {
|
||||
Ptrdname *string `json:"ptrdname,omitempty"`
|
||||
}
|
||||
|
||||
// RecordSet is describes a DNS record set (a collection of DNS records with
|
||||
// the same name and type).
|
||||
type RecordSet struct {
|
||||
autorest.Response `json:"-"`
|
||||
ID *string `json:"id,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
Etag *string `json:"etag,omitempty"`
|
||||
*RecordSetProperties `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// RecordSetListResult is the response to a record set List operation.
|
||||
type RecordSetListResult struct {
|
||||
autorest.Response `json:"-"`
|
||||
Value *[]RecordSet `json:"value,omitempty"`
|
||||
NextLink *string `json:"nextLink,omitempty"`
|
||||
}
|
||||
|
||||
// RecordSetListResultPreparer prepares a request to retrieve the next set of results. It returns
|
||||
// nil if no more results exist.
|
||||
func (client RecordSetListResult) RecordSetListResultPreparer() (*http.Request, error) {
|
||||
if client.NextLink == nil || len(to.String(client.NextLink)) <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return autorest.Prepare(&http.Request{},
|
||||
autorest.AsJSON(),
|
||||
autorest.AsGet(),
|
||||
autorest.WithBaseURL(to.String(client.NextLink)))
|
||||
}
|
||||
|
||||
// RecordSetProperties is represents the properties of the records in the
|
||||
// record set.
|
||||
type RecordSetProperties struct {
|
||||
Metadata *map[string]*string `json:"metadata,omitempty"`
|
||||
TTL *int64 `json:"TTL,omitempty"`
|
||||
ARecords *[]ARecord `json:"ARecords,omitempty"`
|
||||
AaaaRecords *[]AaaaRecord `json:"AAAARecords,omitempty"`
|
||||
MxRecords *[]MxRecord `json:"MXRecords,omitempty"`
|
||||
NsRecords *[]NsRecord `json:"NSRecords,omitempty"`
|
||||
PtrRecords *[]PtrRecord `json:"PTRRecords,omitempty"`
|
||||
SrvRecords *[]SrvRecord `json:"SRVRecords,omitempty"`
|
||||
TxtRecords *[]TxtRecord `json:"TXTRecords,omitempty"`
|
||||
CnameRecord *CnameRecord `json:"CNAMERecord,omitempty"`
|
||||
SoaRecord *SoaRecord `json:"SOARecord,omitempty"`
|
||||
}
|
||||
|
||||
// RecordSetUpdateParameters is parameters supplied to update a record set.
|
||||
type RecordSetUpdateParameters struct {
|
||||
RecordSet *RecordSet `json:"RecordSet,omitempty"`
|
||||
}
|
||||
|
||||
// Resource is
|
||||
type Resource struct {
|
||||
ID *string `json:"id,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
Location *string `json:"location,omitempty"`
|
||||
Tags *map[string]*string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// SoaRecord is an SOA record.
|
||||
type SoaRecord struct {
|
||||
Host *string `json:"host,omitempty"`
|
||||
Email *string `json:"email,omitempty"`
|
||||
SerialNumber *int64 `json:"serialNumber,omitempty"`
|
||||
RefreshTime *int64 `json:"refreshTime,omitempty"`
|
||||
RetryTime *int64 `json:"retryTime,omitempty"`
|
||||
ExpireTime *int64 `json:"expireTime,omitempty"`
|
||||
MinimumTTL *int64 `json:"minimumTTL,omitempty"`
|
||||
}
|
||||
|
||||
// SrvRecord is an SRV record.
|
||||
type SrvRecord struct {
|
||||
Priority *int32 `json:"priority,omitempty"`
|
||||
Weight *int32 `json:"weight,omitempty"`
|
||||
Port *int32 `json:"port,omitempty"`
|
||||
Target *string `json:"target,omitempty"`
|
||||
}
|
||||
|
||||
// SubResource is
|
||||
type SubResource struct {
|
||||
ID *string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// TxtRecord is a TXT record.
|
||||
type TxtRecord struct {
|
||||
Value *[]string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// Zone is describes a DNS zone.
|
||||
type Zone struct {
|
||||
autorest.Response `json:"-"`
|
||||
ID *string `json:"id,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Type *string `json:"type,omitempty"`
|
||||
Location *string `json:"location,omitempty"`
|
||||
Tags *map[string]*string `json:"tags,omitempty"`
|
||||
Etag *string `json:"etag,omitempty"`
|
||||
*ZoneProperties `json:"properties,omitempty"`
|
||||
}
|
||||
|
||||
// ZoneDeleteResult is the response to a Zone Delete operation.
|
||||
type ZoneDeleteResult struct {
|
||||
autorest.Response `json:"-"`
|
||||
AzureAsyncOperation *string `json:"azureAsyncOperation,omitempty"`
|
||||
Status OperationStatus `json:"status,omitempty"`
|
||||
StatusCode HTTPStatusCode `json:"statusCode,omitempty"`
|
||||
RequestID *string `json:"requestId,omitempty"`
|
||||
}
|
||||
|
||||
// ZoneListResult is the response to a Zone List or ListAll operation.
|
||||
type ZoneListResult struct {
|
||||
autorest.Response `json:"-"`
|
||||
Value *[]Zone `json:"value,omitempty"`
|
||||
NextLink *string `json:"nextLink,omitempty"`
|
||||
}
|
||||
|
||||
// ZoneListResultPreparer prepares a request to retrieve the next set of results. It returns
|
||||
// nil if no more results exist.
|
||||
func (client ZoneListResult) ZoneListResultPreparer() (*http.Request, error) {
|
||||
if client.NextLink == nil || len(to.String(client.NextLink)) <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return autorest.Prepare(&http.Request{},
|
||||
autorest.AsJSON(),
|
||||
autorest.AsGet(),
|
||||
autorest.WithBaseURL(to.String(client.NextLink)))
|
||||
}
|
||||
|
||||
// ZoneProperties is represents the properties of the zone.
|
||||
type ZoneProperties struct {
|
||||
MaxNumberOfRecordSets *int64 `json:"maxNumberOfRecordSets,omitempty"`
|
||||
NumberOfRecordSets *int64 `json:"numberOfRecordSets,omitempty"`
|
||||
NameServers *[]string `json:"nameServers,omitempty"`
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
dirname $(find | grep _test.go | grep -v vendor) | sort -u
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
hash: fc11c273a4bfae9a077f2238a4693fa3af3d815dfc1b1e9ec75d9eb8e6428993
|
||||
updated: 2017-05-04T15:24:51.52099-07:00
|
||||
imports:
|
||||
- name: github.com/Azure/go-autorest
|
||||
version: 58f6f26e200fa5dfb40c9cd1c83f3e2c860d779d
|
||||
subpackages:
|
||||
- autorest
|
||||
- autorest/azure
|
||||
- autorest/date
|
||||
- autorest/to
|
||||
- autorest/validation
|
||||
- autorest/adal
|
||||
- name: github.com/dgrijalva/jwt-go
|
||||
version: 2268707a8f0843315e2004ee4f1d021dc08baedf
|
||||
- name: github.com/howeyc/gopass
|
||||
version: bf9dde6d0d2c004a008c27aaee91170c786f6db8
|
||||
- name: github.com/mattn/go-colorable
|
||||
version: ded68f7a9561c023e790de24279db7ebf473ea80
|
||||
- name: github.com/mattn/go-isatty
|
||||
version: fc9e8d8ef48496124e79ae0df75490096eccf6fe
|
||||
- name: github.com/mgutz/ansi
|
||||
version: 9520e82c474b0a04dd04f8a40959027271bab992
|
||||
- name: github.com/mgutz/minimist
|
||||
version: 39eb8cf573ca29344bd7d7e6ba4d7febdebd37a9
|
||||
- name: github.com/mgutz/str
|
||||
version: 968bf66e3da857419e4f6e71b2d5c9ae95682dc4
|
||||
- name: github.com/mgutz/to
|
||||
version: 00c06406c2dd2e011f153a6502a21473676db33f
|
||||
- name: github.com/MichaelTJones/walk
|
||||
version: 4748e29d5718c2df4028a6543edf86fd8cc0f881
|
||||
- name: github.com/nozzle/throttler
|
||||
version: d9b45f19996c645d38c9266d1f5cf1990e930119
|
||||
- name: github.com/satori/uuid
|
||||
version: 5bf94b69c6b68ee1b541973bb8e1144db23a194b
|
||||
- name: github.com/shopspring/decimal
|
||||
version: 3526cd0bdb7f64e1178943b7dee81a0cc3d86a69
|
||||
- name: golang.org/x/crypto
|
||||
version: 5a033cc77e57eca05bdb50522851d29e03569cbe
|
||||
subpackages:
|
||||
- pkcs12
|
||||
- pkcs12/internal/rc2
|
||||
- ssh/terminal
|
||||
- name: golang.org/x/sys
|
||||
version: 9ccfe848b9db8435a24c424abbc07a921adf1df5
|
||||
subpackages:
|
||||
- unix
|
||||
- name: gopkg.in/check.v1
|
||||
version: 20d25e2804050c1cd24a7eea1e7a6447dd0e74ec
|
||||
- name: gopkg.in/godo.v2
|
||||
version: b5fd2f0bef1ebe832e628cfad18ab1cc707f65a1
|
||||
subpackages:
|
||||
- glob
|
||||
- util
|
||||
- watcher
|
||||
- watcher/fswatch
|
||||
testImports:
|
||||
- name: github.com/dnaeon/go-vcr
|
||||
version: 87d4990451a858cc210399285be976e63bc3c364
|
||||
subpackages:
|
||||
- cassette
|
||||
- recorder
|
||||
- name: gopkg.in/yaml.v2
|
||||
version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package: github.com/Azure/azure-sdk-for-go
|
||||
import:
|
||||
- package: github.com/Azure/go-autorest
|
||||
version: ~8.0.0
|
||||
subpackages:
|
||||
- /autorest
|
||||
- autorest/azure
|
||||
- autorest/date
|
||||
- autorest/to
|
||||
- package: golang.org/x/crypto
|
||||
subpackages:
|
||||
- /pkcs12
|
||||
- package: gopkg.in/check.v1
|
||||
Generated
Vendored
Executable → Regular
+10
-11
@@ -1,4 +1,4 @@
|
||||
// Package dns implements the Azure ARM Dns service API version 2016-04-01.
|
||||
// Package dns implements the Azure ARM Dns service API version 2017-09-01.
|
||||
//
|
||||
// The DNS Management Client.
|
||||
package dns
|
||||
@@ -17,9 +17,8 @@ package dns
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0
|
||||
// Changes may cause incorrect behavior and will be lost if the code is
|
||||
// regenerated.
|
||||
// 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"
|
||||
@@ -30,21 +29,21 @@ const (
|
||||
DefaultBaseURI = "https://management.azure.com"
|
||||
)
|
||||
|
||||
// ManagementClient is the base client for Dns.
|
||||
type ManagementClient struct {
|
||||
// BaseClient is the base client for Dns.
|
||||
type BaseClient struct {
|
||||
autorest.Client
|
||||
BaseURI string
|
||||
SubscriptionID string
|
||||
}
|
||||
|
||||
// New creates an instance of the ManagementClient client.
|
||||
func New(subscriptionID string) ManagementClient {
|
||||
// New creates an instance of the BaseClient client.
|
||||
func New(subscriptionID string) BaseClient {
|
||||
return NewWithBaseURI(DefaultBaseURI, subscriptionID)
|
||||
}
|
||||
|
||||
// NewWithBaseURI creates an instance of the ManagementClient client.
|
||||
func NewWithBaseURI(baseURI string, subscriptionID string) ManagementClient {
|
||||
return ManagementClient{
|
||||
// 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,
|
||||
Generated
Vendored
+737
@@ -0,0 +1,737 @@
|
||||
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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
err = azure.NewAsyncOpIncompleteError("dns.ZonesDeleteFuture")
|
||||
return
|
||||
}
|
||||
ar.Response = future.Response()
|
||||
return
|
||||
}
|
||||
Generated
Vendored
Executable → Regular
+133
-111
@@ -14,11 +14,11 @@ package dns
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0
|
||||
// Changes may cause incorrect behavior and will be lost if the code is
|
||||
// regenerated.
|
||||
// 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"
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
|
||||
// RecordSetsClient is the the DNS Management Client.
|
||||
type RecordSetsClient struct {
|
||||
ManagementClient
|
||||
BaseClient
|
||||
}
|
||||
|
||||
// NewRecordSetsClient creates an instance of the RecordSetsClient client.
|
||||
@@ -34,27 +34,25 @@ func NewRecordSetsClient(subscriptionID string) RecordSetsClient {
|
||||
return NewRecordSetsClientWithBaseURI(DefaultBaseURI, subscriptionID)
|
||||
}
|
||||
|
||||
// NewRecordSetsClientWithBaseURI creates an instance of the RecordSetsClient
|
||||
// client.
|
||||
// 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.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. zoneName is the name of
|
||||
// the DNS zone (without a terminating dot). relativeRecordSetName is the name
|
||||
// of the record set, relative to the name of the zone. recordType is 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 is
|
||||
// parameters supplied to the CreateOrUpdate operation. ifMatch is 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 is 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(resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string, ifNoneMatch string) (result RecordSet, err error) {
|
||||
req, err := client.CreateOrUpdatePreparer(resourceGroupName, zoneName, relativeRecordSetName, recordType, parameters, ifMatch, ifNoneMatch)
|
||||
// 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
|
||||
@@ -76,7 +74,7 @@ func (client RecordSetsClient) CreateOrUpdate(resourceGroupName string, zoneName
|
||||
}
|
||||
|
||||
// CreateOrUpdatePreparer prepares the CreateOrUpdate request.
|
||||
func (client RecordSetsClient) CreateOrUpdatePreparer(resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string, ifNoneMatch string) (*http.Request, error) {
|
||||
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,
|
||||
@@ -85,13 +83,13 @@ func (client RecordSetsClient) CreateOrUpdatePreparer(resourceGroupName string,
|
||||
"zoneName": autorest.Encode("path", zoneName),
|
||||
}
|
||||
|
||||
const APIVersion = "2016-04-01"
|
||||
const APIVersion = "2017-09-01"
|
||||
queryParameters := map[string]interface{}{
|
||||
"api-version": APIVersion,
|
||||
}
|
||||
|
||||
preparer := autorest.CreatePreparer(
|
||||
autorest.AsJSON(),
|
||||
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),
|
||||
@@ -105,13 +103,14 @@ func (client RecordSetsClient) CreateOrUpdatePreparer(resourceGroupName string,
|
||||
preparer = autorest.DecoratePreparer(preparer,
|
||||
autorest.WithHeader("If-None-Match", autorest.String(ifNoneMatch)))
|
||||
}
|
||||
return preparer.Prepare(&http.Request{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always
|
||||
@@ -120,26 +119,24 @@ func (client RecordSetsClient) CreateOrUpdateResponder(resp *http.Response) (res
|
||||
err = autorest.Respond(
|
||||
resp,
|
||||
client.ByInspecting(),
|
||||
azure.WithErrorUnlessStatusCode(http.StatusCreated, http.StatusOK),
|
||||
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.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. zoneName is the name of
|
||||
// the DNS zone (without a terminating dot). relativeRecordSetName is the name
|
||||
// of the record set, relative to the name of the zone. recordType is 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 is 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(resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, ifMatch string) (result autorest.Response, err error) {
|
||||
req, err := client.DeletePreparer(resourceGroupName, zoneName, relativeRecordSetName, recordType, ifMatch)
|
||||
// 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
|
||||
@@ -161,7 +158,7 @@ func (client RecordSetsClient) Delete(resourceGroupName string, zoneName string,
|
||||
}
|
||||
|
||||
// DeletePreparer prepares the Delete request.
|
||||
func (client RecordSetsClient) DeletePreparer(resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, ifMatch string) (*http.Request, error) {
|
||||
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,
|
||||
@@ -170,7 +167,7 @@ func (client RecordSetsClient) DeletePreparer(resourceGroupName string, zoneName
|
||||
"zoneName": autorest.Encode("path", zoneName),
|
||||
}
|
||||
|
||||
const APIVersion = "2016-04-01"
|
||||
const APIVersion = "2017-09-01"
|
||||
queryParameters := map[string]interface{}{
|
||||
"api-version": APIVersion,
|
||||
}
|
||||
@@ -184,13 +181,14 @@ func (client RecordSetsClient) DeletePreparer(resourceGroupName string, zoneName
|
||||
preparer = autorest.DecoratePreparer(preparer,
|
||||
autorest.WithHeader("If-Match", autorest.String(ifMatch)))
|
||||
}
|
||||
return preparer.Prepare(&http.Request{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// DeleteResponder handles the response to the Delete request. The method always
|
||||
@@ -199,20 +197,20 @@ func (client RecordSetsClient) DeleteResponder(resp *http.Response) (result auto
|
||||
err = autorest.Respond(
|
||||
resp,
|
||||
client.ByInspecting(),
|
||||
azure.WithErrorUnlessStatusCode(http.StatusNoContent, http.StatusOK),
|
||||
azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent),
|
||||
autorest.ByClosing())
|
||||
result.Response = resp
|
||||
return
|
||||
}
|
||||
|
||||
// Get gets a record set.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. zoneName is the name of
|
||||
// the DNS zone (without a terminating dot). relativeRecordSetName is the name
|
||||
// of the record set, relative to the name of the zone. recordType is the type
|
||||
// of DNS record in this record set.
|
||||
func (client RecordSetsClient) Get(resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType) (result RecordSet, err error) {
|
||||
req, err := client.GetPreparer(resourceGroupName, zoneName, relativeRecordSetName, recordType)
|
||||
// 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
|
||||
@@ -234,7 +232,7 @@ func (client RecordSetsClient) Get(resourceGroupName string, zoneName string, re
|
||||
}
|
||||
|
||||
// GetPreparer prepares the Get request.
|
||||
func (client RecordSetsClient) GetPreparer(resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType) (*http.Request, error) {
|
||||
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,
|
||||
@@ -243,7 +241,7 @@ func (client RecordSetsClient) GetPreparer(resourceGroupName string, zoneName st
|
||||
"zoneName": autorest.Encode("path", zoneName),
|
||||
}
|
||||
|
||||
const APIVersion = "2016-04-01"
|
||||
const APIVersion = "2017-09-01"
|
||||
queryParameters := map[string]interface{}{
|
||||
"api-version": APIVersion,
|
||||
}
|
||||
@@ -253,13 +251,14 @@ func (client RecordSetsClient) GetPreparer(resourceGroupName string, zoneName st
|
||||
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{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// GetResponder handles the response to the Get request. The method always
|
||||
@@ -276,12 +275,16 @@ func (client RecordSetsClient) GetResponder(resp *http.Response) (result RecordS
|
||||
}
|
||||
|
||||
// ListByDNSZone lists all record sets in a DNS zone.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. zoneName is the name of
|
||||
// the DNS zone (without a terminating dot). top is the maximum number of
|
||||
// record sets to return. If not specified, returns up to 100 record sets.
|
||||
func (client RecordSetsClient) ListByDNSZone(resourceGroupName string, zoneName string, top *int32) (result RecordSetListResult, err error) {
|
||||
req, err := client.ListByDNSZonePreparer(resourceGroupName, zoneName, top)
|
||||
// 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
|
||||
@@ -289,12 +292,12 @@ func (client RecordSetsClient) ListByDNSZone(resourceGroupName string, zoneName
|
||||
|
||||
resp, err := client.ListByDNSZoneSender(req)
|
||||
if err != nil {
|
||||
result.Response = autorest.Response{Response: resp}
|
||||
result.rslr.Response = autorest.Response{Response: resp}
|
||||
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByDNSZone", resp, "Failure sending request")
|
||||
return
|
||||
}
|
||||
|
||||
result, err = client.ListByDNSZoneResponder(resp)
|
||||
result.rslr, err = client.ListByDNSZoneResponder(resp)
|
||||
if err != nil {
|
||||
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByDNSZone", resp, "Failure responding to request")
|
||||
}
|
||||
@@ -303,33 +306,37 @@ func (client RecordSetsClient) ListByDNSZone(resourceGroupName string, zoneName
|
||||
}
|
||||
|
||||
// ListByDNSZonePreparer prepares the ListByDNSZone request.
|
||||
func (client RecordSetsClient) ListByDNSZonePreparer(resourceGroupName string, zoneName string, top *int32) (*http.Request, error) {
|
||||
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 = "2016-04-01"
|
||||
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{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// ListByDNSZoneResponder handles the response to the ListByDNSZone request. The method always
|
||||
@@ -345,38 +352,45 @@ func (client RecordSetsClient) ListByDNSZoneResponder(resp *http.Response) (resu
|
||||
return
|
||||
}
|
||||
|
||||
// ListByDNSZoneNextResults retrieves the next set of results, if any.
|
||||
func (client RecordSetsClient) ListByDNSZoneNextResults(lastResults RecordSetListResult) (result RecordSetListResult, err error) {
|
||||
req, err := lastResults.RecordSetListResultPreparer()
|
||||
// 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", "ListByDNSZone", nil, "Failure preparing next results request")
|
||||
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", "ListByDNSZone", resp, "Failure sending next results request")
|
||||
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", "ListByDNSZone", resp, "Failure responding to next results request")
|
||||
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.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. zoneName is the name of
|
||||
// the DNS zone (without a terminating dot). recordType is the type of record
|
||||
// sets to enumerate. top is the maximum number of record sets to return. If
|
||||
// not specified, returns up to 100 record sets.
|
||||
func (client RecordSetsClient) ListByType(resourceGroupName string, zoneName string, recordType RecordType, top *int32) (result RecordSetListResult, err error) {
|
||||
req, err := client.ListByTypePreparer(resourceGroupName, zoneName, recordType, top)
|
||||
// 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
|
||||
@@ -384,12 +398,12 @@ func (client RecordSetsClient) ListByType(resourceGroupName string, zoneName str
|
||||
|
||||
resp, err := client.ListByTypeSender(req)
|
||||
if err != nil {
|
||||
result.Response = autorest.Response{Response: resp}
|
||||
result.rslr.Response = autorest.Response{Response: resp}
|
||||
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByType", resp, "Failure sending request")
|
||||
return
|
||||
}
|
||||
|
||||
result, err = client.ListByTypeResponder(resp)
|
||||
result.rslr, err = client.ListByTypeResponder(resp)
|
||||
if err != nil {
|
||||
err = autorest.NewErrorWithError(err, "dns.RecordSetsClient", "ListByType", resp, "Failure responding to request")
|
||||
}
|
||||
@@ -398,7 +412,7 @@ func (client RecordSetsClient) ListByType(resourceGroupName string, zoneName str
|
||||
}
|
||||
|
||||
// ListByTypePreparer prepares the ListByType request.
|
||||
func (client RecordSetsClient) ListByTypePreparer(resourceGroupName string, zoneName string, recordType RecordType, top *int32) (*http.Request, error) {
|
||||
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),
|
||||
@@ -406,26 +420,30 @@ func (client RecordSetsClient) ListByTypePreparer(resourceGroupName string, zone
|
||||
"zoneName": autorest.Encode("path", zoneName),
|
||||
}
|
||||
|
||||
const APIVersion = "2016-04-01"
|
||||
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{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// ListByTypeResponder handles the response to the ListByType request. The method always
|
||||
@@ -441,41 +459,44 @@ func (client RecordSetsClient) ListByTypeResponder(resp *http.Response) (result
|
||||
return
|
||||
}
|
||||
|
||||
// ListByTypeNextResults retrieves the next set of results, if any.
|
||||
func (client RecordSetsClient) ListByTypeNextResults(lastResults RecordSetListResult) (result RecordSetListResult, err error) {
|
||||
req, err := lastResults.RecordSetListResultPreparer()
|
||||
// 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", "ListByType", nil, "Failure preparing next results request")
|
||||
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", "ListByType", resp, "Failure sending next results request")
|
||||
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", "ListByType", resp, "Failure responding to next results request")
|
||||
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.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. zoneName is the name of
|
||||
// the DNS zone (without a terminating dot). relativeRecordSetName is the name
|
||||
// of the record set, relative to the name of the zone. recordType is the type
|
||||
// of DNS record in this record set. parameters is parameters supplied to the
|
||||
// Update operation. ifMatch is 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(resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string) (result RecordSet, err error) {
|
||||
req, err := client.UpdatePreparer(resourceGroupName, zoneName, relativeRecordSetName, recordType, parameters, ifMatch)
|
||||
// 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
|
||||
@@ -497,7 +518,7 @@ func (client RecordSetsClient) Update(resourceGroupName string, zoneName string,
|
||||
}
|
||||
|
||||
// UpdatePreparer prepares the Update request.
|
||||
func (client RecordSetsClient) UpdatePreparer(resourceGroupName string, zoneName string, relativeRecordSetName string, recordType RecordType, parameters RecordSet, ifMatch string) (*http.Request, error) {
|
||||
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,
|
||||
@@ -506,13 +527,13 @@ func (client RecordSetsClient) UpdatePreparer(resourceGroupName string, zoneName
|
||||
"zoneName": autorest.Encode("path", zoneName),
|
||||
}
|
||||
|
||||
const APIVersion = "2016-04-01"
|
||||
const APIVersion = "2017-09-01"
|
||||
queryParameters := map[string]interface{}{
|
||||
"api-version": APIVersion,
|
||||
}
|
||||
|
||||
preparer := autorest.CreatePreparer(
|
||||
autorest.AsJSON(),
|
||||
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),
|
||||
@@ -522,13 +543,14 @@ func (client RecordSetsClient) UpdatePreparer(resourceGroupName string, zoneName
|
||||
preparer = autorest.DecoratePreparer(preparer,
|
||||
autorest.WithHeader("If-Match", autorest.String(ifMatch)))
|
||||
}
|
||||
return preparer.Prepare(&http.Request{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// UpdateResponder handles the response to the Update request. The method always
|
||||
Generated
Vendored
Executable → Regular
+6
-5
@@ -1,5 +1,7 @@
|
||||
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");
|
||||
@@ -14,16 +16,15 @@ package dns
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0
|
||||
// Changes may cause incorrect behavior and will be lost if the code is
|
||||
// regenerated.
|
||||
// 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/v10.0.2-beta arm-dns/2016-04-01"
|
||||
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 "v10.0.2-beta"
|
||||
return version.Number
|
||||
}
|
||||
Generated
Vendored
Executable → Regular
+118
-123
@@ -14,11 +14,11 @@ package dns
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0
|
||||
// Changes may cause incorrect behavior and will be lost if the code is
|
||||
// regenerated.
|
||||
// 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"
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
|
||||
// ZonesClient is the the DNS Management Client.
|
||||
type ZonesClient struct {
|
||||
ManagementClient
|
||||
BaseClient
|
||||
}
|
||||
|
||||
// NewZonesClient creates an instance of the ZonesClient client.
|
||||
@@ -39,18 +39,17 @@ func NewZonesClientWithBaseURI(baseURI string, subscriptionID string) ZonesClien
|
||||
return ZonesClient{NewWithBaseURI(baseURI, subscriptionID)}
|
||||
}
|
||||
|
||||
// CreateOrUpdate creates or updates a DNS zone. Does not modify DNS records
|
||||
// within the zone.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. zoneName is the name of
|
||||
// the DNS zone (without a terminating dot). parameters is parameters supplied
|
||||
// to the CreateOrUpdate operation. ifMatch is 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 is 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(resourceGroupName string, zoneName string, parameters Zone, ifMatch string, ifNoneMatch string) (result Zone, err error) {
|
||||
req, err := client.CreateOrUpdatePreparer(resourceGroupName, zoneName, parameters, ifMatch, ifNoneMatch)
|
||||
// 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
|
||||
@@ -72,20 +71,20 @@ func (client ZonesClient) CreateOrUpdate(resourceGroupName string, zoneName stri
|
||||
}
|
||||
|
||||
// CreateOrUpdatePreparer prepares the CreateOrUpdate request.
|
||||
func (client ZonesClient) CreateOrUpdatePreparer(resourceGroupName string, zoneName string, parameters Zone, ifMatch string, ifNoneMatch string) (*http.Request, error) {
|
||||
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 = "2016-04-01"
|
||||
const APIVersion = "2017-09-01"
|
||||
queryParameters := map[string]interface{}{
|
||||
"api-version": APIVersion,
|
||||
}
|
||||
|
||||
preparer := autorest.CreatePreparer(
|
||||
autorest.AsJSON(),
|
||||
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),
|
||||
@@ -99,13 +98,14 @@ func (client ZonesClient) CreateOrUpdatePreparer(resourceGroupName string, zoneN
|
||||
preparer = autorest.DecoratePreparer(preparer,
|
||||
autorest.WithHeader("If-None-Match", autorest.String(ifNoneMatch)))
|
||||
}
|
||||
return preparer.Prepare(&http.Request{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always
|
||||
@@ -121,59 +121,38 @@ func (client ZonesClient) CreateOrUpdateResponder(resp *http.Response) (result Z
|
||||
return
|
||||
}
|
||||
|
||||
// Delete deletes a DNS zone. WARNING: All DNS records in the zone will also be
|
||||
// deleted. This operation cannot be undone. This method may poll for
|
||||
// completion. Polling can be canceled by passing the cancel channel argument.
|
||||
// The channel will be used to cancel polling and any outstanding HTTP
|
||||
// requests.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. zoneName is the name of
|
||||
// the DNS zone (without a terminating dot). ifMatch is 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(resourceGroupName string, zoneName string, ifMatch string, cancel <-chan struct{}) (<-chan ZoneDeleteResult, <-chan error) {
|
||||
resultChan := make(chan ZoneDeleteResult, 1)
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
var err error
|
||||
var result ZoneDeleteResult
|
||||
defer func() {
|
||||
resultChan <- result
|
||||
errChan <- err
|
||||
close(resultChan)
|
||||
close(errChan)
|
||||
}()
|
||||
req, err := client.DeletePreparer(resourceGroupName, zoneName, ifMatch, cancel)
|
||||
if err != nil {
|
||||
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "Delete", nil, "Failure preparing request")
|
||||
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
|
||||
}
|
||||
|
||||
resp, err := client.DeleteSender(req)
|
||||
if err != nil {
|
||||
result.Response = autorest.Response{Response: resp}
|
||||
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "Delete", resp, "Failure sending request")
|
||||
return
|
||||
}
|
||||
result, err = client.DeleteSender(req)
|
||||
if err != nil {
|
||||
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "Delete", result.Response(), "Failure sending request")
|
||||
return
|
||||
}
|
||||
|
||||
result, err = client.DeleteResponder(resp)
|
||||
if err != nil {
|
||||
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "Delete", resp, "Failure responding to request")
|
||||
}
|
||||
}()
|
||||
return resultChan, errChan
|
||||
return
|
||||
}
|
||||
|
||||
// DeletePreparer prepares the Delete request.
|
||||
func (client ZonesClient) DeletePreparer(resourceGroupName string, zoneName string, ifMatch string, cancel <-chan struct{}) (*http.Request, error) {
|
||||
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 = "2016-04-01"
|
||||
const APIVersion = "2017-09-01"
|
||||
queryParameters := map[string]interface{}{
|
||||
"api-version": APIVersion,
|
||||
}
|
||||
@@ -187,37 +166,44 @@ func (client ZonesClient) DeletePreparer(resourceGroupName string, zoneName stri
|
||||
preparer = autorest.DecoratePreparer(preparer,
|
||||
autorest.WithHeader("If-Match", autorest.String(ifMatch)))
|
||||
}
|
||||
return preparer.Prepare(&http.Request{Cancel: cancel})
|
||||
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) (*http.Response, error) {
|
||||
return autorest.SendWithSender(client,
|
||||
req,
|
||||
azure.DoPollForAsynchronous(client.PollingDelay))
|
||||
func (client ZonesClient) DeleteSender(req *http.Request) (future ZonesDeleteFuture, err error) {
|
||||
var resp *http.Response
|
||||
resp, err = autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = autorest.Respond(resp, azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
future.Future, err = azure.NewFutureFromResponse(resp)
|
||||
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 ZoneDeleteResult, err error) {
|
||||
func (client ZonesClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) {
|
||||
err = autorest.Respond(
|
||||
resp,
|
||||
client.ByInspecting(),
|
||||
azure.WithErrorUnlessStatusCode(http.StatusNoContent, http.StatusAccepted, http.StatusOK),
|
||||
autorest.ByUnmarshallingJSON(&result),
|
||||
azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent),
|
||||
autorest.ByClosing())
|
||||
result.Response = autorest.Response{Response: resp}
|
||||
result.Response = resp
|
||||
return
|
||||
}
|
||||
|
||||
// Get gets a DNS zone. Retrieves the zone properties, but not the record sets
|
||||
// within the zone.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. zoneName is the name of
|
||||
// the DNS zone (without a terminating dot).
|
||||
func (client ZonesClient) Get(resourceGroupName string, zoneName string) (result Zone, err error) {
|
||||
req, err := client.GetPreparer(resourceGroupName, zoneName)
|
||||
// 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
|
||||
@@ -239,14 +225,14 @@ func (client ZonesClient) Get(resourceGroupName string, zoneName string) (result
|
||||
}
|
||||
|
||||
// GetPreparer prepares the Get request.
|
||||
func (client ZonesClient) GetPreparer(resourceGroupName string, zoneName string) (*http.Request, error) {
|
||||
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 = "2016-04-01"
|
||||
const APIVersion = "2017-09-01"
|
||||
queryParameters := map[string]interface{}{
|
||||
"api-version": APIVersion,
|
||||
}
|
||||
@@ -256,13 +242,14 @@ func (client ZonesClient) GetPreparer(resourceGroupName string, zoneName string)
|
||||
autorest.WithBaseURL(client.BaseURI),
|
||||
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones/{zoneName}", pathParameters),
|
||||
autorest.WithQueryParameters(queryParameters))
|
||||
return preparer.Prepare(&http.Request{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// GetResponder handles the response to the Get request. The method always
|
||||
@@ -279,11 +266,11 @@ func (client ZonesClient) GetResponder(resp *http.Response) (result Zone, err er
|
||||
}
|
||||
|
||||
// List lists the DNS zones in all resource groups in a subscription.
|
||||
//
|
||||
// top is the maximum number of DNS zones to return. If not specified, returns
|
||||
// up to 100 zones.
|
||||
func (client ZonesClient) List(top *int32) (result ZoneListResult, err error) {
|
||||
req, err := client.ListPreparer(top)
|
||||
// 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
|
||||
@@ -291,12 +278,12 @@ func (client ZonesClient) List(top *int32) (result ZoneListResult, err error) {
|
||||
|
||||
resp, err := client.ListSender(req)
|
||||
if err != nil {
|
||||
result.Response = autorest.Response{Response: resp}
|
||||
result.zlr.Response = autorest.Response{Response: resp}
|
||||
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "List", resp, "Failure sending request")
|
||||
return
|
||||
}
|
||||
|
||||
result, err = client.ListResponder(resp)
|
||||
result.zlr, err = client.ListResponder(resp)
|
||||
if err != nil {
|
||||
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "List", resp, "Failure responding to request")
|
||||
}
|
||||
@@ -305,12 +292,12 @@ func (client ZonesClient) List(top *int32) (result ZoneListResult, err error) {
|
||||
}
|
||||
|
||||
// ListPreparer prepares the List request.
|
||||
func (client ZonesClient) ListPreparer(top *int32) (*http.Request, error) {
|
||||
func (client ZonesClient) ListPreparer(ctx context.Context, top *int32) (*http.Request, error) {
|
||||
pathParameters := map[string]interface{}{
|
||||
"subscriptionId": autorest.Encode("path", client.SubscriptionID),
|
||||
}
|
||||
|
||||
const APIVersion = "2016-04-01"
|
||||
const APIVersion = "2017-09-01"
|
||||
queryParameters := map[string]interface{}{
|
||||
"api-version": APIVersion,
|
||||
}
|
||||
@@ -323,13 +310,14 @@ func (client ZonesClient) ListPreparer(top *int32) (*http.Request, error) {
|
||||
autorest.WithBaseURL(client.BaseURI),
|
||||
autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.Network/dnszones", pathParameters),
|
||||
autorest.WithQueryParameters(queryParameters))
|
||||
return preparer.Prepare(&http.Request{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// ListResponder handles the response to the List request. The method always
|
||||
@@ -345,37 +333,40 @@ func (client ZonesClient) ListResponder(resp *http.Response) (result ZoneListRes
|
||||
return
|
||||
}
|
||||
|
||||
// ListNextResults retrieves the next set of results, if any.
|
||||
func (client ZonesClient) ListNextResults(lastResults ZoneListResult) (result ZoneListResult, err error) {
|
||||
req, err := lastResults.ZoneListResultPreparer()
|
||||
// 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", "List", nil, "Failure preparing next results request")
|
||||
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", "List", resp, "Failure sending next results request")
|
||||
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", "List", resp, "Failure responding to next results request")
|
||||
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.
|
||||
//
|
||||
// resourceGroupName is the name of the resource group. top is the maximum
|
||||
// number of record sets to return. If not specified, returns up to 100 record
|
||||
// sets.
|
||||
func (client ZonesClient) ListByResourceGroup(resourceGroupName string, top *int32) (result ZoneListResult, err error) {
|
||||
req, err := client.ListByResourceGroupPreparer(resourceGroupName, top)
|
||||
// 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
|
||||
@@ -383,12 +374,12 @@ func (client ZonesClient) ListByResourceGroup(resourceGroupName string, top *int
|
||||
|
||||
resp, err := client.ListByResourceGroupSender(req)
|
||||
if err != nil {
|
||||
result.Response = autorest.Response{Response: resp}
|
||||
result.zlr.Response = autorest.Response{Response: resp}
|
||||
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "ListByResourceGroup", resp, "Failure sending request")
|
||||
return
|
||||
}
|
||||
|
||||
result, err = client.ListByResourceGroupResponder(resp)
|
||||
result.zlr, err = client.ListByResourceGroupResponder(resp)
|
||||
if err != nil {
|
||||
err = autorest.NewErrorWithError(err, "dns.ZonesClient", "ListByResourceGroup", resp, "Failure responding to request")
|
||||
}
|
||||
@@ -397,13 +388,13 @@ func (client ZonesClient) ListByResourceGroup(resourceGroupName string, top *int
|
||||
}
|
||||
|
||||
// ListByResourceGroupPreparer prepares the ListByResourceGroup request.
|
||||
func (client ZonesClient) ListByResourceGroupPreparer(resourceGroupName string, top *int32) (*http.Request, error) {
|
||||
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 = "2016-04-01"
|
||||
const APIVersion = "2017-09-01"
|
||||
queryParameters := map[string]interface{}{
|
||||
"api-version": APIVersion,
|
||||
}
|
||||
@@ -416,13 +407,14 @@ func (client ZonesClient) ListByResourceGroupPreparer(resourceGroupName string,
|
||||
autorest.WithBaseURL(client.BaseURI),
|
||||
autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/dnsZones", pathParameters),
|
||||
autorest.WithQueryParameters(queryParameters))
|
||||
return preparer.Prepare(&http.Request{})
|
||||
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)
|
||||
return autorest.SendWithSender(client, req,
|
||||
azure.DoRetryWithRegistration(client.Client))
|
||||
}
|
||||
|
||||
// ListByResourceGroupResponder handles the response to the ListByResourceGroup request. The method always
|
||||
@@ -438,26 +430,29 @@ func (client ZonesClient) ListByResourceGroupResponder(resp *http.Response) (res
|
||||
return
|
||||
}
|
||||
|
||||
// ListByResourceGroupNextResults retrieves the next set of results, if any.
|
||||
func (client ZonesClient) ListByResourceGroupNextResults(lastResults ZoneListResult) (result ZoneListResult, err error) {
|
||||
req, err := lastResults.ZoneListResultPreparer()
|
||||
// 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", "ListByResourceGroup", nil, "Failure preparing next results request")
|
||||
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", "ListByResourceGroup", resp, "Failure sending next results request")
|
||||
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", "ListByResourceGroup", resp, "Failure responding to next results request")
|
||||
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
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"meta": {
|
||||
"after_scripts": [
|
||||
"dep ensure",
|
||||
"go generate ./profiles/...",
|
||||
"gofmt -w ./profiles/",
|
||||
"gofmt -w ./services/"
|
||||
],
|
||||
"autorest_options": {
|
||||
"use": "@microsoft.azure/autorest.go@~2.1.100",
|
||||
"go": "",
|
||||
"verbose": "",
|
||||
"sdkrel:go-sdk-folder": ".",
|
||||
"multiapi": "",
|
||||
"use-onever": ""
|
||||
},
|
||||
"repotag": "azure-sdk-for-go",
|
||||
"envs": {
|
||||
"sdkrel:GOPATH": "../../../.."
|
||||
},
|
||||
"advanced_options": {
|
||||
"clone_dir": "./src/github.com/Azure/azure-sdk-for-go"
|
||||
},
|
||||
"version": "0.2.0"
|
||||
}
|
||||
}
|
||||
+21
@@ -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 = "v17.3.0"
|
||||
+2
@@ -7,6 +7,8 @@
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
.DS_Store
|
||||
.idea/
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
|
||||
+17
-5
@@ -2,18 +2,30 @@ sudo: false
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.7
|
||||
- 1.8
|
||||
go:
|
||||
- master
|
||||
- 1.10.x
|
||||
- 1.9.x
|
||||
- 1.8.x
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: master
|
||||
|
||||
env:
|
||||
- DEP_VERSION="0.4.1"
|
||||
|
||||
before_install:
|
||||
- curl -L -o $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v$DEP_VERSION/dep-linux-amd64 && chmod +x $GOPATH/bin/dep
|
||||
|
||||
install:
|
||||
- go get -u github.com/golang/lint/golint
|
||||
- go get -u github.com/Masterminds/glide
|
||||
- go get -u github.com/stretchr/testify
|
||||
- go get -u github.com/GoASTScanner/gas
|
||||
- glide install
|
||||
- dep ensure
|
||||
|
||||
script:
|
||||
- grep -L -r --include *.go --exclude-dir vendor -P "Copyright (\d{4}|\(c\)) Microsoft" ./ | tee /dev/stderr | test -z "$(< /dev/stdin)"
|
||||
- test -z "$(gofmt -s -l -w ./autorest/. | tee /dev/stderr)"
|
||||
- test -z "$(golint ./autorest/... | tee /dev/stderr)"
|
||||
- go vet ./autorest/...
|
||||
|
||||
+343
-1
@@ -1,5 +1,347 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v10.10.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Most ServicePrincipalTokens can now be marshalled/unmarshall to/from JSON (ServicePrincipalCertificateSecret and ServicePrincipalMSISecret are not supported).
|
||||
- Added method ServicePrincipalToken.SetRefreshCallbacks().
|
||||
|
||||
## v10.9.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Refreshing a refresh token obtained from a web app authorization code now works.
|
||||
|
||||
## v10.9.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- The retry logic for MSI token requests now uses exponential backoff per the guidelines.
|
||||
- IsTemporaryNetworkError() will return true for errors that don't implement the net.Error interface.
|
||||
|
||||
## v10.9.0
|
||||
|
||||
### Deprecated Methods
|
||||
|
||||
| Old Method | New Method |
|
||||
|-------------:|:-----------:|
|
||||
|azure.NewFuture() | azure.NewFutureFromResponse()|
|
||||
|Future.WaitForCompletion() | Future.WaitForCompletionRef()|
|
||||
|
||||
### New Features
|
||||
|
||||
- Added azure.NewFutureFromResponse() for creating a Future from the initial response from an async operation.
|
||||
- Added Future.GetResult() for making the final GET call to retrieve the result from an async operation.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Some futures failed to return their results, this should now be fixed.
|
||||
|
||||
## v10.8.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Add nil-gaurd to token retry logic.
|
||||
|
||||
## v10.8.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Return a TokenRefreshError if the sender fails on the initial request.
|
||||
- Don't retry on non-temporary network errors.
|
||||
|
||||
## v10.8.0
|
||||
|
||||
- Added NewAuthorizerFromEnvironmentWithResource() helper function.
|
||||
|
||||
## v10.7.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added *WithContext() methods to ADAL token refresh operations.
|
||||
|
||||
## v10.6.2
|
||||
|
||||
- Fixed a bug on device authentication.
|
||||
|
||||
## v10.6.1
|
||||
|
||||
- Added retries to MSI token get request.
|
||||
|
||||
## v10.6.0
|
||||
|
||||
- Changed MSI token implementation. Now, the token endpoint is the IMDS endpoint.
|
||||
|
||||
## v10.5.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- `DeviceFlowConfig.Authorizer()` now prints the device code message when running `go test`. `-v` flag is required.
|
||||
|
||||
## v10.5.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added NewPollingRequestWithContext() for use with polling asynchronous operations.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Make retry logic use the request's context instead of the deprecated Cancel object.
|
||||
|
||||
## v10.4.0
|
||||
|
||||
### New Features
|
||||
- Added helper for parsing Azure Resource ID's.
|
||||
- Added deprecation message to utils.GetEnvVarOrExit()
|
||||
|
||||
## v10.3.0
|
||||
|
||||
### New Features
|
||||
- Added EnvironmentFromURL method to load an Environment from a given URL. This function is particularly useful in the private and hybrid Cloud model, where one may define their own endpoints
|
||||
- Added TokenAudience endpoint to Environment structure. This is useful in private and hybrid cloud models where TokenAudience endpoint can be different from ResourceManagerEndpoint
|
||||
|
||||
## v10.2.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added endpoints for batch management.
|
||||
|
||||
## v10.1.3
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- In Client.Do() invoke WithInspection() last so that it will inspect WithAuthorization().
|
||||
- Fixed authorization methods to invoke p.Prepare() first, aligning them with the other preparers.
|
||||
|
||||
## v10.1.2
|
||||
|
||||
- Corrected comment for auth.NewAuthorizerFromFile() function.
|
||||
|
||||
## v10.1.1
|
||||
|
||||
- Updated version number to match current release.
|
||||
|
||||
## v10.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Expose the polling URL for futures.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Add validation.NewErrorWithValidationError back to prevent breaking changes (it is deprecated).
|
||||
|
||||
## v10.0.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added target and innererror fields to ServiceError to comply with OData v4 spec.
|
||||
- The Done() method on futures will now return a ServiceError object when available (it used to return a partial value of such errors).
|
||||
- Added helper methods for obtaining authorizers.
|
||||
- Expose the polling URL for futures.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Switched from glide to dep for dependency management.
|
||||
- Fixed unmarshaling of ServiceError for JSON bodies that don't conform to the OData spec.
|
||||
- Fixed a race condition in token refresh.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- The ServiceError.Details field type has been changed to match the OData v4 spec.
|
||||
- Go v1.7 has been dropped from CI.
|
||||
- API parameter validation failures will now return a unique error type validation.Error.
|
||||
- The adal.Token type has been decomposed from adal.ServicePrincipalToken (this was necessary in order to fix the token refresh race).
|
||||
|
||||
## v9.10.0
|
||||
- Fix the Service Bus suffix in Azure public env
|
||||
- Add Service Bus Endpoint (AAD ResourceURI) for use in [Azure Service Bus RBAC Preview](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-role-based-access-control)
|
||||
|
||||
## v9.9.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added EventGridKeyAuthorizer for key authorization with event grid topics.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed race condition when auto-refreshing service principal tokens.
|
||||
|
||||
## v9.8.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Added http.StatusNoContent (204) to the list of expected status codes for long-running operations.
|
||||
- Updated runtime version info so it's current.
|
||||
|
||||
## v9.8.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added type azure.AsyncOpIncompleteError to be returned from a future's Result() method when the operation has not completed.
|
||||
|
||||
## v9.7.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use correct AAD and Graph endpoints for US Gov environment.
|
||||
|
||||
## v9.7.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added support for application/octet-stream MIME types.
|
||||
|
||||
## v9.6.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Ensure Authorization header is added to request when polling for registration status.
|
||||
|
||||
## v9.6.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added support for acquiring tokens via MSI with a user assigned identity.
|
||||
|
||||
## v9.5.3
|
||||
|
||||
### Bug Fixes
|
||||
- Don't remove encoding of existing URL Query parameters when calling autorest.WithQueryParameters.
|
||||
- Set correct Content Type when using autorest.WithFormData.
|
||||
|
||||
## v9.5.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Check for nil *http.Response before dereferencing it.
|
||||
|
||||
## v9.5.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Don't count http.StatusTooManyRequests (429) against the retry cap.
|
||||
- Use retry logic when SkipResourceProviderRegistration is set to true.
|
||||
|
||||
## v9.5.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added support for username + password, API key, authoriazation code and cognitive services authentication.
|
||||
- Added field SkipResourceProviderRegistration to clients to provide a way to skip auto-registration of RPs.
|
||||
- Added utility function AsStringSlice() to convert its parameters to a string slice.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- When checking for authentication failures look at the error type not the status code as it could vary.
|
||||
|
||||
## v9.4.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Validate parameters when creating credentials.
|
||||
- Don't retry requests if the returned status is a 401 (http.StatusUnauthorized) as it will never succeed.
|
||||
|
||||
## v9.4.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Update the AccessTokensPath() to read access tokens path through AZURE_ACCESS_TOKEN_FILE. If this
|
||||
environment variable is not set, it will fall back to use default path set by Azure CLI.
|
||||
- Use case-insensitive string comparison for polling states.
|
||||
|
||||
## v9.4.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added WaitForCompletion() to Future as a default polling implementation.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Method Future.Done() shouldn't update polling status for unexpected HTTP status codes.
|
||||
|
||||
## v9.3.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- DoRetryForStatusCodes will retry if sender.Do returns a non-nil error.
|
||||
|
||||
## v9.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added PollingMethod() to Future so callers know what kind of polling mechanism is used.
|
||||
- Added azure.ChangeToGet() which transforms an http.Request into a GET (to be used with LROs).
|
||||
|
||||
## v9.2.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Added support for custom Azure Stack endpoints.
|
||||
- Added type azure.Future used to track the status of long-running operations.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Preserve the original error in DoRetryWithRegistration when registration fails.
|
||||
|
||||
## v9.1.1
|
||||
|
||||
- Fixes a bug regarding the cookie jar on `autorest.Client.Sender`.
|
||||
|
||||
## v9.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
- In cases where there is a non-empty error from the service, attempt to unmarshal it instead of uniformly calling it an "Unknown" error.
|
||||
- Support for loading Azure CLI Authentication files.
|
||||
- Automatically register your subscription with the Azure Resource Provider if it hadn't been previously.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- RetriableRequest can now tolerate a ReadSeekable body being read but not reset.
|
||||
- Adding missing Apache Headers
|
||||
|
||||
## v9.0.0
|
||||
|
||||
> **IMPORTANT:** This release was intially labeled incorrectly as `v8.4.0`. From the time it was released, it should have been marked `v9.0.0` because it contains breaking changes to the MSI packages. We appologize for any inconvenience this causes.
|
||||
|
||||
Adding MSI Endpoint Support and CLI token rehydration.
|
||||
|
||||
## v8.3.1
|
||||
|
||||
Pick up bug fix in adal for MSI support.
|
||||
|
||||
## v8.3.0
|
||||
|
||||
Updates to Error string formats for clarity. Also, adding a copy of the http.Response to errors for an improved debugging experience.
|
||||
|
||||
## v8.2.0
|
||||
|
||||
### New Features
|
||||
|
||||
- Add support for bearer authentication callbacks
|
||||
- Support 429 response codes that include "Retry-After" header
|
||||
- Support validation constraint "Pattern" for map keys
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Make RetriableRequest work with multiple versions of Go
|
||||
|
||||
## v8.1.1
|
||||
Updates the RetriableRequest to take advantage of GetBody() added in Go 1.8.
|
||||
|
||||
## v8.1.0
|
||||
Adds RetriableRequest type for more efficient handling of retrying HTTP requests.
|
||||
|
||||
## v8.0.0
|
||||
|
||||
ADAL refactored into its own package.
|
||||
Support for UNIX time.
|
||||
|
||||
## v7.3.1
|
||||
- Version Testing now removed from production bits that are shipped with the library.
|
||||
|
||||
## v7.3.0
|
||||
- Exposing new `RespondDecorator`, `ByDiscardingBody`. This allows operations
|
||||
to acknowledge that they do not need either the entire or a trailing portion
|
||||
@@ -15,7 +357,7 @@
|
||||
- Added telemetry.
|
||||
|
||||
## v7.2.3
|
||||
- Fixing bug in calls to `DelayForBackoff` that caused doubling of delay
|
||||
- Fixing bug in calls to `DelayForBackoff` that caused doubling of delay
|
||||
duration.
|
||||
|
||||
## v7.2.2
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
DIR?=./autorest/
|
||||
|
||||
default: build
|
||||
|
||||
build: fmt
|
||||
go install $(DIR)
|
||||
|
||||
test:
|
||||
go test $(DIR) || exit 1
|
||||
|
||||
vet:
|
||||
@echo "go vet ."
|
||||
@go vet $(DIR)... ; if [ $$? -eq 1 ]; then \
|
||||
echo ""; \
|
||||
echo "Vet found suspicious constructs. Please check the reported constructs"; \
|
||||
echo "and fix them if necessary before submitting the code for review."; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
fmt:
|
||||
gofmt -w $(DIR)
|
||||
|
||||
.PHONY: build test vet fmt
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
revision = "dbeaa9332f19a944acb5736b4456cfcc02140e29"
|
||||
version = "v3.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/dimchansky/utfbom"
|
||||
packages = ["."]
|
||||
revision = "6c6132ff69f0f6c088739067407b5d32c52e1d0f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
revision = "b8bc1bf767474819792c23f32d8286a45736f1c6"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = ["assert","require"]
|
||||
revision = "b91bfb9ebec76498946beb6af7c0230c7cc7ba6c"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["pkcs12","pkcs12/internal/rc2"]
|
||||
revision = "5f55bce93ad2c89f411e009659bb1fd83da36e7b"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "ffeca2a12692c1c74addbf6ce6c2671e8d1a9fc5b6f5aaeee09da65eb48e8251"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# 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"
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
version = "3.1.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/dimchansky/utfbom"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "1.2.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
+23
-6
@@ -1,11 +1,22 @@
|
||||
# go-autorest
|
||||
|
||||
[](https://godoc.org/github.com/Azure/go-autorest/autorest) [](https://travis-ci.org/Azure/go-autorest) [](https://goreportcard.com/report/Azure/go-autorest)
|
||||
[](https://godoc.org/github.com/Azure/go-autorest/autorest)
|
||||
[](https://travis-ci.org/Azure/go-autorest)
|
||||
[](https://goreportcard.com/report/Azure/go-autorest)
|
||||
|
||||
## Usage
|
||||
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.
|
||||
Package go-autorest provides an HTTP request client for use with [Autorest](https://github.com/Azure/autorest.go)-generated API client packages.
|
||||
|
||||
An authentication client tested with Azure Active Directory (AAD) is also
|
||||
provided in this repo in the package
|
||||
`github.com/Azure/go-autorest/autorest/adal`. Despite its name, this package
|
||||
is maintained only as part of the Azure Go SDK and is not related to other
|
||||
"ADAL" libraries in [github.com/AzureAD](https://github.com/AzureAD).
|
||||
|
||||
## Overview
|
||||
|
||||
Package go-autorest implements an HTTP request pipeline suitable for use across
|
||||
multiple goroutines and provides the shared routines used by packages generated
|
||||
by [Autorest](https://github.com/Azure/autorest.go).
|
||||
|
||||
The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending,
|
||||
and Responding. A typical pattern is:
|
||||
@@ -129,4 +140,10 @@ go get github.com/Azure/go-autorest/autorest/to
|
||||
See LICENSE file.
|
||||
|
||||
-----
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of
|
||||
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
|
||||
see the [Code of Conduct
|
||||
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
|
||||
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
|
||||
questions or comments.
|
||||
|
||||
+46
-7
@@ -1,19 +1,24 @@
|
||||
# Azure Active Directory library for Go
|
||||
# Azure Active Directory authentication for Go
|
||||
|
||||
This project provides a stand alone Azure Active Directory library for Go. The code was extracted
|
||||
from [go-autorest](https://github.com/Azure/go-autorest/) project, which is used as a base for
|
||||
[azure-sdk-for-go](https://github.com/Azure/azure-sdk-for-go).
|
||||
This is a standalone package for authenticating with Azure Active
|
||||
Directory from other Go libraries and applications, in particular the [Azure SDK
|
||||
for Go](https://github.com/Azure/azure-sdk-for-go).
|
||||
|
||||
Note: Despite the package's name it is not related to other "ADAL" libraries
|
||||
maintained in the [github.com/AzureAD](https://github.com/AzureAD) org. Issues
|
||||
should be opened in [this repo's](https://github.com/Azure/go-autorest/issues)
|
||||
or [the SDK's](https://github.com/Azure/azure-sdk-for-go/issues) issue
|
||||
trackers.
|
||||
|
||||
## Installation
|
||||
## Install
|
||||
|
||||
```
|
||||
```bash
|
||||
go get -u github.com/Azure/go-autorest/autorest/adal
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) follow these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli).
|
||||
An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) by following these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli).
|
||||
|
||||
### Register an Azure AD Application with secret
|
||||
|
||||
@@ -218,6 +223,40 @@ if (err == nil) {
|
||||
}
|
||||
```
|
||||
|
||||
#### Username password authenticate
|
||||
|
||||
```Go
|
||||
spt, err := adal.NewServicePrincipalTokenFromUsernamePassword(
|
||||
oauthConfig,
|
||||
applicationID,
|
||||
username,
|
||||
password,
|
||||
resource,
|
||||
callbacks...)
|
||||
|
||||
if (err == nil) {
|
||||
token := spt.Token
|
||||
}
|
||||
```
|
||||
|
||||
#### Authorization code authenticate
|
||||
|
||||
``` Go
|
||||
spt, err := adal.NewServicePrincipalTokenFromAuthorizationCode(
|
||||
oauthConfig,
|
||||
applicationID,
|
||||
clientSecret,
|
||||
authorizationCode,
|
||||
redirectURI,
|
||||
resource,
|
||||
callbacks...)
|
||||
|
||||
err = spt.Refresh()
|
||||
if (err == nil) {
|
||||
token := spt.Token
|
||||
}
|
||||
```
|
||||
|
||||
### Command Line Tool
|
||||
|
||||
A command line tool is available in `cmd/adal.go` that can acquire a token for a given resource. It supports all flows mentioned above.
|
||||
|
||||
+34
-4
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
@@ -12,14 +26,30 @@ const (
|
||||
// OAuthConfig represents the endpoints needed
|
||||
// in OAuth operations
|
||||
type OAuthConfig struct {
|
||||
AuthorityEndpoint url.URL
|
||||
AuthorizeEndpoint url.URL
|
||||
TokenEndpoint url.URL
|
||||
DeviceCodeEndpoint url.URL
|
||||
AuthorityEndpoint url.URL `json:"authorityEndpoint"`
|
||||
AuthorizeEndpoint url.URL `json:"authorizeEndpoint"`
|
||||
TokenEndpoint url.URL `json:"tokenEndpoint"`
|
||||
DeviceCodeEndpoint url.URL `json:"deviceCodeEndpoint"`
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
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
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
)
|
||||
|
||||
+617
-104
@@ -1,26 +1,45 @@
|
||||
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"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"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
|
||||
tokenBaseDate = "1970-01-01T00:00:00Z"
|
||||
|
||||
// OAuthGrantTypeDeviceCode is the "grant_type" identifier used in device flow
|
||||
OAuthGrantTypeDeviceCode = "device_code"
|
||||
@@ -28,24 +47,33 @@ const (
|
||||
// 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"
|
||||
|
||||
// managedIdentitySettingsPath is the path to the MSI Extension settings file (to discover the endpoint)
|
||||
managedIdentitySettingsPath = "/var/lib/waagent/ManagedIdentity-Settings"
|
||||
// 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"
|
||||
)
|
||||
|
||||
var expirationBase time.Time
|
||||
|
||||
func init() {
|
||||
expirationBase, _ = time.Parse(time.RFC3339, tokenBaseDate)
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -53,6 +81,13 @@ type Refresher interface {
|
||||
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
|
||||
@@ -70,13 +105,21 @@ type Token struct {
|
||||
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
|
||||
}
|
||||
return expirationBase.Add(time.Duration(s) * time.Second).UTC()
|
||||
|
||||
expiration := date.NewUnixTimeFromSeconds(float64(s))
|
||||
|
||||
return time.Time(expiration).UTC()
|
||||
}
|
||||
|
||||
// IsExpired returns true if the Token is expired, false otherwise.
|
||||
@@ -95,6 +138,12 @@ func (t *Token) OAuthToken() string {
|
||||
return t.AccessToken
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -106,15 +155,19 @@ func (noSecret *ServicePrincipalNoSecret) SetAuthenticationValues(spt *ServicePr
|
||||
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
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (noSecret ServicePrincipalNoSecret) MarshalJSON() ([]byte, error) {
|
||||
type tokenType struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
return json.Marshal(tokenType{
|
||||
Type: "ServicePrincipalNoSecret",
|
||||
})
|
||||
}
|
||||
|
||||
// ServicePrincipalTokenSecret implements ServicePrincipalSecret for client_secret type authorization.
|
||||
type ServicePrincipalTokenSecret struct {
|
||||
ClientSecret string
|
||||
ClientSecret string `json:"value"`
|
||||
}
|
||||
|
||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||
@@ -124,23 +177,24 @@ func (tokenSecret *ServicePrincipalTokenSecret) SetAuthenticationValues(spt *Ser
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (tokenSecret ServicePrincipalTokenSecret) MarshalJSON() ([]byte, error) {
|
||||
type tokenType struct {
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
return json.Marshal(tokenType{
|
||||
Type: "ServicePrincipalTokenSecret",
|
||||
Value: tokenSecret.ClientSecret,
|
||||
})
|
||||
}
|
||||
|
||||
// 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 {
|
||||
}
|
||||
|
||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||
// MSI extension requires the authority field to be set to the real tenant authority endpoint
|
||||
func (msiSecret *ServicePrincipalMSISecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||
v.Set("authority", spt.oauthConfig.AuthorityEndpoint.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
// SignJwt returns the JWT signed with the certificate's private key.
|
||||
func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalToken) (string, error) {
|
||||
hasher := sha1.New()
|
||||
@@ -161,9 +215,9 @@ func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalTo
|
||||
token := jwt.New(jwt.SigningMethodRS256)
|
||||
token.Header["x5t"] = thumbprint
|
||||
token.Claims = jwt.MapClaims{
|
||||
"aud": spt.oauthConfig.TokenEndpoint.String(),
|
||||
"iss": spt.clientID,
|
||||
"sub": spt.clientID,
|
||||
"aud": spt.inner.OauthConfig.TokenEndpoint.String(),
|
||||
"iss": spt.inner.ClientID,
|
||||
"sub": spt.inner.ClientID,
|
||||
"jti": base64.URLEncoding.EncodeToString(jti),
|
||||
"nbf": time.Now().Unix(),
|
||||
"exp": time.Now().Add(time.Hour * 24).Unix(),
|
||||
@@ -186,30 +240,177 @@ func (secret *ServicePrincipalCertificateSecret) SetAuthenticationValues(spt *Se
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (secret ServicePrincipalCertificateSecret) MarshalJSON() ([]byte, error) {
|
||||
return nil, errors.New("marshalling ServicePrincipalCertificateSecret is not supported")
|
||||
}
|
||||
|
||||
// ServicePrincipalMSISecret implements ServicePrincipalSecret for machines running the MSI Extension.
|
||||
type ServicePrincipalMSISecret struct {
|
||||
}
|
||||
|
||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
|
||||
func (msiSecret *ServicePrincipalMSISecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (msiSecret ServicePrincipalMSISecret) MarshalJSON() ([]byte, error) {
|
||||
return nil, errors.New("marshalling ServicePrincipalMSISecret is not supported")
|
||||
}
|
||||
|
||||
// ServicePrincipalUsernamePasswordSecret implements ServicePrincipalSecret for username and password auth.
|
||||
type ServicePrincipalUsernamePasswordSecret struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (secret ServicePrincipalUsernamePasswordSecret) MarshalJSON() ([]byte, error) {
|
||||
type tokenType struct {
|
||||
Type string `json:"type"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
return json.Marshal(tokenType{
|
||||
Type: "ServicePrincipalUsernamePasswordSecret",
|
||||
Username: secret.Username,
|
||||
Password: secret.Password,
|
||||
})
|
||||
}
|
||||
|
||||
// ServicePrincipalAuthorizationCodeSecret implements ServicePrincipalSecret for authorization code auth.
|
||||
type ServicePrincipalAuthorizationCodeSecret struct {
|
||||
ClientSecret string `json:"value"`
|
||||
AuthorizationCode string `json:"authCode"`
|
||||
RedirectURI string `json:"redirect"`
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (secret ServicePrincipalAuthorizationCodeSecret) MarshalJSON() ([]byte, error) {
|
||||
type tokenType struct {
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
AuthCode string `json:"authCode"`
|
||||
Redirect string `json:"redirect"`
|
||||
}
|
||||
return json.Marshal(tokenType{
|
||||
Type: "ServicePrincipalAuthorizationCodeSecret",
|
||||
Value: secret.ClientSecret,
|
||||
AuthCode: secret.AuthorizationCode,
|
||||
Redirect: secret.RedirectURI,
|
||||
})
|
||||
}
|
||||
|
||||
// ServicePrincipalToken encapsulates a Token created for a Service Principal.
|
||||
type ServicePrincipalToken struct {
|
||||
Token
|
||||
|
||||
secret ServicePrincipalSecret
|
||||
oauthConfig OAuthConfig
|
||||
clientID string
|
||||
resource string
|
||||
autoRefresh bool
|
||||
refreshWithin time.Duration
|
||||
sender Sender
|
||||
|
||||
inner servicePrincipalToken
|
||||
refreshLock *sync.RWMutex
|
||||
sender Sender
|
||||
refreshCallbacks []TokenRefreshCallback
|
||||
}
|
||||
|
||||
// SetRefreshCallbacks replaces any existing refresh callbacks with the specified callbacks.
|
||||
func (spt *ServicePrincipalToken) SetRefreshCallbacks(callbacks []TokenRefreshCallback) {
|
||||
spt.refreshCallbacks = callbacks
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (spt ServicePrincipalToken) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(spt.inner)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (spt *ServicePrincipalToken) UnmarshalJSON(data []byte) error {
|
||||
// need to determine the token type
|
||||
raw := map[string]interface{}{}
|
||||
err := json.Unmarshal(data, &raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret := raw["secret"].(map[string]interface{})
|
||||
switch secret["type"] {
|
||||
case "ServicePrincipalNoSecret":
|
||||
spt.inner.Secret = &ServicePrincipalNoSecret{}
|
||||
case "ServicePrincipalTokenSecret":
|
||||
spt.inner.Secret = &ServicePrincipalTokenSecret{}
|
||||
case "ServicePrincipalCertificateSecret":
|
||||
return errors.New("unmarshalling ServicePrincipalCertificateSecret is not supported")
|
||||
case "ServicePrincipalMSISecret":
|
||||
return errors.New("unmarshalling ServicePrincipalMSISecret is not supported")
|
||||
case "ServicePrincipalUsernamePasswordSecret":
|
||||
spt.inner.Secret = &ServicePrincipalUsernamePasswordSecret{}
|
||||
case "ServicePrincipalAuthorizationCodeSecret":
|
||||
spt.inner.Secret = &ServicePrincipalAuthorizationCodeSecret{}
|
||||
default:
|
||||
return fmt.Errorf("unrecognized token type '%s'", secret["type"])
|
||||
}
|
||||
err = json.Unmarshal(data, &spt.inner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
spt.refreshLock = &sync.RWMutex{}
|
||||
spt.sender = &http.Client{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// internal type used for marshalling/unmarshalling
|
||||
type servicePrincipalToken struct {
|
||||
Token Token `json:"token"`
|
||||
Secret ServicePrincipalSecret `json:"secret"`
|
||||
OauthConfig OAuthConfig `json:"oauth"`
|
||||
ClientID string `json:"clientID"`
|
||||
Resource string `json:"resource"`
|
||||
AutoRefresh bool `json:"autoRefresh"`
|
||||
RefreshWithin time.Duration `json:"refreshWithin"`
|
||||
}
|
||||
|
||||
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,
|
||||
refreshWithin: defaultRefresh,
|
||||
inner: servicePrincipalToken{
|
||||
OauthConfig: oauthConfig,
|
||||
Secret: secret,
|
||||
ClientID: id,
|
||||
Resource: resource,
|
||||
AutoRefresh: true,
|
||||
RefreshWithin: defaultRefresh,
|
||||
},
|
||||
refreshLock: &sync.RWMutex{},
|
||||
sender: &http.Client{},
|
||||
refreshCallbacks: callbacks,
|
||||
}
|
||||
@@ -218,6 +419,18 @@ func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, reso
|
||||
|
||||
// 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,
|
||||
@@ -228,7 +441,7 @@ func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID s
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spt.Token = token
|
||||
spt.inner.Token = token
|
||||
|
||||
return spt, nil
|
||||
}
|
||||
@@ -236,6 +449,18 @@ func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID s
|
||||
// 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,
|
||||
@@ -247,8 +472,23 @@ func NewServicePrincipalToken(oauthConfig OAuthConfig, clientID string, secret s
|
||||
)
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenFromCertificate create a ServicePrincipalToken from the supplied pkcs12 bytes.
|
||||
// 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,
|
||||
@@ -261,57 +501,171 @@ func NewServicePrincipalTokenFromCertificate(oauthConfig OAuthConfig, clientID s
|
||||
)
|
||||
}
|
||||
|
||||
// NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension.
|
||||
func NewServicePrincipalTokenFromMSI(oauthConfig OAuthConfig, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
return newServicePrincipalTokenFromMSI(oauthConfig, resource, managedIdentitySettingsPath, 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...,
|
||||
)
|
||||
}
|
||||
|
||||
func newServicePrincipalTokenFromMSI(oauthConfig OAuthConfig, resource, settingsPath string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
|
||||
// Read MSI settings
|
||||
bytes, err := ioutil.ReadFile(settingsPath)
|
||||
if err != nil {
|
||||
// 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
|
||||
}
|
||||
msiSettings := struct {
|
||||
URL string `json:"url"`
|
||||
}{}
|
||||
err = json.Unmarshal(bytes, &msiSettings)
|
||||
if err != nil {
|
||||
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
|
||||
// We leave the authority as-is so MSI can POST it with the token request
|
||||
msiEndpointURL, err := url.Parse(msiSettings.URL)
|
||||
msiEndpointURL, err := url.Parse(msiEndpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msiTokenEndpointURL, err := msiEndpointURL.Parse("/oauth2/token")
|
||||
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)
|
||||
}
|
||||
|
||||
oauthConfig.TokenEndpoint = *msiTokenEndpointURL
|
||||
msiEndpointURL.RawQuery = v.Encode()
|
||||
|
||||
spt := &ServicePrincipalToken{
|
||||
oauthConfig: oauthConfig,
|
||||
secret: &ServicePrincipalMSISecret{},
|
||||
resource: resource,
|
||||
autoRefresh: true,
|
||||
refreshWithin: defaultRefresh,
|
||||
inner: servicePrincipalToken{
|
||||
OauthConfig: OAuthConfig{
|
||||
TokenEndpoint: *msiEndpointURL,
|
||||
},
|
||||
Secret: &ServicePrincipalMSISecret{},
|
||||
Resource: resource,
|
||||
AutoRefresh: true,
|
||||
RefreshWithin: defaultRefresh,
|
||||
},
|
||||
refreshLock: &sync.RWMutex{},
|
||||
sender: &http.Client{},
|
||||
refreshCallbacks: callbacks,
|
||||
}
|
||||
|
||||
if userAssignedID != nil {
|
||||
spt.inner.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.
|
||||
// RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use.
|
||||
func (spt *ServicePrincipalToken) EnsureFresh() error {
|
||||
if spt.autoRefresh && spt.WillExpireIn(spt.refreshWithin) {
|
||||
return spt.Refresh()
|
||||
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.inner.AutoRefresh && spt.inner.Token.WillExpireIn(spt.inner.RefreshWithin) {
|
||||
// take the write lock then check to see if the token was already refreshed
|
||||
spt.refreshLock.Lock()
|
||||
defer spt.refreshLock.Unlock()
|
||||
if spt.inner.Token.WillExpireIn(spt.inner.RefreshWithin) {
|
||||
return spt.refreshInternal(ctx, spt.inner.Resource)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -320,7 +674,7 @@ func (spt *ServicePrincipalToken) EnsureFresh() error {
|
||||
func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error {
|
||||
if spt.refreshCallbacks != nil {
|
||||
for _, callback := range spt.refreshCallbacks {
|
||||
err := callback(spt.Token)
|
||||
err := callback(spt.inner.Token)
|
||||
if err != nil {
|
||||
return fmt.Errorf("adal: TokenRefreshCallback handler failed. Error = '%v'", err)
|
||||
}
|
||||
@@ -330,50 +684,118 @@ func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error {
|
||||
}
|
||||
|
||||
// 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.refreshInternal(spt.resource)
|
||||
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.inner.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.refreshInternal(resource)
|
||||
return spt.RefreshExchangeWithContext(context.Background(), resource)
|
||||
}
|
||||
|
||||
func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
|
||||
v := url.Values{}
|
||||
v.Set("client_id", spt.clientID)
|
||||
v.Set("resource", 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)
|
||||
}
|
||||
|
||||
if spt.RefreshToken != "" {
|
||||
v.Set("grant_type", OAuthGrantTypeRefreshToken)
|
||||
v.Set("refresh_token", spt.RefreshToken)
|
||||
} else {
|
||||
v.Set("grant_type", OAuthGrantTypeClientCredentials)
|
||||
err := spt.secret.SetAuthenticationValues(spt, &v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (spt *ServicePrincipalToken) getGrantType() string {
|
||||
switch spt.inner.Secret.(type) {
|
||||
case *ServicePrincipalUsernamePasswordSecret:
|
||||
return OAuthGrantTypeUserPass
|
||||
case *ServicePrincipalAuthorizationCodeSecret:
|
||||
return OAuthGrantTypeAuthorizationCode
|
||||
default:
|
||||
return OAuthGrantTypeClientCredentials
|
||||
}
|
||||
}
|
||||
|
||||
s := v.Encode()
|
||||
body := ioutil.NopCloser(strings.NewReader(s))
|
||||
req, err := http.NewRequest(http.MethodPost, spt.oauthConfig.TokenEndpoint.String(), body)
|
||||
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.inner.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.inner.OauthConfig.TokenEndpoint) {
|
||||
v := url.Values{}
|
||||
v.Set("client_id", spt.inner.ClientID)
|
||||
v.Set("resource", resource)
|
||||
|
||||
req.ContentLength = int64(len(s))
|
||||
req.Header.Set(contentType, mimeTypeFormPost)
|
||||
resp, err := spt.sender.Do(req)
|
||||
if spt.inner.Token.RefreshToken != "" {
|
||||
v.Set("grant_type", OAuthGrantTypeRefreshToken)
|
||||
v.Set("refresh_token", spt.inner.Token.RefreshToken)
|
||||
// web apps must specify client_secret when refreshing tokens
|
||||
// see https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code#refreshing-the-access-tokens
|
||||
if spt.getGrantType() == OAuthGrantTypeAuthorizationCode {
|
||||
err := spt.inner.Secret.SetAuthenticationValues(spt, &v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v.Set("grant_type", spt.getGrantType())
|
||||
err := spt.inner.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.inner.Secret.(*ServicePrincipalMSISecret); ok {
|
||||
req.Method = http.MethodGet
|
||||
req.Header.Set(metadataHeader, "true")
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
if isIMDS(spt.inner.OauthConfig.TokenEndpoint) {
|
||||
resp, err = retry(spt.sender, req)
|
||||
} else {
|
||||
resp, err = spt.sender.Do(req)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("adal: Failed to execute the refresh request. Error = '%v'", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("adal: Refresh request failed. Status Code = '%d'", resp.StatusCode)
|
||||
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)
|
||||
}
|
||||
@@ -386,23 +808,114 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
|
||||
return fmt.Errorf("adal: Failed to unmarshal the service principal token during refresh. Error = '%v' JSON = '%s'", err, string(rb))
|
||||
}
|
||||
|
||||
spt.Token = token
|
||||
spt.inner.Token = token
|
||||
|
||||
return spt.InvokeRefreshCallbacks(token)
|
||||
}
|
||||
|
||||
func retry(sender Sender, req *http.Request) (resp *http.Response, err error) {
|
||||
// copied from client.go due to circular dependency
|
||||
retries := []int{
|
||||
http.StatusRequestTimeout, // 408
|
||||
http.StatusTooManyRequests, // 429
|
||||
http.StatusInternalServerError, // 500
|
||||
http.StatusBadGateway, // 502
|
||||
http.StatusServiceUnavailable, // 503
|
||||
http.StatusGatewayTimeout, // 504
|
||||
}
|
||||
// extra retry status codes specific to IMDS
|
||||
retries = append(retries,
|
||||
http.StatusNotFound,
|
||||
http.StatusGone,
|
||||
// all remaining 5xx
|
||||
http.StatusNotImplemented,
|
||||
http.StatusHTTPVersionNotSupported,
|
||||
http.StatusVariantAlsoNegotiates,
|
||||
http.StatusInsufficientStorage,
|
||||
http.StatusLoopDetected,
|
||||
http.StatusNotExtended,
|
||||
http.StatusNetworkAuthenticationRequired)
|
||||
|
||||
// see https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/how-to-use-vm-token#retry-guidance
|
||||
|
||||
const maxAttempts int = 5
|
||||
const maxDelay time.Duration = 60 * time.Second
|
||||
|
||||
attempt := 0
|
||||
delay := time.Duration(0)
|
||||
|
||||
for attempt < maxAttempts {
|
||||
resp, err = sender.Do(req)
|
||||
// retry on temporary network errors, e.g. transient network failures.
|
||||
if (err != nil && !isTemporaryNetworkError(err)) || resp.StatusCode == http.StatusOK || !containsInt(retries, resp.StatusCode) {
|
||||
return
|
||||
}
|
||||
|
||||
// perform exponential backoff with a cap.
|
||||
// must increment attempt before calculating delay.
|
||||
attempt++
|
||||
// the base value of 2 is the "delta backoff" as specified in the guidance doc
|
||||
delay += (time.Duration(math.Pow(2, float64(attempt))) * time.Second)
|
||||
if delay > maxDelay {
|
||||
delay = maxDelay
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(delay):
|
||||
// intentionally left blank
|
||||
case <-req.Context().Done():
|
||||
err = req.Context().Err()
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// returns true if the specified error is a temporary network error or false if it's not.
|
||||
// if the error doesn't implement the net.Error interface the return value is true.
|
||||
func isTemporaryNetworkError(err error) bool {
|
||||
if netErr, ok := err.(net.Error); !ok || (ok && netErr.Temporary()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// returns true if slice ints contains the value n
|
||||
func containsInt(ints []int, n int) bool {
|
||||
for _, i := range ints {
|
||||
if i == n {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetAutoRefresh enables or disables automatic refreshing of stale tokens.
|
||||
func (spt *ServicePrincipalToken) SetAutoRefresh(autoRefresh bool) {
|
||||
spt.autoRefresh = autoRefresh
|
||||
spt.inner.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
|
||||
spt.inner.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.inner.Token.OAuthToken()
|
||||
}
|
||||
|
||||
// Token returns a copy of the current token.
|
||||
func (spt *ServicePrincipalToken) Token() Token {
|
||||
spt.refreshLock.RLock()
|
||||
defer spt.refreshLock.RUnlock()
|
||||
return spt.inner.Token
|
||||
}
|
||||
|
||||
+211
-9
@@ -1,12 +1,37 @@
|
||||
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.
|
||||
@@ -22,6 +47,53 @@ 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
|
||||
@@ -32,10 +104,6 @@ func NewBearerAuthorizer(tp adal.OAuthTokenProvider) *BearerAuthorizer {
|
||||
return &BearerAuthorizer{tokenProvider: tp}
|
||||
}
|
||||
|
||||
func (ba *BearerAuthorizer) withBearerAuthorization() PrepareDecorator {
|
||||
return WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", ba.tokenProvider.OAuthToken()))
|
||||
}
|
||||
|
||||
// WithAuthorization returns a PrepareDecorator that adds an HTTP Authorization header whose
|
||||
// value is "Bearer " followed by the token.
|
||||
//
|
||||
@@ -43,15 +111,149 @@ func (ba *BearerAuthorizer) withBearerAuthorization() PrepareDecorator {
|
||||
func (ba *BearerAuthorizer) WithAuthorization() PrepareDecorator {
|
||||
return func(p Preparer) Preparer {
|
||||
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
|
||||
refresher, ok := ba.tokenProvider.(adal.Refresher)
|
||||
if ok {
|
||||
err := refresher.EnsureFresh()
|
||||
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 {
|
||||
return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", 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 (ba.withBearerAuthorization()(p)).Prepare(r)
|
||||
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()
|
||||
}
|
||||
|
||||
+35
@@ -57,7 +57,22 @@ 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"
|
||||
)
|
||||
@@ -73,6 +88,9 @@ const (
|
||||
// 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)
|
||||
}
|
||||
|
||||
@@ -113,3 +131,20 @@ func NewPollingRequest(resp *http.Response, cancel <-chan struct{}) (*http.Reque
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
+849
-241
File diff suppressed because it is too large
Load Diff
+137
-16
@@ -1,16 +1,29 @@
|
||||
/*
|
||||
Package azure provides Azure-specific implementations used with AutoRest.
|
||||
|
||||
See the included examples for more detail.
|
||||
*/
|
||||
// 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"
|
||||
)
|
||||
@@ -29,21 +42,88 @@ const (
|
||||
)
|
||||
|
||||
// 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"`
|
||||
Details *[]interface{} `json:"details"`
|
||||
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 {
|
||||
if se.Details != nil {
|
||||
d, err := json.Marshal(*(se.Details))
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Code=%q Message=%q Details=%v", se.Code, se.Message, *se.Details)
|
||||
}
|
||||
return fmt.Sprintf("Code=%q Message=%q Details=%v", se.Code, se.Message, string(d))
|
||||
result := fmt.Sprintf("Code=%q Message=%q", se.Code, se.Message)
|
||||
|
||||
if se.Target != nil {
|
||||
result += fmt.Sprintf(" Target=%q", *se.Target)
|
||||
}
|
||||
return fmt.Sprintf("Code=%q Message=%q", se.Code, se.Message)
|
||||
|
||||
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.
|
||||
@@ -69,6 +149,41 @@ func IsAzureError(e error) bool {
|
||||
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
|
||||
@@ -165,7 +280,13 @@ func WithErrorUnlessStatusCode(codes ...int) autorest.RespondDecorator {
|
||||
if decodeErr != nil {
|
||||
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b.String(), decodeErr)
|
||||
} else if e.ServiceError == nil {
|
||||
e.ServiceError = &ServiceError{Code: "Unknown", Message: "Unknown service error"}
|
||||
// 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)
|
||||
|
||||
+66
-5
@@ -1,10 +1,31 @@
|
||||
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,
|
||||
@@ -23,6 +44,8 @@ type Environment struct {
|
||||
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"`
|
||||
@@ -31,6 +54,7 @@ type Environment struct {
|
||||
ServiceManagementVMDNSSuffix string `json:"serviceManagementVMDNSSuffix"`
|
||||
ResourceManagerVMDNSSuffix string `json:"resourceManagerVMDNSSuffix"`
|
||||
ContainerRegistryDNSSuffix string `json:"containerRegistryDNSSuffix"`
|
||||
TokenAudience string `json:"tokenAudience"`
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -45,14 +69,17 @@ var (
|
||||
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.azure.com",
|
||||
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
|
||||
@@ -62,10 +89,12 @@ var (
|
||||
PublishSettingsURL: "https://manage.windowsazure.us/publishsettings/index",
|
||||
ServiceManagementEndpoint: "https://management.core.usgovcloudapi.net/",
|
||||
ResourceManagerEndpoint: "https://management.usgovcloudapi.net/",
|
||||
ActiveDirectoryEndpoint: "https://login.microsoftonline.com/",
|
||||
ActiveDirectoryEndpoint: "https://login.microsoftonline.us/",
|
||||
GalleryEndpoint: "https://gallery.usgovcloudapi.net/",
|
||||
KeyVaultEndpoint: "https://vault.usgovcloudapi.net/",
|
||||
GraphEndpoint: "https://graph.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",
|
||||
@@ -74,6 +103,7 @@ var (
|
||||
ServiceManagementVMDNSSuffix: "usgovcloudapp.net",
|
||||
ResourceManagerVMDNSSuffix: "cloudapp.windowsazure.us",
|
||||
ContainerRegistryDNSSuffix: "azurecr.io",
|
||||
TokenAudience: "https://management.usgovcloudapi.net/",
|
||||
}
|
||||
|
||||
// ChinaCloud is the cloud environment operated in China
|
||||
@@ -87,14 +117,17 @@ var (
|
||||
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.net",
|
||||
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
|
||||
@@ -108,6 +141,8 @@ var (
|
||||
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",
|
||||
@@ -116,15 +151,41 @@ var (
|
||||
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
|
||||
// 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
@@ -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
@@ -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 ""
|
||||
}
|
||||
+38
-9
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
@@ -21,6 +35,9 @@ const (
|
||||
|
||||
// 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 (
|
||||
@@ -33,8 +50,10 @@ var (
|
||||
Version(),
|
||||
)
|
||||
|
||||
statusCodesForRetry = []int{
|
||||
// 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
|
||||
@@ -147,6 +166,9 @@ type Client struct {
|
||||
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
|
||||
@@ -156,9 +178,10 @@ func NewClientWithUserAgent(ua string) Client {
|
||||
PollingDelay: DefaultPollingDelay,
|
||||
PollingDuration: DefaultPollingDuration,
|
||||
RetryAttempts: DefaultRetryAttempts,
|
||||
RetryDuration: 30 * time.Second,
|
||||
RetryDuration: DefaultRetryDuration,
|
||||
UserAgent: defaultUserAgent,
|
||||
}
|
||||
c.Sender = c.sender()
|
||||
c.AddToUserAgent(ua)
|
||||
return c
|
||||
}
|
||||
@@ -180,16 +203,22 @@ func (c Client) Do(r *http.Request) (*http.Response, error) {
|
||||
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.WithInspection(),
|
||||
c.WithAuthorization())
|
||||
c.WithAuthorization(),
|
||||
c.WithInspection())
|
||||
if err != nil {
|
||||
return nil, NewErrorWithError(err, "autorest/Client", "Do", nil, "Preparing request failed")
|
||||
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,
|
||||
DoRetryForStatusCodes(c.RetryAttempts, c.RetryDuration, statusCodesForRetry...))
|
||||
Respond(resp,
|
||||
c.ByInspecting())
|
||||
|
||||
resp, err := SendWithSender(c.sender(), r)
|
||||
Respond(resp, c.ByInspecting())
|
||||
return resp, err
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -5,6 +5,20 @@ 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"
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
|
||||
+18
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
@@ -31,6 +45,9 @@ type DetailedError struct {
|
||||
|
||||
// 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
|
||||
@@ -67,6 +84,7 @@ func NewErrorWithError(original error, packageType string, method string, resp *
|
||||
Method: method,
|
||||
StatusCode: statusCode,
|
||||
Message: fmt.Sprintf(message, args...),
|
||||
Response: resp,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+56
-4
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
@@ -13,8 +27,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
mimeTypeJSON = "application/json"
|
||||
mimeTypeFormPost = "application/x-www-form-urlencoded"
|
||||
mimeTypeJSON = "application/json"
|
||||
mimeTypeOctetStream = "application/octet-stream"
|
||||
mimeTypeFormPost = "application/x-www-form-urlencoded"
|
||||
|
||||
headerAuthorization = "Authorization"
|
||||
headerContentType = "Content-Type"
|
||||
@@ -98,6 +113,28 @@ func WithHeader(header string, value string) PrepareDecorator {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -128,6 +165,11 @@ 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 {
|
||||
@@ -201,6 +243,11 @@ func WithFormData(v url.Values) PrepareDecorator {
|
||||
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))
|
||||
}
|
||||
@@ -416,11 +463,16 @@ func WithQueryParameters(queryParameters map[string]interface{}) PrepareDecorato
|
||||
if r.URL == nil {
|
||||
return r, NewError("autorest", "WithQueryParameters", "Invoked with a nil URL")
|
||||
}
|
||||
|
||||
v := r.URL.Query()
|
||||
for key, value := range parameters {
|
||||
v.Add(key, value)
|
||||
d, err := url.QueryUnescape(value)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
v.Add(key, d)
|
||||
}
|
||||
r.URL.RawQuery = createQuery(v)
|
||||
r.URL.RawQuery = v.Encode()
|
||||
}
|
||||
return r, err
|
||||
})
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
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"
|
||||
|
||||
+52
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
+75
-20
@@ -1,12 +1,25 @@
|
||||
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/ioutil"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -73,7 +86,7 @@ func SendWithSender(s Sender, r *http.Request, decorators ...SendDecorator) (*ht
|
||||
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.Cancel) {
|
||||
if !DelayForBackoff(d, 0, r.Context().Done()) {
|
||||
return nil, fmt.Errorf("autorest: AfterDelay canceled before full delay")
|
||||
}
|
||||
return s.Do(r)
|
||||
@@ -152,7 +165,7 @@ func DoPollForStatusCodes(duration time.Duration, delay time.Duration, codes ...
|
||||
resp, err = s.Do(r)
|
||||
|
||||
if err == nil && ResponseHasStatusCode(resp, codes...) {
|
||||
r, err = NewPollingRequest(resp, r.Cancel)
|
||||
r, err = NewPollingRequestWithContext(r.Context(), resp)
|
||||
|
||||
for err == nil && ResponseHasStatusCode(resp, codes...) {
|
||||
Respond(resp,
|
||||
@@ -175,12 +188,19 @@ func DoPollForStatusCodes(duration time.Duration, delay time.Duration, codes ...
|
||||
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++ {
|
||||
resp, err = s.Do(r)
|
||||
err = rr.Prepare()
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp, err = s.Do(rr.Request())
|
||||
if err == nil {
|
||||
return resp, err
|
||||
}
|
||||
DelayForBackoff(backoff, attempt, r.Cancel)
|
||||
if !DelayForBackoff(backoff, attempt, r.Context().Done()) {
|
||||
return nil, r.Context().Err()
|
||||
}
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
@@ -194,29 +214,57 @@ func DoRetryForAttempts(attempts int, backoff time.Duration) SendDecorator {
|
||||
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) {
|
||||
b := []byte{}
|
||||
if r.Body != nil {
|
||||
b, err = ioutil.ReadAll(r.Body)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// Increment to add the first call (attempts denotes number of retries)
|
||||
attempts++
|
||||
for attempt := 0; attempt < attempts; attempt++ {
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(b))
|
||||
resp, err = s.Do(r)
|
||||
if err != nil || !ResponseHasStatusCode(resp, codes...) {
|
||||
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
|
||||
}
|
||||
DelayForBackoff(backoff, attempt, r.Cancel)
|
||||
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
|
||||
@@ -224,13 +272,20 @@ func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) Se
|
||||
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++ {
|
||||
resp, err = s.Do(r)
|
||||
err = rr.Prepare()
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp, err = s.Do(rr.Request())
|
||||
if err == nil {
|
||||
return resp, err
|
||||
}
|
||||
DelayForBackoff(backoff, attempt, r.Cancel)
|
||||
if !DelayForBackoff(backoff, attempt, r.Context().Done()) {
|
||||
return nil, r.Context().Err()
|
||||
}
|
||||
}
|
||||
return resp, err
|
||||
})
|
||||
|
||||
+14
@@ -3,6 +3,20 @@ Package to provides helpers to ease working with pointer values of marshalled st
|
||||
*/
|
||||
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 {
|
||||
|
||||
+79
-29
@@ -1,15 +1,32 @@
|
||||
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"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
)
|
||||
|
||||
// EncodedAs is a series of constants specifying various data encodings
|
||||
@@ -123,13 +140,38 @@ func MapToValues(m map[string]interface{}) url.Values {
|
||||
return v
|
||||
}
|
||||
|
||||
// String method converts interface v to string. If interface is a list, it
|
||||
// joins list elements using separator.
|
||||
func String(v interface{}, sep ...string) string {
|
||||
if len(sep) > 0 {
|
||||
return ensureValueString(strings.Join(v.([]string), sep[0]))
|
||||
// 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.")
|
||||
}
|
||||
return ensureValueString(v)
|
||||
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.
|
||||
@@ -153,26 +195,34 @@ func queryEscape(s string) string {
|
||||
return url.QueryEscape(s)
|
||||
}
|
||||
|
||||
// This method is same as Encode() method of "net/url" go package,
|
||||
// except it does not encode the query parameters because they
|
||||
// already come encoded. It formats values map in query format (bar=foo&a=b).
|
||||
func createQuery(v url.Values) string {
|
||||
var buf bytes.Buffer
|
||||
keys := make([]string, 0, len(v))
|
||||
for k := range v {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
vs := v[k]
|
||||
prefix := url.QueryEscape(k) + "="
|
||||
for _, v := range vs {
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteByte('&')
|
||||
}
|
||||
buf.WriteString(prefix)
|
||||
buf.WriteString(v)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
// 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 or false
|
||||
// if it's not. If the error doesn't implement the net.Error interface the return value is true.
|
||||
func IsTemporaryNetworkError(err error) bool {
|
||||
if netErr, ok := err.(net.Error); !ok || (ok && netErr.Temporary()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
+14
-29
@@ -1,35 +1,20 @@
|
||||
package autorest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
major = 8
|
||||
minor = 0
|
||||
patch = 0
|
||||
tag = ""
|
||||
)
|
||||
|
||||
var once sync.Once
|
||||
var version string
|
||||
// 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 {
|
||||
once.Do(func() {
|
||||
semver := fmt.Sprintf("%d.%d.%d", major, minor, patch)
|
||||
verBuilder := bytes.NewBufferString(semver)
|
||||
if tag != "" && tag != "-" {
|
||||
updated := strings.TrimPrefix(tag, "-")
|
||||
_, err := verBuilder.WriteString("-" + updated)
|
||||
if err == nil {
|
||||
verBuilder = bytes.NewBufferString(semver)
|
||||
}
|
||||
}
|
||||
version = verBuilder.String()
|
||||
})
|
||||
return version
|
||||
return "v10.10.0"
|
||||
}
|
||||
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
hash: 51202aefdfe9c4a992f96ab58f6cacf21cdbd1b66efe955c9030bca736ac816d
|
||||
updated: 2017-02-14T17:07:23.015382703-08:00
|
||||
imports:
|
||||
- name: github.com/dgrijalva/jwt-go
|
||||
version: a601269ab70c205d26370c16f7c81e9017c14e04
|
||||
subpackages:
|
||||
- .
|
||||
- name: golang.org/x/crypto
|
||||
version: 453249f01cfeb54c3d549ddb75ff152ca243f9d8
|
||||
repo: https://github.com/golang/crypto.git
|
||||
vcs: git
|
||||
subpackages:
|
||||
- pkcs12
|
||||
- pkcs12/internal/rc2
|
||||
- name: golang.org/x/net
|
||||
version: 61557ac0112b576429a0df080e1c2cef5dfbb642
|
||||
repo: https://github.com/golang/net.git
|
||||
vcs: git
|
||||
subpackages:
|
||||
- .
|
||||
- name: golang.org/x/text
|
||||
version: 06d6eba81293389cafdff7fca90d75592194b2d9
|
||||
repo: https://github.com/golang/text.git
|
||||
vcs: git
|
||||
subpackages:
|
||||
- .
|
||||
testImports:
|
||||
- name: github.com/davecgh/go-spew
|
||||
version: 346938d642f2ec3594ed81d874461961cd0faa76
|
||||
subpackages:
|
||||
- spew
|
||||
- name: github.com/Masterminds/semver
|
||||
version: 59c29afe1a994eacb71c833025ca7acf874bb1da
|
||||
- name: github.com/pmezard/go-difflib
|
||||
version: 792786c7400a136282c1664665ae0a8db921c6c2
|
||||
subpackages:
|
||||
- difflib
|
||||
- name: github.com/stretchr/testify
|
||||
version: 4d4bfba8f1d1027c4fdbe371823030df51419987
|
||||
subpackages:
|
||||
- assert
|
||||
- require
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package: github.com/Azure/go-autorest
|
||||
import:
|
||||
- package: github.com/dgrijalva/jwt-go
|
||||
subpackages:
|
||||
- .
|
||||
- package: golang.org/x/crypto
|
||||
vcs: git
|
||||
repo: https://github.com/golang/crypto.git
|
||||
subpackages:
|
||||
- /pkcs12
|
||||
- package: golang.org/x/net
|
||||
vcs: git
|
||||
repo: https://github.com/golang/net.git
|
||||
subpackages:
|
||||
- .
|
||||
- package: golang.org/x/text
|
||||
vcs: git
|
||||
repo: https://github.com/golang/text.git
|
||||
subpackages:
|
||||
- .
|
||||
testImports:
|
||||
- package: github.com/stretchr/testify
|
||||
vcs: git
|
||||
repo: https://github.com/stretchr/testify.git
|
||||
subpackages:
|
||||
- /require
|
||||
- package: github.com/Masterminds/semver
|
||||
version: ~1.2.2
|
||||
+11
-4
@@ -1,8 +1,15 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- tip
|
||||
env:
|
||||
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
||||
install:
|
||||
- go get -t ./...
|
||||
script: GOMAXPROCS=4 GORACE="halt_on_error=1" go test -race -v ./...
|
||||
- go get github.com/stretchr/testify/assert
|
||||
- go get gopkg.in/gemnasium/logrus-airbrake-hook.v2
|
||||
- go get golang.org/x/sys/unix
|
||||
- go get golang.org/x/sys/windows
|
||||
script:
|
||||
- go test -race -v ./...
|
||||
|
||||
+29
@@ -1,3 +1,32 @@
|
||||
# 1.0.5
|
||||
|
||||
* Fix hooks race (#707)
|
||||
* Fix panic deadlock (#695)
|
||||
|
||||
# 1.0.4
|
||||
|
||||
* Fix race when adding hooks (#612)
|
||||
* Fix terminal check in AppEngine (#635)
|
||||
|
||||
# 1.0.3
|
||||
|
||||
* Replace example files with testable examples
|
||||
|
||||
# 1.0.2
|
||||
|
||||
* bug: quote non-string values in text formatter (#583)
|
||||
* Make (*Logger) SetLevel a public method
|
||||
|
||||
# 1.0.1
|
||||
|
||||
* bug: fix escaping in text formatter (#575)
|
||||
|
||||
# 1.0.0
|
||||
|
||||
* Officially changed name to lower-case
|
||||
* bug: colors on Windows 10 (#541)
|
||||
* bug: fix race in accessing level (#512)
|
||||
|
||||
# 0.11.5
|
||||
|
||||
* feature: add writer and writerlevel to entry (#372)
|
||||
|
||||
+68
-33
@@ -1,17 +1,24 @@
|
||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://travis-ci.org/Sirupsen/logrus) [](https://godoc.org/github.com/Sirupsen/logrus)
|
||||
|
||||
**Seeing weird case-sensitive problems?** See [this
|
||||
issue](https://github.com/sirupsen/logrus/issues/451#issuecomment-264332021).
|
||||
This change has been reverted. I apologize for causing this. I greatly
|
||||
underestimated the impact this would have. Logrus strives for stability and
|
||||
backwards compatibility and failed to provide that.
|
||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://travis-ci.org/sirupsen/logrus) [](https://godoc.org/github.com/sirupsen/logrus)
|
||||
|
||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||
yet stable (pre 1.0). Logrus itself is completely stable and has been used in
|
||||
many large deployments. The core API is unlikely to change much but please
|
||||
version control your Logrus to make sure you aren't fetching latest `master` on
|
||||
every build.**
|
||||
the standard library logger.
|
||||
|
||||
**Seeing weird case-sensitive problems?** It's in the past been possible to
|
||||
import Logrus as both upper- and lower-case. Due to the Go package environment,
|
||||
this caused issues in the community and we needed a standard. Some environments
|
||||
experienced problems with the upper-case variant, so the lower-case was decided.
|
||||
Everything using `logrus` will need to use the lower-case:
|
||||
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
|
||||
|
||||
To fix Glide, see [these
|
||||
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
|
||||
For an in-depth explanation of the casing issue, see [this
|
||||
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
|
||||
|
||||
**Are you interested in assisting in maintaining Logrus?** Currently I have a
|
||||
lot of obligations, and I am unable to provide Logrus with the maintainership it
|
||||
needs. If you'd like to help, please reach out to me at `simon at author's
|
||||
username dot com`.
|
||||
|
||||
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||
plain text):
|
||||
@@ -52,6 +59,12 @@ time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x20822
|
||||
exit status 1
|
||||
```
|
||||
|
||||
#### Case-sensitivity
|
||||
|
||||
The organization's name was changed to lower-case--and this will not be changed
|
||||
back. If you are getting import conflicts due to case sensitivity, please use
|
||||
the lower-case import: `github.com/sirupsen/logrus`.
|
||||
|
||||
#### Example
|
||||
|
||||
The simplest way to use Logrus is simply the package-level exported logger:
|
||||
@@ -60,7 +73,7 @@ The simplest way to use Logrus is simply the package-level exported logger:
|
||||
package main
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -71,7 +84,7 @@ func main() {
|
||||
```
|
||||
|
||||
Note that it's completely api-compatible with the stdlib logger, so you can
|
||||
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
|
||||
replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"`
|
||||
and you'll now have the flexibility of Logrus. You can customize it all you
|
||||
want:
|
||||
|
||||
@@ -80,7 +93,7 @@ package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -130,7 +143,8 @@ application, you can also create an instance of the `logrus` Logger:
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"os"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Create a new instance of the logger. You can have any number of instances.
|
||||
@@ -158,7 +172,7 @@ func main() {
|
||||
|
||||
#### Fields
|
||||
|
||||
Logrus encourages careful, structured logging though logging fields instead of
|
||||
Logrus encourages careful, structured logging through logging fields instead of
|
||||
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
||||
to send event %s to topic %s with key %d")`, you should log the much more
|
||||
discoverable:
|
||||
@@ -189,7 +203,7 @@ application or parts of one. For example, you may want to always log the
|
||||
every line, you can create a `logrus.Entry` to pass around instead:
|
||||
|
||||
```go
|
||||
requestLogger := log.WithFields(log.Fields{"request_id": request_id, user_ip: user_ip})
|
||||
requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
|
||||
requestLogger.Info("something happened on that request") # will log request_id and user_ip
|
||||
requestLogger.Warn("something not great happened")
|
||||
```
|
||||
@@ -205,9 +219,9 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||
|
||||
```go
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
||||
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
|
||||
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||
"log/syslog"
|
||||
)
|
||||
|
||||
@@ -233,30 +247,38 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
|
||||
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
||||
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
|
||||
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
||||
| [Application Insights](https://github.com/jjcollinge/logrus-appinsights) | Hook for logging to [Application Insights](https://azure.microsoft.com/en-us/services/application-insights/)
|
||||
| [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage|
|
||||
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
||||
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
|
||||
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
|
||||
| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/)
|
||||
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
||||
| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
|
||||
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
||||
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
||||
| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
|
||||
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
|
||||
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
|
||||
| [KafkaLogrus](https://github.com/tracer0tong/kafkalogrus) | Hook for logging to Kafka |
|
||||
| [Kafka REST Proxy](https://github.com/Nordstrom/logrus-kafka-rest-proxy) | Hook for logging to [Kafka REST Proxy](https://docs.confluent.io/current/kafka-rest/docs) |
|
||||
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||
| [Logbeat](https://github.com/macandmia/logbeat) | Hook for logging to [Opbeat](https://opbeat.com/) |
|
||||
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
||||
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
||||
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
|
||||
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
|
||||
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
||||
| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) |
|
||||
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
||||
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
|
||||
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
||||
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
||||
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
|
||||
| [Promrus](https://github.com/weaveworks/promrus) | Expose number of log messages as [Prometheus](https://prometheus.io/) metrics |
|
||||
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
|
||||
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
||||
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
||||
@@ -266,10 +288,13 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
|
||||
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
|
||||
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
|
||||
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||
| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
|
||||
| [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) |
|
||||
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
|
||||
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
||||
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
|
||||
| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) |
|
||||
|
||||
#### Level logging
|
||||
|
||||
@@ -318,7 +343,7 @@ could do:
|
||||
|
||||
```go
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
init() {
|
||||
@@ -353,6 +378,7 @@ The built-in logging formatters are:
|
||||
|
||||
Third party logging formatters:
|
||||
|
||||
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
|
||||
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
||||
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||
@@ -421,7 +447,7 @@ entries. It should not be a feature of the application-level logger.
|
||||
| Tool | Description |
|
||||
| ---- | ----------- |
|
||||
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
|
||||
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper arround Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
|
||||
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
|
||||
|
||||
#### Testing
|
||||
|
||||
@@ -431,15 +457,24 @@ Logrus has a built in facility for asserting the presence of log messages. This
|
||||
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
|
||||
|
||||
```go
|
||||
logger, hook := NewNullLogger()
|
||||
logger.Error("Hello error")
|
||||
import(
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
assert.Equal(1, len(hook.Entries))
|
||||
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||
func TestSomething(t*testing.T){
|
||||
logger, hook := test.NewNullLogger()
|
||||
logger.Error("Helloerror")
|
||||
|
||||
hook.Reset()
|
||||
assert.Nil(hook.LastEntry())
|
||||
assert.Equal(t, 1, len(hook.Entries))
|
||||
assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
|
||||
assert.Equal(t, "Helloerror", hook.LastEntry().Message)
|
||||
|
||||
hook.Reset()
|
||||
assert.Nil(t, hook.LastEntry())
|
||||
}
|
||||
```
|
||||
|
||||
#### Fatal handlers
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package logrus
|
||||
|
||||
// The following code was sourced and modified from the
|
||||
// https://bitbucket.org/tebeka/atexit package governed by the following license:
|
||||
// https://github.com/tebeka/atexit package governed by the following license:
|
||||
//
|
||||
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
|
||||
//
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
version: "{build}"
|
||||
platform: x64
|
||||
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
install:
|
||||
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
|
||||
- go version
|
||||
build_script:
|
||||
- go get -t
|
||||
- go test
|
||||
+2
-2
@@ -7,7 +7,7 @@ The simplest way to use Logrus is simply the package-level exported logger:
|
||||
package main
|
||||
|
||||
import (
|
||||
log "github.com/Sirupsen/logrus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -21,6 +21,6 @@ The simplest way to use Logrus is simply the package-level exported logger:
|
||||
Output:
|
||||
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||
|
||||
For a full guide visit https://github.com/Sirupsen/logrus
|
||||
For a full guide visit https://github.com/sirupsen/logrus
|
||||
*/
|
||||
package logrus
|
||||
|
||||
+49
-36
@@ -35,6 +35,7 @@ type Entry struct {
|
||||
Time time.Time
|
||||
|
||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
||||
Level Level
|
||||
|
||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||
@@ -93,29 +94,16 @@ func (entry Entry) log(level Level, msg string) {
|
||||
entry.Level = level
|
||||
entry.Message = msg
|
||||
|
||||
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
entry.fireHooks()
|
||||
|
||||
buffer = bufferPool.Get().(*bytes.Buffer)
|
||||
buffer.Reset()
|
||||
defer bufferPool.Put(buffer)
|
||||
entry.Buffer = buffer
|
||||
serialized, err := entry.Logger.Formatter.Format(&entry)
|
||||
|
||||
entry.write()
|
||||
|
||||
entry.Buffer = nil
|
||||
if err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
} else {
|
||||
entry.Logger.mu.Lock()
|
||||
_, err = entry.Logger.Out.Write(serialized)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
// To avoid Entry#log() returning a value that only would make sense for
|
||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||
@@ -125,8 +113,33 @@ func (entry Entry) log(level Level, msg string) {
|
||||
}
|
||||
}
|
||||
|
||||
// This function is not declared with a pointer value because otherwise
|
||||
// race conditions will occur when using multiple goroutines
|
||||
func (entry Entry) fireHooks() {
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
err := entry.Logger.Hooks.Fire(entry.Level, &entry)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) write() {
|
||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
} else {
|
||||
_, err = entry.Logger.Out.Write(serialized)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
@@ -136,13 +149,13 @@ func (entry *Entry) Print(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Info(args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Warn(args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
@@ -152,20 +165,20 @@ func (entry *Entry) Warning(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Error(args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatal(args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||
}
|
||||
Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panic(args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||
}
|
||||
panic(fmt.Sprint(args...))
|
||||
@@ -174,13 +187,13 @@ func (entry *Entry) Panic(args ...interface{}) {
|
||||
// Entry Printf family functions
|
||||
|
||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
entry.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
entry.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
@@ -190,7 +203,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
entry.Warn(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
@@ -200,20 +213,20 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
entry.Error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
entry.Fatal(fmt.Sprintf(format, args...))
|
||||
}
|
||||
Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
entry.Panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
}
|
||||
@@ -221,13 +234,13 @@ func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||
// Entry Println family functions
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
if entry.Logger.Level >= DebugLevel {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
entry.Debug(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Infoln(args ...interface{}) {
|
||||
if entry.Logger.Level >= InfoLevel {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
entry.Info(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
@@ -237,7 +250,7 @@ func (entry *Entry) Println(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnln(args ...interface{}) {
|
||||
if entry.Logger.Level >= WarnLevel {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
entry.Warn(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
@@ -247,20 +260,20 @@ func (entry *Entry) Warningln(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorln(args ...interface{}) {
|
||||
if entry.Logger.Level >= ErrorLevel {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
entry.Error(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||
if entry.Logger.Level >= FatalLevel {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
entry.Fatal(entry.sprintlnn(args...))
|
||||
}
|
||||
Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicln(args ...interface{}) {
|
||||
if entry.Logger.Level >= PanicLevel {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
entry.Panic(entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,14 +31,14 @@ func SetFormatter(formatter Formatter) {
|
||||
func SetLevel(level Level) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Level = level
|
||||
std.SetLevel(level)
|
||||
}
|
||||
|
||||
// GetLevel returns the standard logger level.
|
||||
func GetLevel() Level {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
return std.Level
|
||||
return std.level()
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the standard logger hooks.
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package logrus
|
||||
|
||||
import "time"
|
||||
|
||||
const DefaultTimestampFormat = time.RFC3339
|
||||
const defaultTimestampFormat = time.RFC3339
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
|
||||
+9
-4
@@ -6,8 +6,11 @@ import (
|
||||
)
|
||||
|
||||
type fieldKey string
|
||||
|
||||
// FieldMap allows customization of the key names for default fields.
|
||||
type FieldMap map[fieldKey]string
|
||||
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
@@ -22,6 +25,7 @@ func (f FieldMap) resolve(key fieldKey) string {
|
||||
return string(key)
|
||||
}
|
||||
|
||||
// JSONFormatter formats logs into parsable json
|
||||
type JSONFormatter struct {
|
||||
// TimestampFormat sets the format used for marshaling timestamps.
|
||||
TimestampFormat string
|
||||
@@ -29,25 +33,26 @@ type JSONFormatter struct {
|
||||
// DisableTimestamp allows disabling automatic timestamps in output
|
||||
DisableTimestamp bool
|
||||
|
||||
// FieldMap allows users to customize the names of keys for various fields.
|
||||
// FieldMap allows users to customize the names of keys for default fields.
|
||||
// As an example:
|
||||
// formatter := &JSONFormatter{
|
||||
// FieldMap: FieldMap{
|
||||
// FieldKeyTime: "@timestamp",
|
||||
// FieldKeyLevel: "@level",
|
||||
// FieldKeyLevel: "@message",
|
||||
// FieldKeyMsg: "@message",
|
||||
// },
|
||||
// }
|
||||
FieldMap FieldMap
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data := make(Fields, len(entry.Data)+3)
|
||||
for k, v := range entry.Data {
|
||||
switch v := v.(type) {
|
||||
case error:
|
||||
// Otherwise errors are ignored by `encoding/json`
|
||||
// https://github.com/Sirupsen/logrus/issues/137
|
||||
// https://github.com/sirupsen/logrus/issues/137
|
||||
data[k] = v.Error()
|
||||
default:
|
||||
data[k] = v
|
||||
@@ -57,7 +62,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = DefaultTimestampFormat
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
|
||||
if !f.DisableTimestamp {
|
||||
|
||||
+37
-22
@@ -4,6 +4,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
@@ -24,7 +25,7 @@ type Logger struct {
|
||||
Formatter Formatter
|
||||
// The logging level the logger should log at. This is typically (and defaults
|
||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||
// logged. `logrus.Debug` is useful in
|
||||
// logged.
|
||||
Level Level
|
||||
// Used to sync writing to the log. Locking is enabled by Default
|
||||
mu MutexWrap
|
||||
@@ -112,7 +113,7 @@ func (logger *Logger) WithError(err error) *Entry {
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
if logger.Level >= DebugLevel {
|
||||
if logger.level() >= DebugLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Debugf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -120,7 +121,7 @@ func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||
if logger.Level >= InfoLevel {
|
||||
if logger.level() >= InfoLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Infof(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -134,7 +135,7 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -142,7 +143,7 @@ func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -150,7 +151,7 @@ func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||
if logger.Level >= ErrorLevel {
|
||||
if logger.level() >= ErrorLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Errorf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -158,7 +159,7 @@ func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||
if logger.Level >= FatalLevel {
|
||||
if logger.level() >= FatalLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatalf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -167,7 +168,7 @@ func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||
if logger.Level >= PanicLevel {
|
||||
if logger.level() >= PanicLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Panicf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -175,7 +176,7 @@ func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Debug(args ...interface{}) {
|
||||
if logger.Level >= DebugLevel {
|
||||
if logger.level() >= DebugLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Debug(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -183,7 +184,7 @@ func (logger *Logger) Debug(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Info(args ...interface{}) {
|
||||
if logger.Level >= InfoLevel {
|
||||
if logger.level() >= InfoLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Info(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -197,7 +198,7 @@ func (logger *Logger) Print(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Warn(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warn(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -205,7 +206,7 @@ func (logger *Logger) Warn(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Warning(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warn(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -213,7 +214,7 @@ func (logger *Logger) Warning(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Error(args ...interface{}) {
|
||||
if logger.Level >= ErrorLevel {
|
||||
if logger.level() >= ErrorLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Error(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -221,7 +222,7 @@ func (logger *Logger) Error(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatal(args ...interface{}) {
|
||||
if logger.Level >= FatalLevel {
|
||||
if logger.level() >= FatalLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatal(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -230,7 +231,7 @@ func (logger *Logger) Fatal(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Panic(args ...interface{}) {
|
||||
if logger.Level >= PanicLevel {
|
||||
if logger.level() >= PanicLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Panic(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -238,7 +239,7 @@ func (logger *Logger) Panic(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugln(args ...interface{}) {
|
||||
if logger.Level >= DebugLevel {
|
||||
if logger.level() >= DebugLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Debugln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -246,7 +247,7 @@ func (logger *Logger) Debugln(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Infoln(args ...interface{}) {
|
||||
if logger.Level >= InfoLevel {
|
||||
if logger.level() >= InfoLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Infoln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -260,7 +261,7 @@ func (logger *Logger) Println(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnln(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -268,7 +269,7 @@ func (logger *Logger) Warnln(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningln(args ...interface{}) {
|
||||
if logger.Level >= WarnLevel {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -276,7 +277,7 @@ func (logger *Logger) Warningln(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorln(args ...interface{}) {
|
||||
if logger.Level >= ErrorLevel {
|
||||
if logger.level() >= ErrorLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Errorln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -284,7 +285,7 @@ func (logger *Logger) Errorln(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||
if logger.Level >= FatalLevel {
|
||||
if logger.level() >= FatalLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatalln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -293,7 +294,7 @@ func (logger *Logger) Fatalln(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicln(args ...interface{}) {
|
||||
if logger.Level >= PanicLevel {
|
||||
if logger.level() >= PanicLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Panicln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
@@ -306,3 +307,17 @@ func (logger *Logger) Panicln(args ...interface{}) {
|
||||
func (logger *Logger) SetNoLock() {
|
||||
logger.mu.Disable()
|
||||
}
|
||||
|
||||
func (logger *Logger) level() Level {
|
||||
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
||||
}
|
||||
|
||||
func (logger *Logger) SetLevel(level Level) {
|
||||
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
||||
}
|
||||
|
||||
func (logger *Logger) AddHook(hook Hook) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Hooks.Add(hook)
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
type Fields map[string]interface{}
|
||||
|
||||
// Level type
|
||||
type Level uint8
|
||||
type Level uint32
|
||||
|
||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||
func (level Level) String() string {
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
// +build appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import "io"
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal(f io.Writer) bool {
|
||||
return true
|
||||
}
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
// +build darwin freebsd openbsd netbsd dragonfly
|
||||
// +build !appengine
|
||||
// +build !appengine,!gopherjs
|
||||
|
||||
package logrus
|
||||
|
||||
import "syscall"
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
const ioctlReadTermios = unix.TIOCGETA
|
||||
|
||||
type Termios syscall.Termios
|
||||
type Termios unix.Termios
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// +build appengine gopherjs
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
func checkIfTerminal(w io.Writer) bool {
|
||||
return true
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// +build !appengine,!gopherjs
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
func checkIfTerminal(w io.Writer) bool {
|
||||
switch v := w.(type) {
|
||||
case *os.File:
|
||||
return terminal.IsTerminal(int(v.Fd()))
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -3,12 +3,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
// +build !appengine,!gopherjs
|
||||
|
||||
package logrus
|
||||
|
||||
import "syscall"
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
const ioctlReadTermios = unix.TCGETS
|
||||
|
||||
type Termios syscall.Termios
|
||||
type Termios unix.Termios
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||
// +build !appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal(f io.Writer) bool {
|
||||
var termios Termios
|
||||
switch v := f.(type) {
|
||||
case *os.File:
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
// +build solaris,!appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(f io.Writer) bool {
|
||||
switch v := f.(type) {
|
||||
case *os.File:
|
||||
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
|
||||
return err == nil
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows,!appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
)
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal(f io.Writer) bool {
|
||||
switch v := f.(type) {
|
||||
case *os.File:
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
+18
-29
@@ -14,7 +14,7 @@ const (
|
||||
red = 31
|
||||
green = 32
|
||||
yellow = 33
|
||||
blue = 34
|
||||
blue = 36
|
||||
gray = 37
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@ func init() {
|
||||
baseTimestamp = time.Now()
|
||||
}
|
||||
|
||||
// TextFormatter formats logs into text
|
||||
type TextFormatter struct {
|
||||
// Set to true to bypass checking for a TTY before outputting colors.
|
||||
ForceColors bool
|
||||
@@ -52,10 +53,6 @@ type TextFormatter struct {
|
||||
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||
QuoteEmptyFields bool
|
||||
|
||||
// QuoteCharacter can be set to the override the default quoting character "
|
||||
// with something else. For example: ', or `.
|
||||
QuoteCharacter string
|
||||
|
||||
// Whether the logger's out is to a terminal
|
||||
isTerminal bool
|
||||
|
||||
@@ -63,14 +60,12 @@ type TextFormatter struct {
|
||||
}
|
||||
|
||||
func (f *TextFormatter) init(entry *Entry) {
|
||||
if len(f.QuoteCharacter) == 0 {
|
||||
f.QuoteCharacter = "\""
|
||||
}
|
||||
if entry.Logger != nil {
|
||||
f.isTerminal = IsTerminal(entry.Logger.Out)
|
||||
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
||||
}
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
var b *bytes.Buffer
|
||||
keys := make([]string, 0, len(entry.Data))
|
||||
@@ -95,7 +90,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = DefaultTimestampFormat
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
if isColored {
|
||||
f.printColored(b, entry, keys, timestampFormat)
|
||||
@@ -153,7 +148,7 @@ func (f *TextFormatter) needsQuoting(text string) bool {
|
||||
if !((ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') ||
|
||||
ch == '-' || ch == '.') {
|
||||
ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -161,29 +156,23 @@ func (f *TextFormatter) needsQuoting(text string) bool {
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||
|
||||
if b.Len() > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteString(key)
|
||||
b.WriteByte('=')
|
||||
f.appendValue(b, value)
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if !f.needsQuoting(value) {
|
||||
b.WriteString(value)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
|
||||
}
|
||||
case error:
|
||||
errmsg := value.Error()
|
||||
if !f.needsQuoting(errmsg) {
|
||||
b.WriteString(errmsg)
|
||||
} else {
|
||||
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
|
||||
}
|
||||
default:
|
||||
fmt.Fprint(b, value)
|
||||
stringVal, ok := value.(string)
|
||||
if !ok {
|
||||
stringVal = fmt.Sprint(value)
|
||||
}
|
||||
|
||||
if !f.needsQuoting(stringVal) {
|
||||
b.WriteString(stringVal)
|
||||
} else {
|
||||
b.WriteString(fmt.Sprintf("%q", stringVal))
|
||||
}
|
||||
}
|
||||
|
||||
+43
-19
@@ -1,24 +1,48 @@
|
||||
language: go
|
||||
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- tip
|
||||
|
||||
# Use Go 1.5's vendoring experiment for 1.5 tests.
|
||||
env:
|
||||
- GO15VENDOREXPERIMENT=1
|
||||
|
||||
install:
|
||||
- make get-deps
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
- go: 1.6.x
|
||||
os: linux
|
||||
include:
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.5.x
|
||||
# Use Go 1.5's vendoring experiment for 1.5 tests.
|
||||
env: GO15VENDOREXPERIMENT=1
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.6.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.7.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.8.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.9.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: 1.10.x
|
||||
- os: linux
|
||||
sudo: required
|
||||
go: tip
|
||||
- os: osx
|
||||
go: 1.7.x
|
||||
- os: osx
|
||||
go: 1.8.x
|
||||
- os: osx
|
||||
go: 1.9.x
|
||||
- os: osx
|
||||
go: 1.10.x
|
||||
- os: osx
|
||||
go: tip
|
||||
|
||||
script:
|
||||
- make unit-with-race-cover
|
||||
- make ci-test
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
+2599
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -2,4 +2,4 @@
|
||||
|
||||
### SDK Enhancements
|
||||
|
||||
### SDK Bugs
|
||||
### SDK Bugs
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
## Code of Conduct
|
||||
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||
+2
-2
@@ -67,7 +67,7 @@ Please be aware of the following notes prior to opening a pull request:
|
||||
5. The JSON files under the SDK's `models` folder are sourced from outside the SDK.
|
||||
Such as `models/apis/ec2/2016-11-15/api.json`. We will not accept pull requests
|
||||
directly on these models. If you discover an issue with the models please
|
||||
create a Github [issue](issues) describing the issue.
|
||||
create a [GitHub issue][issues] describing the issue.
|
||||
|
||||
### Testing
|
||||
|
||||
@@ -89,7 +89,7 @@ go test -tags codegen ./private/...
|
||||
See the `Makefile` for additional testing tags that can be used in testing.
|
||||
|
||||
To test on multiple platform the SDK includes several DockerFiles under the
|
||||
`awstesting/sandbox` folder, and associated make recipes to to execute
|
||||
`awstesting/sandbox` folder, and associated make recipes to execute
|
||||
unit testing within environments configured for specific Go versions.
|
||||
|
||||
```
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ini/ini"
|
||||
packages = ["."]
|
||||
revision = "300e940a926eb277d3901b20bdfcc54928ad3642"
|
||||
version = "v1.25.4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
packages = ["."]
|
||||
revision = "0b12d6b5"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "51a86a867df617990082dec6b868e4efe2fdb2ed0e02a3daa93cd30f962b5085"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
ignored = [
|
||||
# Testing/Example/Codegen dependencies
|
||||
"github.com/stretchr/testify",
|
||||
"github.com/stretchr/testify/assert",
|
||||
"github.com/stretchr/testify/require",
|
||||
"github.com/go-sql-driver/mysql",
|
||||
"github.com/gucumber/gucumber",
|
||||
"github.com/pkg/errors",
|
||||
"golang.org/x/net",
|
||||
"golang.org/x/net/html",
|
||||
"golang.org/x/net/http2",
|
||||
"golang.org/x/text",
|
||||
"golang.org/x/text/html",
|
||||
"golang.org/x/tools",
|
||||
"golang.org/x/tools/go/loader",
|
||||
]
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-ini/ini"
|
||||
version = "1.25.4"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/jmespath/go-jmespath"
|
||||
revision = "0b12d6b5"
|
||||
#version = "0.2.2"
|
||||
+28
-3
@@ -5,13 +5,15 @@ LINTIGNORESTUTTER='service/[^/]+/(api|service)\.go:.+(and that stutters)'
|
||||
LINTIGNOREINFLECT='service/[^/]+/(api|errors|service)\.go:.+(method|const) .+ should be '
|
||||
LINTIGNOREINFLECTS3UPLOAD='service/s3/s3manager/upload\.go:.+struct field SSEKMSKeyId should be '
|
||||
LINTIGNOREDEPS='vendor/.+\.go'
|
||||
UNIT_TEST_TAGS="example codegen"
|
||||
LINTIGNOREPKGCOMMENT='service/[^/]+/doc_custom.go:.+package comment should be of the form'
|
||||
UNIT_TEST_TAGS="example codegen awsinclude"
|
||||
|
||||
SDK_WITH_VENDOR_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/src")
|
||||
SDK_ONLY_PKGS=$(shell go list ./... | grep -v "/vendor/")
|
||||
SDK_UNIT_TEST_ONLY_PKGS=$(shell go list -tags ${UNIT_TEST_TAGS} ./... | grep -v "/vendor/")
|
||||
SDK_GO_1_4=$(shell go version | grep "go1.4")
|
||||
SDK_GO_1_5=$(shell go version | grep "go1.5")
|
||||
SDK_GO_1_6=$(shell go version | grep "go1.6")
|
||||
SDK_GO_VERSION=$(shell go version | awk '''{print $$3}''' | tr -d '''\n''')
|
||||
|
||||
all: get-deps generate unit
|
||||
@@ -59,18 +61,33 @@ unit-with-race-cover: get-deps-tests build verify
|
||||
@echo "go test SDK and vendor packages"
|
||||
@go test -tags ${UNIT_TEST_TAGS} -race -cpu=1,2,4 $(SDK_UNIT_TEST_ONLY_PKGS)
|
||||
|
||||
ci-test: ci-test-generate unit-with-race-cover ci-test-generate-validate
|
||||
|
||||
ci-test-generate: get-deps
|
||||
@echo "CI test generated code"
|
||||
@if [ \( -z "${SDK_GO_1_6}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then make generate; else echo "skipping generate"; fi
|
||||
|
||||
ci-test-generate-validate:
|
||||
@echo "CI test validate no generated code changes"
|
||||
@gitstatus=`if [ \( -z "${SDK_GO_1_6}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then git status --porcelain; else echo "skipping validation"; fi`; \
|
||||
echo "$$gitstatus"; \
|
||||
if [ "$$gitstatus" != "" ] && [ "$$gitstatus" != "skipping validation" ]; then git diff; exit 1; fi
|
||||
|
||||
integration: get-deps-tests integ-custom smoke-tests performance
|
||||
|
||||
integ-custom:
|
||||
go test -tags "integration" ./awstesting/integration/customizations/...
|
||||
|
||||
cleanup-integ:
|
||||
go run -tags "integration" ./awstesting/cmd/bucket_cleanup/main.go "aws-sdk-go-integration"
|
||||
|
||||
smoke-tests: get-deps-tests
|
||||
gucumber -go-tags "integration" ./awstesting/integration/smoke
|
||||
|
||||
performance: get-deps-tests
|
||||
AWS_TESTING_LOG_RESULTS=${log-detailed} AWS_TESTING_REGION=$(region) AWS_TESTING_DB_TABLE=$(table) gucumber -go-tags "integration" ./awstesting/performance
|
||||
|
||||
sandbox-tests: sandbox-test-go15 sandbox-test-go15-novendorexp sandbox-test-go16 sandbox-test-go17 sandbox-test-go18 sandbox-test-gotip
|
||||
sandbox-tests: sandbox-test-go15 sandbox-test-go15-novendorexp sandbox-test-go16 sandbox-test-go17 sandbox-test-go18 sandbox-test-go19 sandbox-test-gotip
|
||||
|
||||
sandbox-build-go15:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.5 -t "aws-sdk-go-1.5" .
|
||||
@@ -107,6 +124,13 @@ sandbox-go18: sandbox-build-go18
|
||||
sandbox-test-go18: sandbox-build-go18
|
||||
docker run -t aws-sdk-go-1.8
|
||||
|
||||
sandbox-build-go19:
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.go1.8 -t "aws-sdk-go-1.9" .
|
||||
sandbox-go19: sandbox-build-go19
|
||||
docker run -i -t aws-sdk-go-1.9 bash
|
||||
sandbox-test-go19: sandbox-build-go19
|
||||
docker run -t aws-sdk-go-1.9
|
||||
|
||||
sandbox-build-gotip:
|
||||
@echo "Run make update-aws-golang-tip, if this test fails because missing aws-golang:tip container"
|
||||
docker build -f ./awstesting/sandbox/Dockerfile.test.gotip -t "aws-sdk-go-tip" .
|
||||
@@ -123,7 +147,7 @@ verify: get-deps-verify lint vet
|
||||
lint:
|
||||
@echo "go lint SDK and vendor packages"
|
||||
@lint=`if [ \( -z "${SDK_GO_1_4}" \) -a \( -z "${SDK_GO_1_5}" \) ]; then golint ./...; else echo "skipping golint"; fi`; \
|
||||
lint=`echo "$$lint" | grep -E -v -e ${LINTIGNOREDOT} -e ${LINTIGNOREDOC} -e ${LINTIGNORECONST} -e ${LINTIGNORESTUTTER} -e ${LINTIGNOREINFLECT} -e ${LINTIGNOREDEPS} -e ${LINTIGNOREINFLECTS3UPLOAD}`; \
|
||||
lint=`echo "$$lint" | grep -E -v -e ${LINTIGNOREDOT} -e ${LINTIGNOREDOC} -e ${LINTIGNORECONST} -e ${LINTIGNORESTUTTER} -e ${LINTIGNOREINFLECT} -e ${LINTIGNOREDEPS} -e ${LINTIGNOREINFLECTS3UPLOAD} -e ${LINTIGNOREPKGCOMMENT}`; \
|
||||
echo "$$lint"; \
|
||||
if [ "$$lint" != "" ] && [ "$$lint" != "skipping golint" ]; then exit 1; fi
|
||||
|
||||
@@ -149,6 +173,7 @@ get-deps-tests:
|
||||
go get github.com/stretchr/testify
|
||||
go get github.com/smartystreets/goconvey
|
||||
go get golang.org/x/net/html
|
||||
go get golang.org/x/net/http2
|
||||
|
||||
get-deps-verify:
|
||||
@echo "go get SDK verification utilities"
|
||||
|
||||
+385
-96
@@ -1,9 +1,13 @@
|
||||
# AWS SDK for Go [](http://docs.aws.amazon.com/sdk-for-go/api) [](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://travis-ci.org/aws/aws-sdk-go) [](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
|
||||
[](http://docs.aws.amazon.com/sdk-for-go/api) [](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://travis-ci.org/aws/aws-sdk-go) [](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
|
||||
|
||||
# AWS SDK for Go
|
||||
|
||||
aws-sdk-go is the official AWS SDK for the Go programming language.
|
||||
|
||||
Checkout our [release notes](https://github.com/aws/aws-sdk-go/releases) for information about the latest bug fixes, updates, and features added to the SDK.
|
||||
|
||||
We [announced](https://aws.amazon.com/blogs/developer/aws-sdk-for-go-2-0-developer-preview/) the Developer Preview for the [v2 AWS SDK for Go](https://github.com/aws/aws-sdk-go-v2). The v2 SDK is available at https://github.com/aws/aws-sdk-go-v2, and `go get github.com/aws/aws-sdk-go-v2` via `go get`. Check out the v2 SDK's [changes and updates](https://github.com/aws/aws-sdk-go-v2/blob/master/CHANGELOG.md), and let us know what you think. We want your feedback.
|
||||
|
||||
## Installing
|
||||
|
||||
If you are using Go 1.5 with the `GO15VENDOREXPERIMENT=1` vendoring flag, or 1.6 and higher you can use the following command to retrieve the SDK. The SDK's non-testing dependencies will be included and are vendored in the `vendor` folder.
|
||||
@@ -26,16 +30,17 @@ These two processes will still include the `vendor` folder and it should be dele
|
||||
## Getting Help
|
||||
|
||||
Please use these community resources for getting help. We use the GitHub issues for tracking bugs and feature requests.
|
||||
|
||||
* Ask a question on [StackOverflow](http://stackoverflow.com/) and tag it with the [`aws-sdk-go`](http://stackoverflow.com/questions/tagged/aws-sdk-go) tag.
|
||||
* Come join the AWS SDK for Go community chat on [gitter](https://gitter.im/aws/aws-sdk-go).
|
||||
* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html).
|
||||
* If you think you may of found a bug, please open an [issue](https://github.com/aws/aws-sdk-go/issues/new).
|
||||
* If you think you may have found a bug, please open an [issue](https://github.com/aws/aws-sdk-go/issues/new).
|
||||
|
||||
## Opening Issues
|
||||
|
||||
If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues]( https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS you’re using. Please also include repro case when appropriate.
|
||||
If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues](https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS you’re using. Please also include repro case when appropriate.
|
||||
|
||||
The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help]( https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner.
|
||||
The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help](https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner.
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
@@ -47,113 +52,397 @@ The GitHub issues are intended for bug reports and feature requests. For help an
|
||||
|
||||
[`SDK Examples`](https://github.com/aws/aws-sdk-go/tree/master/example) - Included in the SDK's repo are a several hand crafted examples using the SDK features and AWS services.
|
||||
|
||||
## Configuring Credentials
|
||||
## Overview of SDK's Packages
|
||||
|
||||
Before using the SDK, ensure that you've configured credentials. The best
|
||||
way to configure credentials on a development machine is to use the
|
||||
`~/.aws/credentials` file, which might look like:
|
||||
The SDK is composed of two main components, SDK core, and service clients.
|
||||
The SDK core packages are all available under the aws package at the root of
|
||||
the SDK. Each client for a supported AWS service is available within its own
|
||||
package under the service folder at the root of the SDK.
|
||||
|
||||
```
|
||||
[default]
|
||||
aws_access_key_id = AKID1234567890
|
||||
aws_secret_access_key = MY-SECRET-KEY
|
||||
```
|
||||
* aws - SDK core, provides common shared types such as Config, Logger,
|
||||
and utilities to make working with API parameters easier.
|
||||
|
||||
You can learn more about the credentials file from this
|
||||
[blog post](http://blogs.aws.amazon.com/security/post/Tx3D6U6WSFGOK2H/A-New-and-Standardized-Way-to-Manage-Credentials-in-the-AWS-SDKs).
|
||||
* awserr - Provides the error interface that the SDK will use for all
|
||||
errors that occur in the SDK's processing. This includes service API
|
||||
response errors as well. The Error type is made up of a code and message.
|
||||
Cast the SDK's returned error type to awserr.Error and call the Code
|
||||
method to compare returned error to specific error codes. See the package's
|
||||
documentation for additional values that can be extracted such as RequestID.
|
||||
|
||||
Alternatively, you can set the following environment variables:
|
||||
* credentials - Provides the types and built in credentials providers
|
||||
the SDK will use to retrieve AWS credentials to make API requests with.
|
||||
Nested under this folder are also additional credentials providers such as
|
||||
stscreds for assuming IAM roles, and ec2rolecreds for EC2 Instance roles.
|
||||
|
||||
```
|
||||
AWS_ACCESS_KEY_ID=AKID1234567890
|
||||
AWS_SECRET_ACCESS_KEY=MY-SECRET-KEY
|
||||
```
|
||||
* endpoints - Provides the AWS Regions and Endpoints metadata for the SDK.
|
||||
Use this to lookup AWS service endpoint information such as which services
|
||||
are in a region, and what regions a service is in. Constants are also provided
|
||||
for all region identifiers, e.g UsWest2RegionID for "us-west-2".
|
||||
|
||||
### AWS shared config file (`~/.aws/config`)
|
||||
The AWS SDK for Go added support the shared config file in release [v1.3.0](https://github.com/aws/aws-sdk-go/releases/tag/v1.3.0). You can opt into enabling support for the shared config by setting the environment variable `AWS_SDK_LOAD_CONFIG` to a truthy value. See the [Session](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/sessions.html) docs for more information about this feature.
|
||||
* session - Provides initial default configuration, and load
|
||||
configuration from external sources such as environment and shared
|
||||
credentials file.
|
||||
|
||||
## Using the Go SDK
|
||||
* request - Provides the API request sending, and retry logic for the SDK.
|
||||
This package also includes utilities for defining your own request
|
||||
retryer, and configuring how the SDK processes the request.
|
||||
|
||||
To use a service in the SDK, create a service variable by calling the `New()`
|
||||
function. Once you have a service client, you can call API operations which each
|
||||
return response data and a possible error.
|
||||
* service - Clients for AWS services. All services supported by the SDK are
|
||||
available under this folder.
|
||||
|
||||
For example the following code shows how to upload an object to Amazon S3 with a Context timeout.
|
||||
## How to Use the SDK's AWS Service Clients
|
||||
|
||||
The SDK includes the Go types and utilities you can use to make requests to
|
||||
AWS service APIs. Within the service folder at the root of the SDK you'll find
|
||||
a package for each AWS service the SDK supports. All service clients follows
|
||||
a common pattern of creation and usage.
|
||||
|
||||
When creating a client for an AWS service you'll first need to have a Session
|
||||
value constructed. The Session provides shared configuration that can be shared
|
||||
between your service clients. When service clients are created you can pass
|
||||
in additional configuration via the aws.Config type to override configuration
|
||||
provided by in the Session to create service client instances with custom
|
||||
configuration.
|
||||
|
||||
Once the service's client is created you can use it to make API requests the
|
||||
AWS service. These clients are safe to use concurrently.
|
||||
|
||||
## Configuring the SDK
|
||||
|
||||
In the AWS SDK for Go, you can configure settings for service clients, such
|
||||
as the log level and maximum number of retries. Most settings are optional;
|
||||
however, for each service client, you must specify a region and your credentials.
|
||||
The SDK uses these values to send requests to the correct AWS region and sign
|
||||
requests with the correct credentials. You can specify these values as part
|
||||
of a session or as environment variables.
|
||||
|
||||
See the SDK's [configuration guide][config_guide] for more information.
|
||||
|
||||
See the [session][session_pkg] package documentation for more information on how to use Session
|
||||
with the SDK.
|
||||
|
||||
See the [Config][config_typ] type in the [aws][aws_pkg] package for more information on configuration
|
||||
options.
|
||||
|
||||
[config_guide]: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html
|
||||
[session_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/session/
|
||||
[config_typ]: https://docs.aws.amazon.com/sdk-for-go/api/aws/#Config
|
||||
[aws_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/
|
||||
|
||||
### Configuring Credentials
|
||||
|
||||
When using the SDK you'll generally need your AWS credentials to authenticate
|
||||
with AWS services. The SDK supports multiple methods of supporting these
|
||||
credentials. By default the SDK will source credentials automatically from
|
||||
its default credential chain. See the session package for more information
|
||||
on this chain, and how to configure it. The common items in the credential
|
||||
chain are the following:
|
||||
|
||||
* Environment Credentials - Set of environment variables that are useful
|
||||
when sub processes are created for specific roles.
|
||||
|
||||
* Shared Credentials file (~/.aws/credentials) - This file stores your
|
||||
credentials based on a profile name and is useful for local development.
|
||||
|
||||
* EC2 Instance Role Credentials - Use EC2 Instance Role to assign credentials
|
||||
to application running on an EC2 instance. This removes the need to manage
|
||||
credential files in production.
|
||||
|
||||
Credentials can be configured in code as well by setting the Config's Credentials
|
||||
value to a custom provider or using one of the providers included with the
|
||||
SDK to bypass the default credential chain and use a custom one. This is
|
||||
helpful when you want to instruct the SDK to only use a specific set of
|
||||
credentials or providers.
|
||||
|
||||
This example creates a credential provider for assuming an IAM role, "myRoleARN"
|
||||
and configures the S3 service client to use that role for API requests.
|
||||
|
||||
```go
|
||||
package main
|
||||
// Initial credentials loaded from SDK's default credential chain. Such as
|
||||
// the environment, shared credentials (~/.aws/credentials), or EC2 Instance
|
||||
// Role. These credentials will be used to to make the STS Assume Role API.
|
||||
sess := session.Must(session.NewSession())
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
// Create the credentials from AssumeRoleProvider to assume the role
|
||||
// referenced by the "myRoleARN" ARN.
|
||||
creds := stscreds.NewCredentials(sess, "myRoleArn")
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
// Uploads a file to S3 given a bucket and object key. Also takes a duration
|
||||
// value to terminate the update if it doesn't complete within that time.
|
||||
//
|
||||
// The AWS Region needs to be provided in the AWS shared config or on the
|
||||
// environment variable as `AWS_REGION`. Credentials also must be provided
|
||||
// Will default to shared config file, but can load from environment if provided.
|
||||
//
|
||||
// Usage:
|
||||
// # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
|
||||
// go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
|
||||
func main() {
|
||||
var bucket, key string
|
||||
var timeout time.Duration
|
||||
|
||||
flag.StringVar(&bucket, "b", "", "Bucket name.")
|
||||
flag.StringVar(&key, "k", "", "Object key name.")
|
||||
flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
|
||||
flag.Parse()
|
||||
|
||||
sess := session.Must(session.NewSession())
|
||||
svc := s3.New(sess)
|
||||
|
||||
// Create a context with a timeout that will abort the upload if it takes
|
||||
// more than the passed in timeout.
|
||||
ctx := context.Background()
|
||||
var cancelFn func()
|
||||
if timeout > 0 {
|
||||
ctx, cancelFn = context.WithTimeout(ctx, timeout)
|
||||
}
|
||||
// Ensure the context is canceled to prevent leaking.
|
||||
// See context package for more information, https://golang.org/pkg/context/
|
||||
defer cancelFn()
|
||||
|
||||
// Uploads the object to S3. The Context will interrupt the request if the
|
||||
// timeout expires.
|
||||
_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: aws.String(key),
|
||||
Body: os.Stdin,
|
||||
})
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
|
||||
// If the SDK can determine the request or retry delay was canceled
|
||||
// by a context the CanceledErrorCode error code will be returned.
|
||||
fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
|
||||
}
|
||||
// Create service client value configured for credentials
|
||||
// from assumed role.
|
||||
svc := s3.New(sess, &aws.Config{Credentials: creds})
|
||||
```
|
||||
|
||||
You can find more information and operations in our
|
||||
[API documentation](http://docs.aws.amazon.com/sdk-for-go/api/).
|
||||
See the [credentials][credentials_pkg] package documentation for more information on credential
|
||||
providers included with the SDK, and how to customize the SDK's usage of
|
||||
credentials.
|
||||
|
||||
The SDK has support for the shared configuration file (~/.aws/config). This
|
||||
support can be enabled by setting the environment variable, "AWS_SDK_LOAD_CONFIG=1",
|
||||
or enabling the feature in code when creating a Session via the
|
||||
Option's SharedConfigState parameter.
|
||||
|
||||
```go
|
||||
sess := session.Must(session.NewSessionWithOptions(session.Options{
|
||||
SharedConfigState: session.SharedConfigEnable,
|
||||
}))
|
||||
```
|
||||
|
||||
[credentials_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials
|
||||
|
||||
### Configuring AWS Region
|
||||
|
||||
In addition to the credentials you'll need to specify the region the SDK
|
||||
will use to make AWS API requests to. In the SDK you can specify the region
|
||||
either with an environment variable, or directly in code when a Session or
|
||||
service client is created. The last value specified in code wins if the region
|
||||
is specified multiple ways.
|
||||
|
||||
To set the region via the environment variable set the "AWS_REGION" to the
|
||||
region you want to the SDK to use. Using this method to set the region will
|
||||
allow you to run your application in multiple regions without needing additional
|
||||
code in the application to select the region.
|
||||
|
||||
AWS_REGION=us-west-2
|
||||
|
||||
The endpoints package includes constants for all regions the SDK knows. The
|
||||
values are all suffixed with RegionID. These values are helpful, because they
|
||||
reduce the need to type the region string manually.
|
||||
|
||||
To set the region on a Session use the aws package's Config struct parameter
|
||||
Region to the AWS region you want the service clients created from the session to
|
||||
use. This is helpful when you want to create multiple service clients, and
|
||||
all of the clients make API requests to the same region.
|
||||
|
||||
```go
|
||||
sess := session.Must(session.NewSession(&aws.Config{
|
||||
Region: aws.String(endpoints.UsWest2RegionID),
|
||||
}))
|
||||
```
|
||||
|
||||
See the [endpoints][endpoints_pkg] package for the AWS Regions and Endpoints metadata.
|
||||
|
||||
In addition to setting the region when creating a Session you can also set
|
||||
the region on a per service client bases. This overrides the region of a
|
||||
Session. This is helpful when you want to create service clients in specific
|
||||
regions different from the Session's region.
|
||||
|
||||
```go
|
||||
svc := s3.New(sess, &aws.Config{
|
||||
Region: aws.String(endpoints.UsWest2RegionID),
|
||||
})
|
||||
```
|
||||
|
||||
See the [Config][config_typ] type in the [aws][aws_pkg] package for more information and additional
|
||||
options such as setting the Endpoint, and other service client configuration options.
|
||||
|
||||
[endpoints_pkg]: https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/
|
||||
|
||||
## Making API Requests
|
||||
|
||||
Once the client is created you can make an API request to the service.
|
||||
Each API method takes a input parameter, and returns the service response
|
||||
and an error. The SDK provides methods for making the API call in multiple ways.
|
||||
|
||||
In this list we'll use the S3 ListObjects API as an example for the different
|
||||
ways of making API requests.
|
||||
|
||||
* ListObjects - Base API operation that will make the API request to the service.
|
||||
|
||||
* ListObjectsRequest - API methods suffixed with Request will construct the
|
||||
API request, but not send it. This is also helpful when you want to get a
|
||||
presigned URL for a request, and share the presigned URL instead of your
|
||||
application making the request directly.
|
||||
|
||||
* ListObjectsPages - Same as the base API operation, but uses a callback to
|
||||
automatically handle pagination of the API's response.
|
||||
|
||||
* ListObjectsWithContext - Same as base API operation, but adds support for
|
||||
the Context pattern. This is helpful for controlling the canceling of in
|
||||
flight requests. See the Go standard library context package for more
|
||||
information. This method also takes request package's Option functional
|
||||
options as the variadic argument for modifying how the request will be
|
||||
made, or extracting information from the raw HTTP response.
|
||||
|
||||
* ListObjectsPagesWithContext - same as ListObjectsPages, but adds support for
|
||||
the Context pattern. Similar to ListObjectsWithContext this method also
|
||||
takes the request package's Option function option types as the variadic
|
||||
argument.
|
||||
|
||||
In addition to the API operations the SDK also includes several higher level
|
||||
methods that abstract checking for and waiting for an AWS resource to be in
|
||||
a desired state. In this list we'll use WaitUntilBucketExists to demonstrate
|
||||
the different forms of waiters.
|
||||
|
||||
* WaitUntilBucketExists. - Method to make API request to query an AWS service for
|
||||
a resource's state. Will return successfully when that state is accomplished.
|
||||
|
||||
* WaitUntilBucketExistsWithContext - Same as WaitUntilBucketExists, but adds
|
||||
support for the Context pattern. In addition these methods take request
|
||||
package's WaiterOptions to configure the waiter, and how underlying request
|
||||
will be made by the SDK.
|
||||
|
||||
The API method will document which error codes the service might return for
|
||||
the operation. These errors will also be available as const strings prefixed
|
||||
with "ErrCode" in the service client's package. If there are no errors listed
|
||||
in the API's SDK documentation you'll need to consult the AWS service's API
|
||||
documentation for the errors that could be returned.
|
||||
|
||||
```go
|
||||
ctx := context.Background()
|
||||
|
||||
result, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
|
||||
Bucket: aws.String("my-bucket"),
|
||||
Key: aws.String("my-key"),
|
||||
})
|
||||
if err != nil {
|
||||
// Cast err to awserr.Error to handle specific error codes.
|
||||
aerr, ok := err.(awserr.Error)
|
||||
if ok && aerr.Code() == s3.ErrCodeNoSuchKey {
|
||||
// Specific error code handling
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure to close the body when done with it for S3 GetObject APIs or
|
||||
// will leak connections.
|
||||
defer result.Body.Close()
|
||||
|
||||
fmt.Println("Object Size:", aws.Int64Value(result.ContentLength))
|
||||
```
|
||||
|
||||
### API Request Pagination and Resource Waiters
|
||||
|
||||
Pagination helper methods are suffixed with "Pages", and provide the
|
||||
functionality needed to round trip API page requests. Pagination methods
|
||||
take a callback function that will be called for each page of the API's response.
|
||||
|
||||
```go
|
||||
objects := []string{}
|
||||
err := svc.ListObjectsPagesWithContext(ctx, &s3.ListObjectsInput{
|
||||
Bucket: aws.String(myBucket),
|
||||
}, func(p *s3.ListObjectsOutput, lastPage bool) bool {
|
||||
for _, o := range p.Contents {
|
||||
objects = append(objects, aws.StringValue(o.Key))
|
||||
}
|
||||
return true // continue paging
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to list objects for bucket, %s, %v", myBucket, err))
|
||||
}
|
||||
|
||||
fmt.Println("Objects in bucket:", objects)
|
||||
```
|
||||
|
||||
Waiter helper methods provide the functionality to wait for an AWS resource
|
||||
state. These methods abstract the logic needed to check the state of an
|
||||
AWS resource, and wait until that resource is in a desired state. The waiter
|
||||
will block until the resource is in the state that is desired, an error occurs,
|
||||
or the waiter times out. If a resource times out the error code returned will
|
||||
be request.WaiterResourceNotReadyErrorCode.
|
||||
|
||||
```go
|
||||
err := svc.WaitUntilBucketExistsWithContext(ctx, &s3.HeadBucketInput{
|
||||
Bucket: aws.String(myBucket),
|
||||
})
|
||||
if err != nil {
|
||||
aerr, ok := err.(awserr.Error)
|
||||
if ok && aerr.Code() == request.WaiterResourceNotReadyErrorCode {
|
||||
fmt.Fprintf(os.Stderr, "timed out while waiting for bucket to exist")
|
||||
}
|
||||
panic(fmt.Errorf("failed to wait for bucket to exist, %v", err))
|
||||
}
|
||||
fmt.Println("Bucket", myBucket, "exists")
|
||||
```
|
||||
|
||||
## Complete SDK Example
|
||||
|
||||
This example shows a complete working Go file which will upload a file to S3
|
||||
and use the Context pattern to implement timeout logic that will cancel the
|
||||
request if it takes too long. This example highlights how to use sessions,
|
||||
create a service client, make a request, handle the error, and process the
|
||||
response.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
// Uploads a file to S3 given a bucket and object key. Also takes a duration
|
||||
// value to terminate the update if it doesn't complete within that time.
|
||||
//
|
||||
// The AWS Region needs to be provided in the AWS shared config or on the
|
||||
// environment variable as `AWS_REGION`. Credentials also must be provided
|
||||
// Will default to shared config file, but can load from environment if provided.
|
||||
//
|
||||
// Usage:
|
||||
// # Upload myfile.txt to myBucket/myKey. Must complete within 10 minutes or will fail
|
||||
// go run withContext.go -b mybucket -k myKey -d 10m < myfile.txt
|
||||
func main() {
|
||||
var bucket, key string
|
||||
var timeout time.Duration
|
||||
|
||||
flag.StringVar(&bucket, "b", "", "Bucket name.")
|
||||
flag.StringVar(&key, "k", "", "Object key name.")
|
||||
flag.DurationVar(&timeout, "d", 0, "Upload timeout.")
|
||||
flag.Parse()
|
||||
|
||||
// All clients require a Session. The Session provides the client with
|
||||
// shared configuration such as region, endpoint, and credentials. A
|
||||
// Session should be shared where possible to take advantage of
|
||||
// configuration and credential caching. See the session package for
|
||||
// more information.
|
||||
sess := session.Must(session.NewSession())
|
||||
|
||||
// Create a new instance of the service's client with a Session.
|
||||
// Optional aws.Config values can also be provided as variadic arguments
|
||||
// to the New function. This option allows you to provide service
|
||||
// specific configuration.
|
||||
svc := s3.New(sess)
|
||||
|
||||
// Create a context with a timeout that will abort the upload if it takes
|
||||
// more than the passed in timeout.
|
||||
ctx := context.Background()
|
||||
var cancelFn func()
|
||||
if timeout > 0 {
|
||||
ctx, cancelFn = context.WithTimeout(ctx, timeout)
|
||||
}
|
||||
// Ensure the context is canceled to prevent leaking.
|
||||
// See context package for more information, https://golang.org/pkg/context/
|
||||
defer cancelFn()
|
||||
|
||||
// Uploads the object to S3. The Context will interrupt the request if the
|
||||
// timeout expires.
|
||||
_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: aws.String(key),
|
||||
Body: os.Stdin,
|
||||
})
|
||||
if err != nil {
|
||||
if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode {
|
||||
// If the SDK can determine the request or retry delay was canceled
|
||||
// by a context the CanceledErrorCode error code will be returned.
|
||||
fmt.Fprintf(os.Stderr, "upload canceled due to timeout, %v\n", err)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "failed to upload object, %v\n", err)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("successfully uploaded file to %s/%s\n", bucket, key)
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user