Bump version of lego to 1.0.1

This commit is contained in:
Dmitry
2018-06-10 09:43:45 +03:00
committed by Dmitry NN
parent 58248b9410
commit eb89fad573
319 changed files with 23923 additions and 49697 deletions
Executable → Regular
View File
+1 -1
View File
@@ -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 && \
+1 -1
View File
@@ -1 +1 @@
v0.5.0
v1.0.0
+14 -19
View File
@@ -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
View File
@@ -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
View File
@@ -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 && \
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
make deps && make -j 4 build
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
env
exec "$@" &
wait
+48
View File
@@ -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
View File
@@ -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
View File
@@ -8,7 +8,7 @@ _obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
# *.[568vq]
[568vq].out
*.cgo1.go
+24 -22
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1,5 @@
Microsoft Azure-SDK-for-Go
Copyright 2014-2017 Microsoft
This product includes software developed at
the Microsoft Corporation (https://www.microsoft.com).
+282 -40
View File
@@ -1,59 +1,301 @@
# Microsoft Azure SDK for Go
[![GoDoc](https://godoc.org/github.com/Azure/azure-sdk-for-go?status.svg)](https://godoc.org/github.com/Azure/azure-sdk-for-go)
[![Build Status](https://travis-ci.org/Azure/azure-sdk-for-go.svg?branch=master)](https://travis-ci.org/Azure/azure-sdk-for-go)
# Azure SDK for Go
[![godoc](https://godoc.org/github.com/Azure/azure-sdk-for-go?status.svg)](https://godoc.org/github.com/Azure/azure-sdk-for-go)
[![Build Status](https://travis-ci.org/Azure/azure-sdk-for-go.svg?branch=master)](https://travis-ci.org/Azure/azure-sdk-for-go)
[![Go Report Card](https://goreportcard.com/badge/github.com/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
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1 @@
dirname $(find | grep _test.go | grep -v vendor) | sort -u
-63
View File
@@ -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
View File
@@ -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 Regular → Executable
View File
@@ -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,
@@ -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
}
@@ -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
@@ -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
}
@@ -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
View File
@@ -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
View File
@@ -0,0 +1,21 @@
package version
// Copyright (c) Microsoft and contributors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Code generated by Microsoft (R) AutoRest Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
// Number contains the semantic version of this SDK.
const Number = "v17.3.0"
+2
View File
@@ -7,6 +7,8 @@
# Folders
_obj
_test
.DS_Store
.idea/
# Architecture specific extensions/prefixes
*.[568vq]
+17 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -1,11 +1,22 @@
# go-autorest
[![GoDoc](https://godoc.org/github.com/Azure/go-autorest/autorest?status.png)](https://godoc.org/github.com/Azure/go-autorest/autorest) [![Build Status](https://travis-ci.org/Azure/go-autorest.svg?branch=master)](https://travis-ci.org/Azure/go-autorest) [![Go Report Card](https://goreportcard.com/badge/Azure/go-autorest)](https://goreportcard.com/report/Azure/go-autorest)
[![GoDoc](https://godoc.org/github.com/Azure/go-autorest/autorest?status.png)](https://godoc.org/github.com/Azure/go-autorest/autorest)
[![Build Status](https://travis-ci.org/Azure/go-autorest.svg?branch=master)](https://travis-ci.org/Azure/go-autorest)
[![Go Report Card](https://goreportcard.com/badge/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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
File diff suppressed because it is too large Load Diff
+137 -16
View File
@@ -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
View File
@@ -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
}
@@ -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
View File
@@ -0,0 +1,200 @@
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package azure
import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"time"
"github.com/Azure/go-autorest/autorest"
)
// DoRetryWithRegistration tries to register the resource provider in case it is unregistered.
// It also handles request retries
func DoRetryWithRegistration(client autorest.Client) autorest.SendDecorator {
return func(s autorest.Sender) autorest.Sender {
return autorest.SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
rr := autorest.NewRetriableRequest(r)
for currentAttempt := 0; currentAttempt < client.RetryAttempts; currentAttempt++ {
err = rr.Prepare()
if err != nil {
return resp, err
}
resp, err = autorest.SendWithSender(s, rr.Request(),
autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...),
)
if err != nil {
return resp, err
}
if resp.StatusCode != http.StatusConflict || client.SkipResourceProviderRegistration {
return resp, err
}
var re RequestError
err = autorest.Respond(
resp,
autorest.ByUnmarshallingJSON(&re),
)
if err != nil {
return resp, err
}
err = re
if re.ServiceError != nil && re.ServiceError.Code == "MissingSubscriptionRegistration" {
regErr := register(client, r, re)
if regErr != nil {
return resp, fmt.Errorf("failed auto registering Resource Provider: %s. Original error: %s", regErr, err)
}
}
}
return resp, fmt.Errorf("failed request: %s", err)
})
}
}
func getProvider(re RequestError) (string, error) {
if re.ServiceError != nil && len(re.ServiceError.Details) > 0 {
return re.ServiceError.Details[0]["target"].(string), nil
}
return "", errors.New("provider was not found in the response")
}
func register(client autorest.Client, originalReq *http.Request, re RequestError) error {
subID := getSubscription(originalReq.URL.Path)
if subID == "" {
return errors.New("missing parameter subscriptionID to register resource provider")
}
providerName, err := getProvider(re)
if err != nil {
return fmt.Errorf("missing parameter provider to register resource provider: %s", err)
}
newURL := url.URL{
Scheme: originalReq.URL.Scheme,
Host: originalReq.URL.Host,
}
// taken from the resources SDK
// with almost identical code, this sections are easier to mantain
// It is also not a good idea to import the SDK here
// https://github.com/Azure/azure-sdk-for-go/blob/9f366792afa3e0ddaecdc860e793ba9d75e76c27/arm/resources/resources/providers.go#L252
pathParameters := map[string]interface{}{
"resourceProviderNamespace": autorest.Encode("path", providerName),
"subscriptionId": autorest.Encode("path", subID),
}
const APIVersion = "2016-09-01"
queryParameters := map[string]interface{}{
"api-version": APIVersion,
}
preparer := autorest.CreatePreparer(
autorest.AsPost(),
autorest.WithBaseURL(newURL.String()),
autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}/register", pathParameters),
autorest.WithQueryParameters(queryParameters),
)
req, err := preparer.Prepare(&http.Request{})
if err != nil {
return err
}
req = req.WithContext(originalReq.Context())
resp, err := autorest.SendWithSender(client, req,
autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...),
)
if err != nil {
return err
}
type Provider struct {
RegistrationState *string `json:"registrationState,omitempty"`
}
var provider Provider
err = autorest.Respond(
resp,
WithErrorUnlessStatusCode(http.StatusOK),
autorest.ByUnmarshallingJSON(&provider),
autorest.ByClosing(),
)
if err != nil {
return err
}
// poll for registered provisioning state
now := time.Now()
for err == nil && time.Since(now) < client.PollingDuration {
// taken from the resources SDK
// https://github.com/Azure/azure-sdk-for-go/blob/9f366792afa3e0ddaecdc860e793ba9d75e76c27/arm/resources/resources/providers.go#L45
preparer := autorest.CreatePreparer(
autorest.AsGet(),
autorest.WithBaseURL(newURL.String()),
autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}", pathParameters),
autorest.WithQueryParameters(queryParameters),
)
req, err = preparer.Prepare(&http.Request{})
if err != nil {
return err
}
req = req.WithContext(originalReq.Context())
resp, err := autorest.SendWithSender(client, req,
autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...),
)
if err != nil {
return err
}
err = autorest.Respond(
resp,
WithErrorUnlessStatusCode(http.StatusOK),
autorest.ByUnmarshallingJSON(&provider),
autorest.ByClosing(),
)
if err != nil {
return err
}
if provider.RegistrationState != nil &&
*provider.RegistrationState == "Registered" {
break
}
delayed := autorest.DelayWithRetryAfter(resp, originalReq.Context().Done())
if !delayed && !autorest.DelayForBackoff(client.PollingDelay, 0, originalReq.Context().Done()) {
return originalReq.Context().Err()
}
}
if !(time.Since(now) < client.PollingDuration) {
return errors.New("polling for resource provider registration has exceeded the polling duration")
}
return err
}
func getSubscription(path string) string {
parts := strings.Split(path, "/")
for i, v := range parts {
if v == "subscriptions" && (i+1) < len(parts) {
return parts[i+1]
}
}
return ""
}
+38 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1,52 @@
package autorest
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import (
"bytes"
"io"
"io/ioutil"
"net/http"
)
// NewRetriableRequest returns a wrapper around an HTTP request that support retry logic.
func NewRetriableRequest(req *http.Request) *RetriableRequest {
return &RetriableRequest{req: req}
}
// Request returns the wrapped HTTP request.
func (rr *RetriableRequest) Request() *http.Request {
return rr.req
}
func (rr *RetriableRequest) prepareFromByteReader() (err error) {
// fall back to making a copy (only do this once)
b := []byte{}
if rr.req.ContentLength > 0 {
b = make([]byte, rr.req.ContentLength)
_, err = io.ReadFull(rr.req.Body, b)
if err != nil {
return err
}
} else {
b, err = ioutil.ReadAll(rr.req.Body)
if err != nil {
return err
}
}
rr.br = bytes.NewReader(b)
rr.req.Body = ioutil.NopCloser(rr.br)
return err
}
+54
View File
@@ -0,0 +1,54 @@
// +build !go1.8
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package autorest
import (
"bytes"
"io/ioutil"
"net/http"
)
// RetriableRequest provides facilities for retrying an HTTP request.
type RetriableRequest struct {
req *http.Request
br *bytes.Reader
}
// Prepare signals that the request is about to be sent.
func (rr *RetriableRequest) Prepare() (err error) {
// preserve the request body; this is to support retry logic as
// the underlying transport will always close the reqeust body
if rr.req.Body != nil {
if rr.br != nil {
_, err = rr.br.Seek(0, 0 /*io.SeekStart*/)
rr.req.Body = ioutil.NopCloser(rr.br)
}
if err != nil {
return err
}
if rr.br == nil {
// fall back to making a copy (only do this once)
err = rr.prepareFromByteReader()
}
}
return err
}
func removeRequestBody(req *http.Request) {
req.Body = nil
req.ContentLength = 0
}
+66
View File
@@ -0,0 +1,66 @@
// +build go1.8
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package autorest
import (
"bytes"
"io"
"io/ioutil"
"net/http"
)
// RetriableRequest provides facilities for retrying an HTTP request.
type RetriableRequest struct {
req *http.Request
rc io.ReadCloser
br *bytes.Reader
}
// Prepare signals that the request is about to be sent.
func (rr *RetriableRequest) Prepare() (err error) {
// preserve the request body; this is to support retry logic as
// the underlying transport will always close the reqeust body
if rr.req.Body != nil {
if rr.rc != nil {
rr.req.Body = rr.rc
} else if rr.br != nil {
_, err = rr.br.Seek(0, io.SeekStart)
rr.req.Body = ioutil.NopCloser(rr.br)
}
if err != nil {
return err
}
if rr.req.GetBody != nil {
// this will allow us to preserve the body without having to
// make a copy. note we need to do this on each iteration
rr.rc, err = rr.req.GetBody()
if err != nil {
return err
}
} else if rr.br == nil {
// fall back to making a copy (only do this once)
err = rr.prepareFromByteReader()
}
}
return err
}
func removeRequestBody(req *http.Request) {
req.Body = nil
req.GetBody = nil
req.ContentLength = 0
}
+75 -20
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -1,17 +1,24 @@
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](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:"/>&nbsp;[![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1,11 @@
// +build appengine gopherjs
package logrus
import (
"io"
)
func checkIfTerminal(w io.Writer) bool {
return true
}
+19
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -2,4 +2,4 @@
### SDK Enhancements
### SDK Bugs
### SDK Bugs
+4
View File
@@ -0,0 +1,4 @@
## Code of Conduct
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
opensource-codeofconduct@amazon.com with any additional questions or comments.
+2 -2
View File
@@ -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
View File
@@ -0,0 +1,20 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/go-ini/ini"
packages = ["."]
revision = "300e940a926eb277d3901b20bdfcc54928ad3642"
version = "v1.25.4"
[[projects]]
name = "github.com/jmespath/go-jmespath"
packages = ["."]
revision = "0b12d6b5"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "51a86a867df617990082dec6b868e4efe2fdb2ed0e02a3daa93cd30f962b5085"
solver-name = "gps-cdcl"
solver-version = 1
+48
View File
@@ -0,0 +1,48 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
ignored = [
# Testing/Example/Codegen dependencies
"github.com/stretchr/testify",
"github.com/stretchr/testify/assert",
"github.com/stretchr/testify/require",
"github.com/go-sql-driver/mysql",
"github.com/gucumber/gucumber",
"github.com/pkg/errors",
"golang.org/x/net",
"golang.org/x/net/html",
"golang.org/x/net/http2",
"golang.org/x/text",
"golang.org/x/text/html",
"golang.org/x/tools",
"golang.org/x/tools/go/loader",
]
[[constraint]]
name = "github.com/go-ini/ini"
version = "1.25.4"
[[constraint]]
name = "github.com/jmespath/go-jmespath"
revision = "0b12d6b5"
#version = "0.2.2"
+28 -3
View File
@@ -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
View File
@@ -1,9 +1,13 @@
# AWS SDK for Go [![API Reference](http://img.shields.io/badge/api-reference-blue.svg)](http://docs.aws.amazon.com/sdk-for-go/api) [![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://img.shields.io/travis/aws/aws-sdk-go.svg)](https://travis-ci.org/aws/aws-sdk-go) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
[![API Reference](http://img.shields.io/badge/api-reference-blue.svg)](http://docs.aws.amazon.com/sdk-for-go/api) [![Join the chat at https://gitter.im/aws/aws-sdk-go](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/aws/aws-sdk-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://img.shields.io/travis/aws/aws-sdk-go.svg)](https://travis-ci.org/aws/aws-sdk-go) [![Apache V2 License](http://img.shields.io/badge/license-Apache%20V2-blue.svg)](https://github.com/aws/aws-sdk-go/blob/master/LICENSE.txt)
# 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 youre using. Please also include repro case when appropriate.
If you encounter a bug with the AWS SDK for Go we would like to hear about it. Search the [existing issues](https://github.com/aws/aws-sdk-go/issues) and see if others are also experiencing the issue before opening a new issue. Please include the version of AWS SDK for Go, Go language, and OS youre using. Please also include repro case when appropriate.
The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help]( https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner.
The GitHub issues are intended for bug reports and feature requests. For help and questions with using AWS SDK for GO please make use of the resources listed in the [Getting Help](https://github.com/aws/aws-sdk-go#getting-help) section. Keeping the list of open issues lean will help us respond in a timely manner.
## Reference Documentation
@@ -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