fix: update lego.

This commit is contained in:
Ludovic Fernandez 2018-04-09 18:28:03 +02:00 committed by Traefiker Bot
parent 2d0d320d05
commit b1be062437
48 changed files with 2979 additions and 1076 deletions

18
Gopkg.lock generated
View file

@ -24,8 +24,12 @@
[[projects]]
name = "github.com/Azure/azure-sdk-for-go"
packages = ["arm/dns"]
revision = "f7bb4db3ea4c73dc58bd284c38ea644a79324be0"
packages = [
"services/dns/mgmt/2017-09-01/dns",
"version"
]
revision = "068ec4d616be5b2175509bf1fb3e4c8ea160d5c8"
version = "v15.0.1"
[[projects]]
branch = "master"
@ -45,8 +49,8 @@
"autorest/date",
"autorest/to"
]
revision = "f6be1abbb5abd0517522f850dd785990d373da7e"
version = "v9.0.0"
revision = "9ad9326b278af8fa5cc67c30c0ce9a58cc0862b2"
version = "v10.6.0"
[[projects]]
branch = "master"
@ -312,8 +316,8 @@
[[projects]]
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
revision = "d2709f9f1f31ebcda9651b03077758c1f3a0018c"
version = "v3.0.0"
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
version = "v3.2.0"
[[projects]]
name = "github.com/dnsimple/dnsimple-go"
@ -1274,7 +1278,7 @@
"providers/dns/route53",
"providers/dns/vultr"
]
revision = "2357607e4ddeb93d5364c9ae6571ded32b7d01f1"
revision = "2817d2131186742bc98830c73a5d9c255b3f4537"
source = "github.com/containous/lego"
[[projects]]

View file

@ -1,338 +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.
// 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"`
}

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
@ -29,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,

View file

@ -0,0 +1,763 @@
package dns
// Copyright (c) Microsoft and contributors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Code generated by Microsoft (R) AutoRest Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
import (
"encoding/json"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to"
"net/http"
)
// RecordType enumerates the values for record type.
type RecordType string
const (
// A ...
A RecordType = "A"
// AAAA ...
AAAA RecordType = "AAAA"
// CAA ...
CAA RecordType = "CAA"
// CNAME ...
CNAME RecordType = "CNAME"
// MX ...
MX RecordType = "MX"
// NS ...
NS RecordType = "NS"
// PTR ...
PTR RecordType = "PTR"
// SOA ...
SOA RecordType = "SOA"
// SRV ...
SRV RecordType = "SRV"
// TXT ...
TXT RecordType = "TXT"
)
// PossibleRecordTypeValues returns an array of possible values for the RecordType const type.
func PossibleRecordTypeValues() []RecordType {
return []RecordType{A, AAAA, CAA, CNAME, MX, NS, PTR, SOA, SRV, TXT}
}
// AaaaRecord an AAAA record.
type AaaaRecord struct {
// Ipv6Address - The IPv6 address of this AAAA record.
Ipv6Address *string `json:"ipv6Address,omitempty"`
}
// ARecord an A record.
type ARecord struct {
// Ipv4Address - The IPv4 address of this A record.
Ipv4Address *string `json:"ipv4Address,omitempty"`
}
// CaaRecord a CAA record.
type CaaRecord struct {
// Flags - The flags for this CAA record as an integer between 0 and 255.
Flags *int32 `json:"flags,omitempty"`
// Tag - The tag for this CAA record.
Tag *string `json:"tag,omitempty"`
// Value - The value for this CAA record.
Value *string `json:"value,omitempty"`
}
// CloudError an error message
type CloudError struct {
// Error - The error message body
Error *CloudErrorBody `json:"error,omitempty"`
}
// CloudErrorBody the body of an error message
type CloudErrorBody struct {
// Code - The error code
Code *string `json:"code,omitempty"`
// Message - A description of what caused the error
Message *string `json:"message,omitempty"`
// Target - The target resource of the error message
Target *string `json:"target,omitempty"`
// Details - Extra error information
Details *[]CloudErrorBody `json:"details,omitempty"`
}
// CnameRecord a CNAME record.
type CnameRecord struct {
// Cname - The canonical name for this CNAME record.
Cname *string `json:"cname,omitempty"`
}
// MxRecord an MX record.
type MxRecord struct {
// Preference - The preference value for this MX record.
Preference *int32 `json:"preference,omitempty"`
// Exchange - The domain name of the mail host for this MX record.
Exchange *string `json:"exchange,omitempty"`
}
// NsRecord an NS record.
type NsRecord struct {
// Nsdname - The name server name for this NS record.
Nsdname *string `json:"nsdname,omitempty"`
}
// PtrRecord a PTR record.
type PtrRecord struct {
// Ptrdname - The PTR target domain name for this PTR record.
Ptrdname *string `json:"ptrdname,omitempty"`
}
// RecordSet describes a DNS record set (a collection of DNS records with the same name and type).
type RecordSet struct {
autorest.Response `json:"-"`
// ID - The ID of the record set.
ID *string `json:"id,omitempty"`
// Name - The name of the record set.
Name *string `json:"name,omitempty"`
// Type - The type of the record set.
Type *string `json:"type,omitempty"`
// Etag - The etag of the record set.
Etag *string `json:"etag,omitempty"`
// RecordSetProperties - The properties of the record set.
*RecordSetProperties `json:"properties,omitempty"`
}
// MarshalJSON is the custom marshaler for RecordSet.
func (rs RecordSet) MarshalJSON() ([]byte, error) {
objectMap := make(map[string]interface{})
if rs.ID != nil {
objectMap["id"] = rs.ID
}
if rs.Name != nil {
objectMap["name"] = rs.Name
}
if rs.Type != nil {
objectMap["type"] = rs.Type
}
if rs.Etag != nil {
objectMap["etag"] = rs.Etag
}
if rs.RecordSetProperties != nil {
objectMap["properties"] = rs.RecordSetProperties
}
return json.Marshal(objectMap)
}
// UnmarshalJSON is the custom unmarshaler for RecordSet struct.
func (rs *RecordSet) UnmarshalJSON(body []byte) error {
var m map[string]*json.RawMessage
err := json.Unmarshal(body, &m)
if err != nil {
return err
}
for k, v := range m {
switch k {
case "id":
if v != nil {
var ID string
err = json.Unmarshal(*v, &ID)
if err != nil {
return err
}
rs.ID = &ID
}
case "name":
if v != nil {
var name string
err = json.Unmarshal(*v, &name)
if err != nil {
return err
}
rs.Name = &name
}
case "type":
if v != nil {
var typeVar string
err = json.Unmarshal(*v, &typeVar)
if err != nil {
return err
}
rs.Type = &typeVar
}
case "etag":
if v != nil {
var etag string
err = json.Unmarshal(*v, &etag)
if err != nil {
return err
}
rs.Etag = &etag
}
case "properties":
if v != nil {
var recordSetProperties RecordSetProperties
err = json.Unmarshal(*v, &recordSetProperties)
if err != nil {
return err
}
rs.RecordSetProperties = &recordSetProperties
}
}
}
return nil
}
// RecordSetListResult the response to a record set List operation.
type RecordSetListResult struct {
autorest.Response `json:"-"`
// Value - Information about the record sets in the response.
Value *[]RecordSet `json:"value,omitempty"`
// NextLink - The continuation token for the next page of results.
NextLink *string `json:"nextLink,omitempty"`
}
// RecordSetListResultIterator provides access to a complete listing of RecordSet values.
type RecordSetListResultIterator struct {
i int
page RecordSetListResultPage
}
// Next advances to the next value. If there was an error making
// the request the iterator does not advance and the error is returned.
func (iter *RecordSetListResultIterator) Next() error {
iter.i++
if iter.i < len(iter.page.Values()) {
return nil
}
err := iter.page.Next()
if err != nil {
iter.i--
return err
}
iter.i = 0
return nil
}
// NotDone returns true if the enumeration should be started or is not yet complete.
func (iter RecordSetListResultIterator) NotDone() bool {
return iter.page.NotDone() && iter.i < len(iter.page.Values())
}
// Response returns the raw server response from the last page request.
func (iter RecordSetListResultIterator) Response() RecordSetListResult {
return iter.page.Response()
}
// Value returns the current value or a zero-initialized value if the
// iterator has advanced beyond the end of the collection.
func (iter RecordSetListResultIterator) Value() RecordSet {
if !iter.page.NotDone() {
return RecordSet{}
}
return iter.page.Values()[iter.i]
}
// IsEmpty returns true if the ListResult contains no values.
func (rslr RecordSetListResult) IsEmpty() bool {
return rslr.Value == nil || len(*rslr.Value) == 0
}
// recordSetListResultPreparer prepares a request to retrieve the next set of results.
// It returns nil if no more results exist.
func (rslr RecordSetListResult) recordSetListResultPreparer() (*http.Request, error) {
if rslr.NextLink == nil || len(to.String(rslr.NextLink)) < 1 {
return nil, nil
}
return autorest.Prepare(&http.Request{},
autorest.AsJSON(),
autorest.AsGet(),
autorest.WithBaseURL(to.String(rslr.NextLink)))
}
// RecordSetListResultPage contains a page of RecordSet values.
type RecordSetListResultPage struct {
fn func(RecordSetListResult) (RecordSetListResult, error)
rslr RecordSetListResult
}
// Next advances to the next page of values. If there was an error making
// the request the page does not advance and the error is returned.
func (page *RecordSetListResultPage) Next() error {
next, err := page.fn(page.rslr)
if err != nil {
return err
}
page.rslr = next
return nil
}
// NotDone returns true if the page enumeration should be started or is not yet complete.
func (page RecordSetListResultPage) NotDone() bool {
return !page.rslr.IsEmpty()
}
// Response returns the raw server response from the last page request.
func (page RecordSetListResultPage) Response() RecordSetListResult {
return page.rslr
}
// Values returns the slice of values for the current page or nil if there are no values.
func (page RecordSetListResultPage) Values() []RecordSet {
if page.rslr.IsEmpty() {
return nil
}
return *page.rslr.Value
}
// RecordSetProperties represents the properties of the records in the record set.
type RecordSetProperties struct {
// Metadata - The metadata attached to the record set.
Metadata map[string]*string `json:"metadata"`
// TTL - The TTL (time-to-live) of the records in the record set.
TTL *int64 `json:"TTL,omitempty"`
// Fqdn - Fully qualified domain name of the record set.
Fqdn *string `json:"fqdn,omitempty"`
// ARecords - The list of A records in the record set.
ARecords *[]ARecord `json:"ARecords,omitempty"`
// AaaaRecords - The list of AAAA records in the record set.
AaaaRecords *[]AaaaRecord `json:"AAAARecords,omitempty"`
// MxRecords - The list of MX records in the record set.
MxRecords *[]MxRecord `json:"MXRecords,omitempty"`
// NsRecords - The list of NS records in the record set.
NsRecords *[]NsRecord `json:"NSRecords,omitempty"`
// PtrRecords - The list of PTR records in the record set.
PtrRecords *[]PtrRecord `json:"PTRRecords,omitempty"`
// SrvRecords - The list of SRV records in the record set.
SrvRecords *[]SrvRecord `json:"SRVRecords,omitempty"`
// TxtRecords - The list of TXT records in the record set.
TxtRecords *[]TxtRecord `json:"TXTRecords,omitempty"`
// CnameRecord - The CNAME record in the record set.
CnameRecord *CnameRecord `json:"CNAMERecord,omitempty"`
// SoaRecord - The SOA record in the record set.
SoaRecord *SoaRecord `json:"SOARecord,omitempty"`
// CaaRecords - The list of CAA records in the record set.
CaaRecords *[]CaaRecord `json:"caaRecords,omitempty"`
}
// MarshalJSON is the custom marshaler for RecordSetProperties.
func (rsp RecordSetProperties) MarshalJSON() ([]byte, error) {
objectMap := make(map[string]interface{})
if rsp.Metadata != nil {
objectMap["metadata"] = rsp.Metadata
}
if rsp.TTL != nil {
objectMap["TTL"] = rsp.TTL
}
if rsp.Fqdn != nil {
objectMap["fqdn"] = rsp.Fqdn
}
if rsp.ARecords != nil {
objectMap["ARecords"] = rsp.ARecords
}
if rsp.AaaaRecords != nil {
objectMap["AAAARecords"] = rsp.AaaaRecords
}
if rsp.MxRecords != nil {
objectMap["MXRecords"] = rsp.MxRecords
}
if rsp.NsRecords != nil {
objectMap["NSRecords"] = rsp.NsRecords
}
if rsp.PtrRecords != nil {
objectMap["PTRRecords"] = rsp.PtrRecords
}
if rsp.SrvRecords != nil {
objectMap["SRVRecords"] = rsp.SrvRecords
}
if rsp.TxtRecords != nil {
objectMap["TXTRecords"] = rsp.TxtRecords
}
if rsp.CnameRecord != nil {
objectMap["CNAMERecord"] = rsp.CnameRecord
}
if rsp.SoaRecord != nil {
objectMap["SOARecord"] = rsp.SoaRecord
}
if rsp.CaaRecords != nil {
objectMap["caaRecords"] = rsp.CaaRecords
}
return json.Marshal(objectMap)
}
// RecordSetUpdateParameters parameters supplied to update a record set.
type RecordSetUpdateParameters struct {
// RecordSet - Specifies information about the record set being updated.
RecordSet *RecordSet `json:"RecordSet,omitempty"`
}
// Resource common properties of an Azure Resource Manager resource
type Resource struct {
// ID - Resource ID.
ID *string `json:"id,omitempty"`
// Name - Resource name.
Name *string `json:"name,omitempty"`
// Type - Resource type.
Type *string `json:"type,omitempty"`
// Location - Resource location.
Location *string `json:"location,omitempty"`
// Tags - Resource tags.
Tags map[string]*string `json:"tags"`
}
// MarshalJSON is the custom marshaler for Resource.
func (r Resource) MarshalJSON() ([]byte, error) {
objectMap := make(map[string]interface{})
if r.ID != nil {
objectMap["id"] = r.ID
}
if r.Name != nil {
objectMap["name"] = r.Name
}
if r.Type != nil {
objectMap["type"] = r.Type
}
if r.Location != nil {
objectMap["location"] = r.Location
}
if r.Tags != nil {
objectMap["tags"] = r.Tags
}
return json.Marshal(objectMap)
}
// SoaRecord an SOA record.
type SoaRecord struct {
// Host - The domain name of the authoritative name server for this SOA record.
Host *string `json:"host,omitempty"`
// Email - The email contact for this SOA record.
Email *string `json:"email,omitempty"`
// SerialNumber - The serial number for this SOA record.
SerialNumber *int64 `json:"serialNumber,omitempty"`
// RefreshTime - The refresh value for this SOA record.
RefreshTime *int64 `json:"refreshTime,omitempty"`
// RetryTime - The retry time for this SOA record.
RetryTime *int64 `json:"retryTime,omitempty"`
// ExpireTime - The expire time for this SOA record.
ExpireTime *int64 `json:"expireTime,omitempty"`
// MinimumTTL - The minimum value for this SOA record. By convention this is used to determine the negative caching duration.
MinimumTTL *int64 `json:"minimumTTL,omitempty"`
}
// SrvRecord an SRV record.
type SrvRecord struct {
// Priority - The priority value for this SRV record.
Priority *int32 `json:"priority,omitempty"`
// Weight - The weight value for this SRV record.
Weight *int32 `json:"weight,omitempty"`
// Port - The port value for this SRV record.
Port *int32 `json:"port,omitempty"`
// Target - The target domain name for this SRV record.
Target *string `json:"target,omitempty"`
}
// SubResource a reference to a another resource
type SubResource struct {
// ID - Resource Id.
ID *string `json:"id,omitempty"`
}
// TxtRecord a TXT record.
type TxtRecord struct {
// Value - The text value of this TXT record.
Value *[]string `json:"value,omitempty"`
}
// Zone describes a DNS zone.
type Zone struct {
autorest.Response `json:"-"`
// Etag - The etag of the zone.
Etag *string `json:"etag,omitempty"`
// ZoneProperties - The properties of the zone.
*ZoneProperties `json:"properties,omitempty"`
// ID - Resource ID.
ID *string `json:"id,omitempty"`
// Name - Resource name.
Name *string `json:"name,omitempty"`
// Type - Resource type.
Type *string `json:"type,omitempty"`
// Location - Resource location.
Location *string `json:"location,omitempty"`
// Tags - Resource tags.
Tags map[string]*string `json:"tags"`
}
// MarshalJSON is the custom marshaler for Zone.
func (z Zone) MarshalJSON() ([]byte, error) {
objectMap := make(map[string]interface{})
if z.Etag != nil {
objectMap["etag"] = z.Etag
}
if z.ZoneProperties != nil {
objectMap["properties"] = z.ZoneProperties
}
if z.ID != nil {
objectMap["id"] = z.ID
}
if z.Name != nil {
objectMap["name"] = z.Name
}
if z.Type != nil {
objectMap["type"] = z.Type
}
if z.Location != nil {
objectMap["location"] = z.Location
}
if z.Tags != nil {
objectMap["tags"] = z.Tags
}
return json.Marshal(objectMap)
}
// UnmarshalJSON is the custom unmarshaler for Zone struct.
func (z *Zone) UnmarshalJSON(body []byte) error {
var m map[string]*json.RawMessage
err := json.Unmarshal(body, &m)
if err != nil {
return err
}
for k, v := range m {
switch k {
case "etag":
if v != nil {
var etag string
err = json.Unmarshal(*v, &etag)
if err != nil {
return err
}
z.Etag = &etag
}
case "properties":
if v != nil {
var zoneProperties ZoneProperties
err = json.Unmarshal(*v, &zoneProperties)
if err != nil {
return err
}
z.ZoneProperties = &zoneProperties
}
case "id":
if v != nil {
var ID string
err = json.Unmarshal(*v, &ID)
if err != nil {
return err
}
z.ID = &ID
}
case "name":
if v != nil {
var name string
err = json.Unmarshal(*v, &name)
if err != nil {
return err
}
z.Name = &name
}
case "type":
if v != nil {
var typeVar string
err = json.Unmarshal(*v, &typeVar)
if err != nil {
return err
}
z.Type = &typeVar
}
case "location":
if v != nil {
var location string
err = json.Unmarshal(*v, &location)
if err != nil {
return err
}
z.Location = &location
}
case "tags":
if v != nil {
var tags map[string]*string
err = json.Unmarshal(*v, &tags)
if err != nil {
return err
}
z.Tags = tags
}
}
}
return nil
}
// ZoneListResult the response to a Zone List or ListAll operation.
type ZoneListResult struct {
autorest.Response `json:"-"`
// Value - Information about the DNS zones.
Value *[]Zone `json:"value,omitempty"`
// NextLink - The continuation token for the next page of results.
NextLink *string `json:"nextLink,omitempty"`
}
// ZoneListResultIterator provides access to a complete listing of Zone values.
type ZoneListResultIterator struct {
i int
page ZoneListResultPage
}
// Next advances to the next value. If there was an error making
// the request the iterator does not advance and the error is returned.
func (iter *ZoneListResultIterator) Next() error {
iter.i++
if iter.i < len(iter.page.Values()) {
return nil
}
err := iter.page.Next()
if err != nil {
iter.i--
return err
}
iter.i = 0
return nil
}
// NotDone returns true if the enumeration should be started or is not yet complete.
func (iter ZoneListResultIterator) NotDone() bool {
return iter.page.NotDone() && iter.i < len(iter.page.Values())
}
// Response returns the raw server response from the last page request.
func (iter ZoneListResultIterator) Response() ZoneListResult {
return iter.page.Response()
}
// Value returns the current value or a zero-initialized value if the
// iterator has advanced beyond the end of the collection.
func (iter ZoneListResultIterator) Value() Zone {
if !iter.page.NotDone() {
return Zone{}
}
return iter.page.Values()[iter.i]
}
// IsEmpty returns true if the ListResult contains no values.
func (zlr ZoneListResult) IsEmpty() bool {
return zlr.Value == nil || len(*zlr.Value) == 0
}
// zoneListResultPreparer prepares a request to retrieve the next set of results.
// It returns nil if no more results exist.
func (zlr ZoneListResult) zoneListResultPreparer() (*http.Request, error) {
if zlr.NextLink == nil || len(to.String(zlr.NextLink)) < 1 {
return nil, nil
}
return autorest.Prepare(&http.Request{},
autorest.AsJSON(),
autorest.AsGet(),
autorest.WithBaseURL(to.String(zlr.NextLink)))
}
// ZoneListResultPage contains a page of Zone values.
type ZoneListResultPage struct {
fn func(ZoneListResult) (ZoneListResult, error)
zlr ZoneListResult
}
// Next advances to the next page of values. If there was an error making
// the request the page does not advance and the error is returned.
func (page *ZoneListResultPage) Next() error {
next, err := page.fn(page.zlr)
if err != nil {
return err
}
page.zlr = next
return nil
}
// NotDone returns true if the page enumeration should be started or is not yet complete.
func (page ZoneListResultPage) NotDone() bool {
return !page.zlr.IsEmpty()
}
// Response returns the raw server response from the last page request.
func (page ZoneListResultPage) Response() ZoneListResult {
return page.zlr
}
// Values returns the slice of values for the current page or nil if there are no values.
func (page ZoneListResultPage) Values() []Zone {
if page.zlr.IsEmpty() {
return nil
}
return *page.zlr.Value
}
// ZoneProperties represents the properties of the zone.
type ZoneProperties struct {
// MaxNumberOfRecordSets - The maximum number of record sets that can be created in this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
MaxNumberOfRecordSets *int64 `json:"maxNumberOfRecordSets,omitempty"`
// NumberOfRecordSets - The current number of record sets in this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
NumberOfRecordSets *int64 `json:"numberOfRecordSets,omitempty"`
// NameServers - The name servers for this DNS zone. This is a read-only property and any attempt to set this value will be ignored.
NameServers *[]string `json:"nameServers,omitempty"`
}
// ZonesDeleteFuture an abstraction for monitoring and retrieving the results of a long-running operation.
type ZonesDeleteFuture struct {
azure.Future
req *http.Request
}
// Result returns the result of the asynchronous operation.
// If the operation has not completed it will return an error.
func (future ZonesDeleteFuture) Result(client ZonesClient) (ar autorest.Response, err error) {
var done bool
done, err = future.Done(client)
if err != nil {
err = autorest.NewErrorWithError(err, "dns.ZonesDeleteFuture", "Result", future.Response(), "Polling failure")
return
}
if !done {
return ar, azure.NewAsyncOpIncompleteError("dns.ZonesDeleteFuture")
}
if future.PollingMethod() == azure.PollingLocation {
ar, err = client.DeleteResponder(future.Response())
if err != nil {
err = autorest.NewErrorWithError(err, "dns.ZonesDeleteFuture", "Result", future.Response(), "Failure responding to request")
}
return
}
var req *http.Request
var resp *http.Response
if future.PollingURL() != "" {
req, err = http.NewRequest(http.MethodGet, future.PollingURL(), nil)
if err != nil {
return
}
} else {
req = autorest.ChangeToGet(future.req)
}
resp, err = autorest.SendWithSender(client, req,
autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...))
if err != nil {
err = autorest.NewErrorWithError(err, "dns.ZonesDeleteFuture", "Result", resp, "Failure sending request")
return
}
ar, err = client.DeleteResponder(resp)
if err != nil {
err = autorest.NewErrorWithError(err, "dns.ZonesDeleteFuture", "Result", resp, "Failure responding to request")
}
return
}

View file

@ -18,6 +18,7 @@ package dns
// 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"
@ -25,7 +26,7 @@ import (
// RecordSetsClient is the the DNS Management Client.
type RecordSetsClient struct {
ManagementClient
BaseClient
}
// NewRecordSetsClient creates an instance of the RecordSetsClient client.
@ -41,14 +42,14 @@ func NewRecordSetsClientWithBaseURI(baseURI string, subscriptionID string) Recor
// 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)
// 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(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
@ -70,7 +71,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,
@ -79,13 +80,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),
@ -99,13 +100,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
@ -114,7 +116,7 @@ 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}
@ -124,12 +126,12 @@ func (client RecordSetsClient) CreateOrUpdateResponder(resp *http.Response) (res
// 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)
// 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(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
@ -151,7 +153,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,
@ -160,7 +162,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,
}
@ -174,13 +176,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
@ -189,7 +192,7 @@ 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
@ -198,10 +201,10 @@ func (client RecordSetsClient) DeleteResponder(resp *http.Response) (result auto
// 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)
// 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(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
@ -223,7 +226,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,
@ -232,7 +235,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,
}
@ -242,13 +245,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
@ -271,8 +275,9 @@ func (client RecordSetsClient) GetResponder(resp *http.Response) (result RecordS
// recordsetnamesuffix is 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(resourceGroupName string, zoneName string, top *int32, recordsetnamesuffix string) (result RecordSetListResult, err error) {
req, err := client.ListByDNSZonePreparer(resourceGroupName, zoneName, top, 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
@ -280,12 +285,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")
}
@ -294,14 +299,14 @@ func (client RecordSetsClient) ListByDNSZone(resourceGroupName string, zoneName
}
// ListByDNSZonePreparer prepares the ListByDNSZone request.
func (client RecordSetsClient) ListByDNSZonePreparer(resourceGroupName string, zoneName string, top *int32, recordsetnamesuffix string) (*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,
}
@ -317,13 +322,14 @@ func (client RecordSetsClient) ListByDNSZonePreparer(resourceGroupName string, z
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
@ -339,84 +345,43 @@ 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 gets all elements from the list without paging.
func (client RecordSetsClient) ListByDNSZoneComplete(resourceGroupName string, zoneName string, top *int32, recordsetnamesuffix string, cancel <-chan struct{}) (<-chan RecordSet, <-chan error) {
resultChan := make(chan RecordSet)
errChan := make(chan error, 1)
go func() {
defer func() {
close(resultChan)
close(errChan)
}()
list, err := client.ListByDNSZone(resourceGroupName, zoneName, top, recordsetnamesuffix)
if err != nil {
errChan <- err
return
}
if list.Value != nil {
for _, item := range *list.Value {
select {
case <-cancel:
return
case resultChan <- item:
// Intentionally left blank
}
}
}
for list.NextLink != nil {
list, err = client.ListByDNSZoneNextResults(list)
if err != nil {
errChan <- err
return
}
if list.Value != nil {
for _, item := range *list.Value {
select {
case <-cancel:
return
case resultChan <- item:
// Intentionally left blank
}
}
}
}
}()
return resultChan, errChan
// 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. recordsetnamesuffix is 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(resourceGroupName string, zoneName string, recordType RecordType, top *int32, recordsetnamesuffix string) (result RecordSetListResult, err error) {
req, err := client.ListByTypePreparer(resourceGroupName, zoneName, recordType, top, recordsetnamesuffix)
// 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. recordsetnamesuffix is 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
@ -424,12 +389,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")
}
@ -438,7 +403,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, recordsetnamesuffix string) (*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),
@ -446,7 +411,7 @@ 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,
}
@ -462,13 +427,14 @@ func (client RecordSetsClient) ListByTypePreparer(resourceGroupName string, zone
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
@ -484,84 +450,42 @@ 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 gets all elements from the list without paging.
func (client RecordSetsClient) ListByTypeComplete(resourceGroupName string, zoneName string, recordType RecordType, top *int32, recordsetnamesuffix string, cancel <-chan struct{}) (<-chan RecordSet, <-chan error) {
resultChan := make(chan RecordSet)
errChan := make(chan error, 1)
go func() {
defer func() {
close(resultChan)
close(errChan)
}()
list, err := client.ListByType(resourceGroupName, zoneName, recordType, top, recordsetnamesuffix)
if err != nil {
errChan <- err
return
}
if list.Value != nil {
for _, item := range *list.Value {
select {
case <-cancel:
return
case resultChan <- item:
// Intentionally left blank
}
}
}
for list.NextLink != nil {
list, err = client.ListByTypeNextResults(list)
if err != nil {
errChan <- err
return
}
if list.Value != nil {
for _, item := range *list.Value {
select {
case <-cancel:
return
case resultChan <- item:
// Intentionally left blank
}
}
}
}
}()
return resultChan, errChan
// 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)
// 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(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
@ -583,7 +507,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,
@ -592,13 +516,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),
@ -608,13 +532,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

View file

@ -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");
@ -19,10 +21,10 @@ package dns
// UserAgent returns the UserAgent string to use when sending http.Requests.
func UserAgent() string {
return "Azure-SDK-For-Go/v11.0.0-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 "v11.0.0-beta"
return version.Number
}

View file

@ -18,6 +18,7 @@ package dns
// 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"
@ -25,7 +26,7 @@ import (
// ZonesClient is the the DNS Management Client.
type ZonesClient struct {
ManagementClient
BaseClient
}
// NewZonesClient creates an instance of the ZonesClient client.
@ -41,12 +42,12 @@ func NewZonesClientWithBaseURI(baseURI string, subscriptionID string) ZonesClien
// 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)
// 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(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
@ -68,20 +69,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),
@ -95,13 +96,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
@ -118,56 +120,36 @@ func (client ZonesClient) CreateOrUpdateResponder(resp *http.Response) (result Z
}
// 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.
// undone.
//
// 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() {
if err != nil {
errChan <- err
}
resultChan <- result
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
}
// 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(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,
}
@ -181,27 +163,33 @@ 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) {
sender := autorest.DecorateSender(client, azure.DoRetryWithRegistration(client.Client))
future.Future = azure.NewFuture(req)
future.req = req
_, err = future.Done(sender)
if err != nil {
return
}
err = autorest.Respond(future.Response(),
azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent))
return
}
// DeleteResponder handles the response to the Delete request. The method always
// closes the http.Response Body.
func (client ZonesClient) DeleteResponder(resp *http.Response) (result 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
}
@ -209,8 +197,8 @@ func (client ZonesClient) DeleteResponder(resp *http.Response) (result ZoneDelet
//
// 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)
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
@ -232,14 +220,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,
}
@ -249,13 +237,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
@ -274,8 +263,9 @@ 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)
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
@ -283,12 +273,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")
}
@ -297,12 +287,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,
}
@ -315,13 +305,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
@ -337,81 +328,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 gets all elements from the list without paging.
func (client ZonesClient) ListComplete(top *int32, cancel <-chan struct{}) (<-chan Zone, <-chan error) {
resultChan := make(chan Zone)
errChan := make(chan error, 1)
go func() {
defer func() {
close(resultChan)
close(errChan)
}()
list, err := client.List(top)
if err != nil {
errChan <- err
return
}
if list.Value != nil {
for _, item := range *list.Value {
select {
case <-cancel:
return
case resultChan <- item:
// Intentionally left blank
}
}
}
for list.NextLink != nil {
list, err = client.ListNextResults(list)
if err != nil {
errChan <- err
return
}
if list.Value != nil {
for _, item := range *list.Value {
select {
case <-cancel:
return
case resultChan <- item:
// Intentionally left blank
}
}
}
}
}()
return resultChan, errChan
// 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)
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
@ -419,12 +369,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")
}
@ -433,13 +383,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,
}
@ -452,13 +402,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
@ -474,71 +425,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 gets all elements from the list without paging.
func (client ZonesClient) ListByResourceGroupComplete(resourceGroupName string, top *int32, cancel <-chan struct{}) (<-chan Zone, <-chan error) {
resultChan := make(chan Zone)
errChan := make(chan error, 1)
go func() {
defer func() {
close(resultChan)
close(errChan)
}()
list, err := client.ListByResourceGroup(resourceGroupName, top)
if err != nil {
errChan <- err
return
}
if list.Value != nil {
for _, item := range *list.Value {
select {
case <-cancel:
return
case resultChan <- item:
// Intentionally left blank
}
}
}
for list.NextLink != nil {
list, err = client.ListByResourceGroupNextResults(list)
if err != nil {
errChan <- err
return
}
if list.Value != nil {
for _, item := range *list.Value {
select {
case <-cancel:
return
case resultChan <- item:
// Intentionally left blank
}
}
}
}
}()
return resultChan, errChan
// 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
}

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 = "v15.0.1"

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"
@ -18,8 +32,24 @@ type OAuthConfig struct {
DeviceCodeEndpoint url.URL
}
// IsZero returns true if the OAuthConfig object is zero-initialized.
func (oac OAuthConfig) IsZero() bool {
return oac == OAuthConfig{}
}
func validateStringParam(param, name string) error {
if len(param) == 0 {
return fmt.Errorf("parameter '" + name + "' cannot be empty")
}
return nil
}
// NewOAuthConfig returns an OAuthConfig with tenant specific urls
func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
if err := validateStringParam(activeDirectoryEndpoint, "activeDirectoryEndpoint"); err != nil {
return nil, err
}
// it's legal for tenantID to be empty so don't validate it
const activeDirectoryEndpointTemplate = "%s/oauth2/%s?api-version=%s"
u, err := url.Parse(activeDirectoryEndpoint)
if err != nil {

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

View file

@ -1,6 +0,0 @@
// +build !windows
package adal
// msiPath is the path to the MSI Extension settings file (to discover the endpoint)
var msiPath = "/var/lib/waagent/ManagedIdentity-Settings"

View file

@ -1,11 +0,0 @@
// +build windows
package adal
import (
"os"
"strings"
)
// msiPath is the path to the MSI Extension settings file (to discover the endpoint)
var msiPath = strings.Join([]string{os.Getenv("SystemDrive"), "WindowsAzure/Config/ManagedIdentity-Settings"}, "/")

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"

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"
)

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 (
"crypto/rand"
"crypto/rsa"
@ -13,6 +27,7 @@ import (
"net/url"
"strconv"
"strings"
"sync"
"time"
"github.com/Azure/go-autorest/autorest/date"
@ -28,11 +43,20 @@ 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"
// OAuthGrantTypeAuthorizationCode is the "grant_type" identifier used in authorization code flows
OAuthGrantTypeAuthorizationCode = "authorization_code"
// metadataHeader is the header required by MSI extension
metadataHeader = "Metadata"
// msiEndpoint is the well known endpoint for getting MSI authentications tokens
msiEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token"
)
// OAuthTokenProvider is an interface which should be implemented by an access token retriever
@ -40,6 +64,12 @@ 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
@ -64,6 +94,11 @@ 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)
@ -131,6 +166,34 @@ type ServicePrincipalCertificateSecret struct {
type ServicePrincipalMSISecret struct {
}
// ServicePrincipalUsernamePasswordSecret implements ServicePrincipalSecret for username and password auth.
type ServicePrincipalUsernamePasswordSecret struct {
Username string
Password string
}
// ServicePrincipalAuthorizationCodeSecret implements ServicePrincipalSecret for authorization code auth.
type ServicePrincipalAuthorizationCodeSecret struct {
ClientSecret string
AuthorizationCode string
RedirectURI string
}
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
func (secret *ServicePrincipalAuthorizationCodeSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
v.Set("code", secret.AuthorizationCode)
v.Set("client_secret", secret.ClientSecret)
v.Set("redirect_uri", secret.RedirectURI)
return nil
}
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
func (secret *ServicePrincipalUsernamePasswordSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
v.Set("username", secret.Username)
v.Set("password", secret.Password)
return nil
}
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret.
func (msiSecret *ServicePrincipalMSISecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
return nil
@ -183,27 +246,47 @@ func (secret *ServicePrincipalCertificateSecret) SetAuthenticationValues(spt *Se
// ServicePrincipalToken encapsulates a Token created for a Service Principal.
type ServicePrincipalToken struct {
Token
token Token
secret ServicePrincipalSecret
oauthConfig OAuthConfig
clientID string
resource string
autoRefresh bool
refreshLock *sync.RWMutex
refreshWithin time.Duration
sender Sender
refreshCallbacks []TokenRefreshCallback
}
func validateOAuthConfig(oac OAuthConfig) error {
if oac.IsZero() {
return fmt.Errorf("parameter 'oauthConfig' cannot be zero-initialized")
}
return nil
}
// NewServicePrincipalTokenWithSecret create a ServicePrincipalToken using the supplied ServicePrincipalSecret implementation.
func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, resource string, secret ServicePrincipalSecret, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
if err := validateOAuthConfig(oauthConfig); err != nil {
return nil, err
}
if err := validateStringParam(id, "id"); err != nil {
return nil, err
}
if err := validateStringParam(resource, "resource"); err != nil {
return nil, err
}
if secret == nil {
return nil, fmt.Errorf("parameter 'secret' cannot be nil")
}
spt := &ServicePrincipalToken{
oauthConfig: oauthConfig,
secret: secret,
clientID: id,
resource: resource,
autoRefresh: true,
refreshLock: &sync.RWMutex{},
refreshWithin: defaultRefresh,
sender: &http.Client{},
refreshCallbacks: callbacks,
@ -213,6 +296,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,
@ -223,7 +318,7 @@ func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID s
return nil, err
}
spt.Token = token
spt.token = token
return spt, nil
}
@ -231,6 +326,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,
@ -242,8 +349,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,
@ -256,59 +378,163 @@ func NewServicePrincipalTokenFromCertificate(oauthConfig OAuthConfig, clientID s
)
}
// GetMSIVMEndpoint gets the MSI endpoint on Virtual Machines.
func GetMSIVMEndpoint() (string, error) {
return getMSIVMEndpoint(msiPath)
// 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 getMSIVMEndpoint(path string) (string, error) {
// Read MSI settings
bytes, err := ioutil.ReadFile(path)
if err != nil {
return "", err
// 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 {
return "", err
if err := validateStringParam(clientID, "clientID"); err != nil {
return nil, err
}
if err := validateStringParam(clientSecret, "clientSecret"); err != nil {
return nil, err
}
if err := validateStringParam(authorizationCode, "authorizationCode"); err != nil {
return nil, err
}
if err := validateStringParam(redirectURI, "redirectURI"); err != nil {
return nil, err
}
if err := validateStringParam(resource, "resource"); err != nil {
return nil, err
}
return msiSettings.URL, nil
return NewServicePrincipalTokenWithSecret(
oauthConfig,
clientID,
resource,
&ServicePrincipalAuthorizationCodeSecret{
ClientSecret: clientSecret,
AuthorizationCode: authorizationCode,
RedirectURI: redirectURI,
},
callbacks...,
)
}
// GetMSIVMEndpoint gets the MSI endpoint on Virtual Machines.
func GetMSIVMEndpoint() (string, error) {
return msiEndpoint, nil
}
// NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension.
// It will use the system assigned identity when creating the token.
func NewServicePrincipalTokenFromMSI(msiEndpoint, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, callbacks...)
}
// NewServicePrincipalTokenFromMSIWithUserAssignedID creates a ServicePrincipalToken via the MSI VM Extension.
// It will use the specified user assigned identity when creating the token.
func NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, resource string, userAssignedID string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, &userAssignedID, callbacks...)
}
func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedID *string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
if err := validateStringParam(msiEndpoint, "msiEndpoint"); err != nil {
return nil, err
}
if err := validateStringParam(resource, "resource"); err != nil {
return nil, err
}
if userAssignedID != nil {
if err := validateStringParam(*userAssignedID, "userAssignedID"); err != nil {
return nil, err
}
}
// We set the oauth config token endpoint to be MSI's endpoint
msiEndpointURL, err := url.Parse(msiEndpoint)
if err != nil {
return nil, err
}
oauthConfig, err := NewOAuthConfig(msiEndpointURL.String(), "")
if err != nil {
return nil, err
v := url.Values{}
v.Set("resource", resource)
v.Set("api-version", "2018-02-01")
if userAssignedID != nil {
v.Set("client_id", *userAssignedID)
}
msiEndpointURL.RawQuery = v.Encode()
spt := &ServicePrincipalToken{
oauthConfig: *oauthConfig,
oauthConfig: OAuthConfig{
TokenEndpoint: *msiEndpointURL,
},
secret: &ServicePrincipalMSISecret{},
resource: resource,
autoRefresh: true,
refreshLock: &sync.RWMutex{},
refreshWithin: defaultRefresh,
sender: &http.Client{},
refreshCallbacks: callbacks,
}
if userAssignedID != nil {
spt.clientID = *userAssignedID
}
return spt, nil
}
// internal type that implements TokenRefreshError
type tokenRefreshError struct {
message string
resp *http.Response
}
// Error implements the error interface which is part of the TokenRefreshError interface.
func (tre tokenRefreshError) Error() string {
return tre.message
}
// Response implements the TokenRefreshError interface, it returns the raw HTTP response from the refresh operation.
func (tre tokenRefreshError) Response() *http.Response {
return tre.resp
}
func newTokenRefreshError(message string, resp *http.Response) TokenRefreshError {
return tokenRefreshError{message: message, resp: resp}
}
// EnsureFresh will refresh the token if it will expire within the refresh window (as set by
// RefreshWithin) and autoRefresh flag is on.
// 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()
if spt.autoRefresh && spt.token.WillExpireIn(spt.refreshWithin) {
// take the write lock then check to see if the token was already refreshed
spt.refreshLock.Lock()
defer spt.refreshLock.Unlock()
if spt.token.WillExpireIn(spt.refreshWithin) {
return spt.refreshInternal(spt.resource)
}
}
return nil
}
@ -317,7 +543,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.token)
if err != nil {
return fmt.Errorf("adal: TokenRefreshCallback handler failed. Error = '%v'", err)
}
@ -327,43 +553,74 @@ 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 {
spt.refreshLock.Lock()
defer spt.refreshLock.Unlock()
return spt.refreshInternal(spt.resource)
}
// RefreshExchange refreshes the token, but for a different resource.
// This method is not safe for concurrent use and should be syncrhonized.
func (spt *ServicePrincipalToken) RefreshExchange(resource string) error {
spt.refreshLock.Lock()
defer spt.refreshLock.Unlock()
return spt.refreshInternal(resource)
}
func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
v := url.Values{}
v.Set("client_id", spt.clientID)
v.Set("resource", 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.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(resource string) error {
req, err := http.NewRequest(http.MethodPost, spt.oauthConfig.TokenEndpoint.String(), nil)
if err != nil {
return fmt.Errorf("adal: Failed to build the refresh request. Error = '%v'", err)
}
req.ContentLength = int64(len(s))
req.Header.Set(contentType, mimeTypeFormPost)
if !isIMDS(spt.oauthConfig.TokenEndpoint) {
v := url.Values{}
v.Set("client_id", spt.clientID)
v.Set("resource", resource)
if spt.token.RefreshToken != "" {
v.Set("grant_type", OAuthGrantTypeRefreshToken)
v.Set("refresh_token", spt.token.RefreshToken)
} else {
v.Set("grant_type", spt.getGrantType())
err := spt.secret.SetAuthenticationValues(spt, &v)
if err != nil {
return err
}
}
s := v.Encode()
body := ioutil.NopCloser(strings.NewReader(s))
req.ContentLength = int64(len(s))
req.Header.Set(contentType, mimeTypeFormPost)
req.Body = body
}
if _, ok := spt.secret.(*ServicePrincipalMSISecret); ok {
req.Method = http.MethodGet
req.Header.Set(metadataHeader, "true")
}
resp, err := spt.sender.Do(req)
if err != nil {
return fmt.Errorf("adal: Failed to execute the refresh request. Error = '%v'", err)
@ -374,9 +631,9 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
if resp.StatusCode != http.StatusOK {
if err != nil {
return fmt.Errorf("adal: Refresh request failed. Status Code = '%d'. Failed reading response body", resp.StatusCode)
return newTokenRefreshError(fmt.Sprintf("adal: Refresh request failed. Status Code = '%d'. Failed reading response body", resp.StatusCode), resp)
}
return fmt.Errorf("adal: Refresh request failed. Status Code = '%d'. Response body: %s", resp.StatusCode, string(rb))
return newTokenRefreshError(fmt.Sprintf("adal: Refresh request failed. Status Code = '%d'. Response body: %s", resp.StatusCode, string(rb)), resp)
}
if err != nil {
@ -391,7 +648,7 @@ 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.token = token
return spt.InvokeRefreshCallbacks(token)
}
@ -411,3 +668,17 @@ func (spt *ServicePrincipalToken) SetRefreshWithin(d time.Duration) {
// SetSender sets the http.Client used when obtaining the Service Principal token. An
// undecorated http.Client is used by default.
func (spt *ServicePrincipalToken) SetSender(s Sender) { spt.sender = s }
// OAuthToken implements the OAuthTokenProvider interface. It returns the current access token.
func (spt *ServicePrincipalToken) OAuthToken() string {
spt.refreshLock.RLock()
defer spt.refreshLock.RUnlock()
return spt.token.OAuthToken()
}
// Token returns a copy of the current token.
func (spt *ServicePrincipalToken) Token() Token {
spt.refreshLock.RLock()
defer spt.refreshLock.RUnlock()
return spt.token
}

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"
@ -10,9 +24,12 @@ import (
)
const (
bearerChallengeHeader = "Www-Authenticate"
bearer = "Bearer"
tenantID = "tenantID"
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
@ -30,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
@ -40,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.
//
@ -51,15 +111,23 @@ 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()
if err != nil {
return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", nil,
"Failed to refresh the Token for request to %s", r.URL)
r, err := p.Prepare(r)
if err == nil {
refresher, ok := ba.tokenProvider.(adal.Refresher)
if ok {
err := refresher.EnsureFresh()
if err != nil {
var resp *http.Response
if tokError, ok := err.(adal.TokenRefreshError); ok {
resp = tokError.Response()
}
return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", resp,
"Failed to refresh the Token for request to %s", r.URL)
}
}
return Prepare(r, WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", ba.tokenProvider.OAuthToken())))
}
return (ba.withBearerAuthorization()(p)).Prepare(r)
return r, err
})
}
}
@ -89,25 +157,28 @@ func NewBearerAuthorizerCallback(sender Sender, callback BearerAuthorizerCallbac
func (bacb *BearerAuthorizerCallback) WithAuthorization() PrepareDecorator {
return func(p Preparer) Preparer {
return PreparerFunc(func(r *http.Request) (*http.Request, error) {
// 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)
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"])
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
}
return ba.WithAuthorization()(p).Prepare(r)
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())
}
}
}
}
@ -165,3 +236,22 @@ func newBearerChallenge(resp *http.Response) (bc bearerChallenge, err error) {
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()
}

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
}

View file

@ -1,7 +1,23 @@
package azure
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
@ -23,6 +39,184 @@ const (
operationSucceeded string = "Succeeded"
)
var pollingCodes = [...]int{http.StatusNoContent, http.StatusAccepted, http.StatusCreated, http.StatusOK}
// Future provides a mechanism to access the status and results of an asynchronous request.
// Since futures are stateful they should be passed by value to avoid race conditions.
type Future struct {
req *http.Request
resp *http.Response
ps pollingState
}
// NewFuture returns a new Future object initialized with the specified request.
func NewFuture(req *http.Request) Future {
return Future{req: req}
}
// Response returns the last HTTP response or nil if there isn't one.
func (f Future) Response() *http.Response {
return f.resp
}
// Status returns the last status message of the operation.
func (f Future) Status() string {
if f.ps.State == "" {
return "Unknown"
}
return f.ps.State
}
// PollingMethod returns the method used to monitor the status of the asynchronous operation.
func (f Future) PollingMethod() PollingMethodType {
return f.ps.PollingMethod
}
// Done queries the service to see if the operation has completed.
func (f *Future) Done(sender autorest.Sender) (bool, error) {
// exit early if this future has terminated
if f.ps.hasTerminated() {
return true, f.errorInfo()
}
resp, err := sender.Do(f.req)
f.resp = resp
if err != nil {
return false, err
}
if !autorest.ResponseHasStatusCode(resp, pollingCodes[:]...) {
// check response body for error content
if resp.Body != nil {
type respErr struct {
ServiceError ServiceError `json:"error"`
}
re := respErr{}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return false, err
}
err = json.Unmarshal(b, &re)
if err != nil {
return false, err
}
return false, re.ServiceError
}
// try to return something meaningful
return false, ServiceError{
Code: fmt.Sprintf("%v", resp.StatusCode),
Message: resp.Status,
}
}
err = updatePollingState(resp, &f.ps)
if err != nil {
return false, err
}
if f.ps.hasTerminated() {
return true, f.errorInfo()
}
f.req, err = newPollingRequest(f.ps)
return false, err
}
// GetPollingDelay returns a duration the application should wait before checking
// the status of the asynchronous request and true; this value is returned from
// the service via the Retry-After response header. If the header wasn't returned
// then the function returns the zero-value time.Duration and false.
func (f Future) GetPollingDelay() (time.Duration, bool) {
if f.resp == nil {
return 0, false
}
retry := f.resp.Header.Get(autorest.HeaderRetryAfter)
if retry == "" {
return 0, false
}
d, err := time.ParseDuration(retry + "s")
if err != nil {
panic(err)
}
return d, true
}
// WaitForCompletion will return when one of the following conditions is met: the long
// running operation has completed, the provided context is cancelled, or the client's
// polling duration has been exceeded. It will retry failed polling attempts based on
// the retry value defined in the client up to the maximum retry attempts.
func (f Future) WaitForCompletion(ctx context.Context, client autorest.Client) error {
ctx, cancel := context.WithTimeout(ctx, client.PollingDuration)
defer cancel()
done, err := f.Done(client)
for attempts := 0; !done; done, err = f.Done(client) {
if attempts >= client.RetryAttempts {
return autorest.NewErrorWithError(err, "azure", "WaitForCompletion", f.resp, "the number of retries has been exceeded")
}
// we want delayAttempt to be zero in the non-error case so
// that DelayForBackoff doesn't perform exponential back-off
var delayAttempt int
var delay time.Duration
if err == nil {
// check for Retry-After delay, if not present use the client's polling delay
var ok bool
delay, ok = f.GetPollingDelay()
if !ok {
delay = client.PollingDelay
}
} else {
// there was an error polling for status so perform exponential
// back-off based on the number of attempts using the client's retry
// duration. update attempts after delayAttempt to avoid off-by-one.
delayAttempt = attempts
delay = client.RetryDuration
attempts++
}
// wait until the delay elapses or the context is cancelled
delayElapsed := autorest.DelayForBackoff(delay, delayAttempt, ctx.Done())
if !delayElapsed {
return autorest.NewErrorWithError(ctx.Err(), "azure", "WaitForCompletion", f.resp, "context has been cancelled")
}
}
return err
}
// if the operation failed the polling state will contain
// error information and implements the error interface
func (f *Future) errorInfo() error {
if !f.ps.hasSucceeded() {
return f.ps
}
return nil
}
// MarshalJSON implements the json.Marshaler interface.
func (f Future) MarshalJSON() ([]byte, error) {
return json.Marshal(&f.ps)
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (f *Future) UnmarshalJSON(data []byte) error {
err := json.Unmarshal(data, &f.ps)
if err != nil {
return err
}
f.req, err = newPollingRequest(f.ps)
return err
}
// PollingURL returns the URL used for retrieving the status of the long-running operation.
// For LROs that use the Location header the final URL value is used to retrieve the result.
func (f Future) PollingURL() string {
return f.ps.URI
}
// DoPollForAsynchronous returns a SendDecorator that polls if the http.Response is for an Azure
// long-running operation. It will delay between requests for the duration specified in the
// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled by
@ -34,8 +228,7 @@ func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator {
if err != nil {
return resp, err
}
pollingCodes := []int{http.StatusAccepted, http.StatusCreated, http.StatusOK}
if !autorest.ResponseHasStatusCode(resp, pollingCodes...) {
if !autorest.ResponseHasStatusCode(resp, pollingCodes[:]...) {
return resp, nil
}
@ -52,10 +245,11 @@ func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator {
break
}
r, err = newPollingRequest(resp, ps)
r, err = newPollingRequest(ps)
if err != nil {
return resp, err
}
r = r.WithContext(resp.Request.Context())
delay = autorest.GetRetryAfter(resp, delay)
resp, err = autorest.SendWithSender(s, r,
@ -72,20 +266,15 @@ func getAsyncOperation(resp *http.Response) string {
}
func hasSucceeded(state string) bool {
return state == operationSucceeded
return strings.EqualFold(state, operationSucceeded)
}
func hasTerminated(state string) bool {
switch state {
case operationCanceled, operationFailed, operationSucceeded:
return true
default:
return false
}
return strings.EqualFold(state, operationCanceled) || strings.EqualFold(state, operationFailed) || strings.EqualFold(state, operationSucceeded)
}
func hasFailed(state string) bool {
return state == operationFailed
return strings.EqualFold(state, operationFailed)
}
type provisioningTracker interface {
@ -143,39 +332,50 @@ func (ps provisioningStatus) hasTerminated() bool {
}
func (ps provisioningStatus) hasProvisioningError() bool {
return ps.ProvisioningError != ServiceError{}
// code and message are required fields so only check them
return len(ps.ProvisioningError.Code) > 0 ||
len(ps.ProvisioningError.Message) > 0
}
type pollingResponseFormat string
// PollingMethodType defines a type used for enumerating polling mechanisms.
type PollingMethodType string
const (
usesOperationResponse pollingResponseFormat = "OperationResponse"
usesProvisioningStatus pollingResponseFormat = "ProvisioningStatus"
formatIsUnknown pollingResponseFormat = ""
// PollingAsyncOperation indicates the polling method uses the Azure-AsyncOperation header.
PollingAsyncOperation PollingMethodType = "AsyncOperation"
// PollingLocation indicates the polling method uses the Location header.
PollingLocation PollingMethodType = "Location"
// PollingUnknown indicates an unknown polling method and is the default value.
PollingUnknown PollingMethodType = ""
)
type pollingState struct {
responseFormat pollingResponseFormat
uri string
state string
code string
message string
PollingMethod PollingMethodType `json:"pollingMethod"`
URI string `json:"uri"`
State string `json:"state"`
ServiceError *ServiceError `json:"error,omitempty"`
}
func (ps pollingState) hasSucceeded() bool {
return hasSucceeded(ps.state)
return hasSucceeded(ps.State)
}
func (ps pollingState) hasTerminated() bool {
return hasTerminated(ps.state)
return hasTerminated(ps.State)
}
func (ps pollingState) hasFailed() bool {
return hasFailed(ps.state)
return hasFailed(ps.State)
}
func (ps pollingState) Error() string {
return fmt.Sprintf("Long running operation terminated with status '%s': Code=%q Message=%q", ps.state, ps.code, ps.message)
s := fmt.Sprintf("Long running operation terminated with status '%s'", ps.State)
if ps.ServiceError != nil {
s = fmt.Sprintf("%s: %+v", s, *ps.ServiceError)
}
return s
}
// updatePollingState maps the operation status -- retrieved from either a provisioningState
@ -190,7 +390,7 @@ func updatePollingState(resp *http.Response, ps *pollingState) error {
// -- The first response will always be a provisioningStatus response; only the polling requests,
// depending on the header returned, may be something otherwise.
var pt provisioningTracker
if ps.responseFormat == usesOperationResponse {
if ps.PollingMethod == PollingAsyncOperation {
pt = &operationResource{}
} else {
pt = &provisioningStatus{}
@ -198,30 +398,30 @@ func updatePollingState(resp *http.Response, ps *pollingState) error {
// If this is the first request (that is, the polling response shape is unknown), determine how
// to poll and what to expect
if ps.responseFormat == formatIsUnknown {
if ps.PollingMethod == PollingUnknown {
req := resp.Request
if req == nil {
return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Original HTTP request is missing")
}
// Prefer the Azure-AsyncOperation header
ps.uri = getAsyncOperation(resp)
if ps.uri != "" {
ps.responseFormat = usesOperationResponse
ps.URI = getAsyncOperation(resp)
if ps.URI != "" {
ps.PollingMethod = PollingAsyncOperation
} else {
ps.responseFormat = usesProvisioningStatus
ps.PollingMethod = PollingLocation
}
// Else, use the Location header
if ps.uri == "" {
ps.uri = autorest.GetLocation(resp)
if ps.URI == "" {
ps.URI = autorest.GetLocation(resp)
}
// Lastly, requests against an existing resource, use the last request URI
if ps.uri == "" {
if ps.URI == "" {
m := strings.ToUpper(req.Method)
if m == http.MethodPatch || m == http.MethodPut || m == http.MethodGet {
ps.uri = req.URL.String()
ps.URI = req.URL.String()
}
}
}
@ -242,23 +442,23 @@ func updatePollingState(resp *http.Response, ps *pollingState) error {
// -- Unknown states are per-service inprogress states
// -- Otherwise, infer state from HTTP status code
if pt.hasTerminated() {
ps.state = pt.state()
ps.State = pt.state()
} else if pt.state() != "" {
ps.state = operationInProgress
ps.State = operationInProgress
} else {
switch resp.StatusCode {
case http.StatusAccepted:
ps.state = operationInProgress
ps.State = operationInProgress
case http.StatusNoContent, http.StatusCreated, http.StatusOK:
ps.state = operationSucceeded
ps.State = operationSucceeded
default:
ps.state = operationFailed
ps.State = operationFailed
}
}
if ps.state == operationInProgress && ps.uri == "" {
if strings.EqualFold(ps.State, operationInProgress) && ps.URI == "" {
return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Unable to obtain polling URI for %s %s", resp.Request.Method, resp.Request.URL)
}
@ -267,36 +467,45 @@ func updatePollingState(resp *http.Response, ps *pollingState) error {
// -- Response
// -- Otherwise, Unknown
if ps.hasFailed() {
if ps.responseFormat == usesOperationResponse {
or := pt.(*operationResource)
ps.code = or.OperationError.Code
ps.message = or.OperationError.Message
if or, ok := pt.(*operationResource); ok {
ps.ServiceError = &or.OperationError
} else if p, ok := pt.(*provisioningStatus); ok && p.hasProvisioningError() {
ps.ServiceError = &p.ProvisioningError
} else {
p := pt.(*provisioningStatus)
if p.hasProvisioningError() {
ps.code = p.ProvisioningError.Code
ps.message = p.ProvisioningError.Message
} else {
ps.code = "Unknown"
ps.message = "None"
ps.ServiceError = &ServiceError{
Code: "Unknown",
Message: "None",
}
}
}
return nil
}
func newPollingRequest(resp *http.Response, ps pollingState) (*http.Request, error) {
req := resp.Request
if req == nil {
return nil, autorest.NewError("azure", "newPollingRequest", "Azure Polling Error - Original HTTP request is missing")
}
reqPoll, err := autorest.Prepare(&http.Request{Cancel: req.Cancel},
func newPollingRequest(ps pollingState) (*http.Request, error) {
reqPoll, err := autorest.Prepare(&http.Request{},
autorest.AsGet(),
autorest.WithBaseURL(ps.uri))
autorest.WithBaseURL(ps.URI))
if err != nil {
return nil, autorest.NewErrorWithError(err, "azure", "newPollingRequest", nil, "Failure creating poll request to %s", ps.uri)
return nil, autorest.NewErrorWithError(err, "azure", "newPollingRequest", nil, "Failure creating poll request to %s", ps.URI)
}
return reqPoll, nil
}
// AsyncOpIncompleteError is the type that's returned from a future that has not completed.
type AsyncOpIncompleteError struct {
// FutureType is the name of the type composed of a azure.Future.
FutureType string
}
// Error returns an error message including the originating type name of the error.
func (e AsyncOpIncompleteError) Error() string {
return fmt.Sprintf("%s: asynchronous operation has not completed", e.FutureType)
}
// NewAsyncOpIncompleteError creates a new AsyncOpIncompleteError with the specified parameters.
func NewAsyncOpIncompleteError(futureType string) AsyncOpIncompleteError {
return AsyncOpIncompleteError{
FutureType: futureType,
}
}

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)

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
}

View file

@ -0,0 +1,245 @@
package azure
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/Azure/go-autorest/autorest"
)
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
type audience []string
type authentication struct {
LoginEndpoint string `json:"loginEndpoint"`
Audiences audience `json:"audiences"`
}
type environmentMetadataInfo struct {
GalleryEndpoint string `json:"galleryEndpoint"`
GraphEndpoint string `json:"graphEndpoint"`
PortalEndpoint string `json:"portalEndpoint"`
Authentication authentication `json:"authentication"`
}
// EnvironmentProperty represent property names that clients can override
type EnvironmentProperty string
const (
// EnvironmentName ...
EnvironmentName EnvironmentProperty = "name"
// EnvironmentManagementPortalURL ..
EnvironmentManagementPortalURL EnvironmentProperty = "managementPortalURL"
// EnvironmentPublishSettingsURL ...
EnvironmentPublishSettingsURL EnvironmentProperty = "publishSettingsURL"
// EnvironmentServiceManagementEndpoint ...
EnvironmentServiceManagementEndpoint EnvironmentProperty = "serviceManagementEndpoint"
// EnvironmentResourceManagerEndpoint ...
EnvironmentResourceManagerEndpoint EnvironmentProperty = "resourceManagerEndpoint"
// EnvironmentActiveDirectoryEndpoint ...
EnvironmentActiveDirectoryEndpoint EnvironmentProperty = "activeDirectoryEndpoint"
// EnvironmentGalleryEndpoint ...
EnvironmentGalleryEndpoint EnvironmentProperty = "galleryEndpoint"
// EnvironmentKeyVaultEndpoint ...
EnvironmentKeyVaultEndpoint EnvironmentProperty = "keyVaultEndpoint"
// EnvironmentGraphEndpoint ...
EnvironmentGraphEndpoint EnvironmentProperty = "graphEndpoint"
// EnvironmentServiceBusEndpoint ...
EnvironmentServiceBusEndpoint EnvironmentProperty = "serviceBusEndpoint"
// EnvironmentBatchManagementEndpoint ...
EnvironmentBatchManagementEndpoint EnvironmentProperty = "batchManagementEndpoint"
// EnvironmentStorageEndpointSuffix ...
EnvironmentStorageEndpointSuffix EnvironmentProperty = "storageEndpointSuffix"
// EnvironmentSQLDatabaseDNSSuffix ...
EnvironmentSQLDatabaseDNSSuffix EnvironmentProperty = "sqlDatabaseDNSSuffix"
// EnvironmentTrafficManagerDNSSuffix ...
EnvironmentTrafficManagerDNSSuffix EnvironmentProperty = "trafficManagerDNSSuffix"
// EnvironmentKeyVaultDNSSuffix ...
EnvironmentKeyVaultDNSSuffix EnvironmentProperty = "keyVaultDNSSuffix"
// EnvironmentServiceBusEndpointSuffix ...
EnvironmentServiceBusEndpointSuffix EnvironmentProperty = "serviceBusEndpointSuffix"
// EnvironmentServiceManagementVMDNSSuffix ...
EnvironmentServiceManagementVMDNSSuffix EnvironmentProperty = "serviceManagementVMDNSSuffix"
// EnvironmentResourceManagerVMDNSSuffix ...
EnvironmentResourceManagerVMDNSSuffix EnvironmentProperty = "resourceManagerVMDNSSuffix"
// EnvironmentContainerRegistryDNSSuffix ...
EnvironmentContainerRegistryDNSSuffix EnvironmentProperty = "containerRegistryDNSSuffix"
// EnvironmentTokenAudience ...
EnvironmentTokenAudience EnvironmentProperty = "tokenAudience"
)
// OverrideProperty represents property name and value that clients can override
type OverrideProperty struct {
Key EnvironmentProperty
Value string
}
// EnvironmentFromURL loads an Environment from a URL
// This function is particularly useful in the Hybrid Cloud model, where one may define their own
// endpoints.
func EnvironmentFromURL(resourceManagerEndpoint string, properties ...OverrideProperty) (environment Environment, err error) {
var metadataEnvProperties environmentMetadataInfo
if resourceManagerEndpoint == "" {
return environment, fmt.Errorf("Metadata resource manager endpoint is empty")
}
if metadataEnvProperties, err = retrieveMetadataEnvironment(resourceManagerEndpoint); err != nil {
return environment, err
}
// Give priority to user's override values
overrideProperties(&environment, properties)
if environment.Name == "" {
environment.Name = "HybridEnvironment"
}
stampDNSSuffix := environment.StorageEndpointSuffix
if stampDNSSuffix == "" {
stampDNSSuffix = strings.TrimSuffix(strings.TrimPrefix(strings.Replace(resourceManagerEndpoint, strings.Split(resourceManagerEndpoint, ".")[0], "", 1), "."), "/")
environment.StorageEndpointSuffix = stampDNSSuffix
}
if environment.KeyVaultDNSSuffix == "" {
environment.KeyVaultDNSSuffix = fmt.Sprintf("%s.%s", "vault", stampDNSSuffix)
}
if environment.KeyVaultEndpoint == "" {
environment.KeyVaultEndpoint = fmt.Sprintf("%s%s", "https://", environment.KeyVaultDNSSuffix)
}
if environment.TokenAudience == "" {
environment.TokenAudience = metadataEnvProperties.Authentication.Audiences[0]
}
if environment.ActiveDirectoryEndpoint == "" {
environment.ActiveDirectoryEndpoint = metadataEnvProperties.Authentication.LoginEndpoint
}
if environment.ResourceManagerEndpoint == "" {
environment.ResourceManagerEndpoint = resourceManagerEndpoint
}
if environment.GalleryEndpoint == "" {
environment.GalleryEndpoint = metadataEnvProperties.GalleryEndpoint
}
if environment.GraphEndpoint == "" {
environment.GraphEndpoint = metadataEnvProperties.GraphEndpoint
}
return environment, nil
}
func overrideProperties(environment *Environment, properties []OverrideProperty) {
for _, property := range properties {
switch property.Key {
case EnvironmentName:
{
environment.Name = property.Value
}
case EnvironmentManagementPortalURL:
{
environment.ManagementPortalURL = property.Value
}
case EnvironmentPublishSettingsURL:
{
environment.PublishSettingsURL = property.Value
}
case EnvironmentServiceManagementEndpoint:
{
environment.ServiceManagementEndpoint = property.Value
}
case EnvironmentResourceManagerEndpoint:
{
environment.ResourceManagerEndpoint = property.Value
}
case EnvironmentActiveDirectoryEndpoint:
{
environment.ActiveDirectoryEndpoint = property.Value
}
case EnvironmentGalleryEndpoint:
{
environment.GalleryEndpoint = property.Value
}
case EnvironmentKeyVaultEndpoint:
{
environment.KeyVaultEndpoint = property.Value
}
case EnvironmentGraphEndpoint:
{
environment.GraphEndpoint = property.Value
}
case EnvironmentServiceBusEndpoint:
{
environment.ServiceBusEndpoint = property.Value
}
case EnvironmentBatchManagementEndpoint:
{
environment.BatchManagementEndpoint = property.Value
}
case EnvironmentStorageEndpointSuffix:
{
environment.StorageEndpointSuffix = property.Value
}
case EnvironmentSQLDatabaseDNSSuffix:
{
environment.SQLDatabaseDNSSuffix = property.Value
}
case EnvironmentTrafficManagerDNSSuffix:
{
environment.TrafficManagerDNSSuffix = property.Value
}
case EnvironmentKeyVaultDNSSuffix:
{
environment.KeyVaultDNSSuffix = property.Value
}
case EnvironmentServiceBusEndpointSuffix:
{
environment.ServiceBusEndpointSuffix = property.Value
}
case EnvironmentServiceManagementVMDNSSuffix:
{
environment.ServiceManagementVMDNSSuffix = property.Value
}
case EnvironmentResourceManagerVMDNSSuffix:
{
environment.ResourceManagerVMDNSSuffix = property.Value
}
case EnvironmentContainerRegistryDNSSuffix:
{
environment.ContainerRegistryDNSSuffix = property.Value
}
case EnvironmentTokenAudience:
{
environment.TokenAudience = property.Value
}
}
}
}
func retrieveMetadataEnvironment(endpoint string) (environment environmentMetadataInfo, err error) {
client := autorest.NewClientWithUserAgent("")
managementEndpoint := fmt.Sprintf("%s%s", strings.TrimSuffix(endpoint, "/"), "/metadata/endpoints?api-version=1.0")
req, _ := http.NewRequest("GET", managementEndpoint, nil)
response, err := client.Do(req)
if err != nil {
return environment, err
}
defer response.Body.Close()
jsonResponse, err := ioutil.ReadAll(response.Body)
if err != nil {
return environment, err
}
err = json.Unmarshal(jsonResponse, &environment)
return environment, err
}

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 ""
}

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,7 +50,8 @@ 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
@ -148,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
@ -157,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
}
@ -181,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
}

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"

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"

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"

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"

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"

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"

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
})

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"

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"
"io"

View file

@ -1,17 +1,31 @@
// +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
reset bool
req *http.Request
br *bytes.Reader
}
// Prepare signals that the request is about to be sent.
@ -19,21 +33,17 @@ 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.reset {
if rr.br != nil {
_, err = rr.br.Seek(0, 0 /*io.SeekStart*/)
}
rr.reset = false
if err != nil {
return err
}
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()
}
// indicates that the request body needs to be reset
rr.reset = true
}
return err
}

View file

@ -1,19 +1,33 @@
// +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
reset bool
req *http.Request
rc io.ReadCloser
br *bytes.Reader
}
// Prepare signals that the request is about to be sent.
@ -21,16 +35,14 @@ 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.reset {
if rr.rc != nil {
rr.req.Body = rr.rc
} else if rr.br != nil {
_, err = rr.br.Seek(0, io.SeekStart)
}
rr.reset = false
if err != nil {
return err
}
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
@ -43,8 +55,6 @@ func (rr *RetriableRequest) Prepare() (err error) {
// fall back to making a copy (only do this once)
err = rr.prepareFromByteReader()
}
// indicates that the request body needs to be reset
rr.reset = true
}
return err
}

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"
"log"
@ -72,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)
@ -151,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,
@ -184,7 +198,9 @@ func DoRetryForAttempts(attempts int, backoff time.Duration) SendDecorator {
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
})
@ -201,18 +217,25 @@ func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) Se
rr := NewRetriableRequest(r)
// Increment to add the first call (attempts denotes number of retries)
attempts++
for attempt := 0; attempt < attempts; attempt++ {
for attempt := 0; attempt < attempts; {
err = rr.Prepare()
if err != nil {
return resp, err
}
resp, err = s.Do(rr.Request())
if err != nil || !ResponseHasStatusCode(resp, codes...) {
// we want to retry if err is not nil (e.g. transient network failure). note that for failed authentication
// resp and err will both have a value, so in this case we don't want to retry as it will never succeed.
if err == nil && !ResponseHasStatusCode(resp, codes...) || IsTokenRefreshError(err) {
return resp, err
}
delayed := DelayWithRetryAfter(resp, r.Cancel)
if !delayed {
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
@ -223,6 +246,9 @@ func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) Se
// 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 {
@ -253,7 +279,9 @@ func DoRetryForDuration(d time.Duration, backoff time.Duration) SendDecorator {
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
})

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 {

View file

@ -1,15 +1,31 @@
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/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 +139,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 +194,25 @@ 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
}

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.5.0"
}

View file

@ -14,6 +14,7 @@ var (
)
// Implements the ECDSA family of signing methods signing methods
// Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
type SigningMethodECDSA struct {
Name string
Hash crypto.Hash

View file

@ -51,13 +51,9 @@ func (e ValidationError) Error() string {
} else {
return "token is invalid"
}
return e.Inner.Error()
}
// No errors
func (e *ValidationError) valid() bool {
if e.Errors > 0 {
return false
}
return true
return e.Errors == 0
}

View file

@ -7,6 +7,7 @@ import (
)
// Implements the HMAC-SHA family of signing methods signing methods
// Expects key type of []byte for both signing and validation
type SigningMethodHMAC struct {
Name string
Hash crypto.Hash
@ -90,5 +91,5 @@ func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string,
return EncodeSegment(hasher.Sum(nil)), nil
}
return "", ErrInvalidKey
return "", ErrInvalidKeyType
}

View file

@ -8,8 +8,9 @@ import (
)
type Parser struct {
ValidMethods []string // If populated, only these methods will be considered valid
UseJSONNumber bool // Use JSON Number format in JSON decoder
ValidMethods []string // If populated, only these methods will be considered valid
UseJSONNumber bool // Use JSON Number format in JSON decoder
SkipClaimsValidation bool // Skip claims validation during token parsing
}
// Parse, validate, and return a token.
@ -20,55 +21,9 @@ func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
}
func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
parts := strings.Split(tokenString, ".")
if len(parts) != 3 {
return nil, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
}
var err error
token := &Token{Raw: tokenString}
// parse Header
var headerBytes []byte
if headerBytes, err = DecodeSegment(parts[0]); err != nil {
if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
return token, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
}
return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
}
if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
}
// parse Claims
var claimBytes []byte
token.Claims = claims
if claimBytes, err = DecodeSegment(parts[1]); err != nil {
return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
}
dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
if p.UseJSONNumber {
dec.UseNumber()
}
// JSON Decode. Special case for map type to avoid weird pointer behavior
if c, ok := token.Claims.(MapClaims); ok {
err = dec.Decode(&c)
} else {
err = dec.Decode(&claims)
}
// Handle decode error
token, parts, err := p.ParseUnverified(tokenString, claims)
if err != nil {
return token, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
}
// Lookup signature method
if method, ok := token.Header["alg"].(string); ok {
if token.Method = GetSigningMethod(method); token.Method == nil {
return token, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
}
} else {
return token, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
return token, err
}
// Verify signing method is in the required set
@ -95,20 +50,25 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
}
if key, err = keyFunc(token); err != nil {
// keyFunc returned an error
if ve, ok := err.(*ValidationError); ok {
return token, ve
}
return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
}
vErr := &ValidationError{}
// Validate Claims
if err := token.Claims.Valid(); err != nil {
if !p.SkipClaimsValidation {
if err := token.Claims.Valid(); err != nil {
// If the Claims Valid returned an error, check if it is a validation error,
// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
if e, ok := err.(*ValidationError); !ok {
vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
} else {
vErr = e
// If the Claims Valid returned an error, check if it is a validation error,
// If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
if e, ok := err.(*ValidationError); !ok {
vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
} else {
vErr = e
}
}
}
@ -126,3 +86,63 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
return token, vErr
}
// WARNING: Don't use this method unless you know what you're doing
//
// This method parses the token but doesn't validate the signature. It's only
// ever useful in cases where you know the signature is valid (because it has
// been checked previously in the stack) and you want to extract values from
// it.
func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
parts = strings.Split(tokenString, ".")
if len(parts) != 3 {
return nil, parts, NewValidationError("token contains an invalid number of segments", ValidationErrorMalformed)
}
token = &Token{Raw: tokenString}
// parse Header
var headerBytes []byte
if headerBytes, err = DecodeSegment(parts[0]); err != nil {
if strings.HasPrefix(strings.ToLower(tokenString), "bearer ") {
return token, parts, NewValidationError("tokenstring should not contain 'bearer '", ValidationErrorMalformed)
}
return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
}
if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
}
// parse Claims
var claimBytes []byte
token.Claims = claims
if claimBytes, err = DecodeSegment(parts[1]); err != nil {
return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
}
dec := json.NewDecoder(bytes.NewBuffer(claimBytes))
if p.UseJSONNumber {
dec.UseNumber()
}
// JSON Decode. Special case for map type to avoid weird pointer behavior
if c, ok := token.Claims.(MapClaims); ok {
err = dec.Decode(&c)
} else {
err = dec.Decode(&claims)
}
// Handle decode error
if err != nil {
return token, parts, &ValidationError{Inner: err, Errors: ValidationErrorMalformed}
}
// Lookup signature method
if method, ok := token.Header["alg"].(string); ok {
if token.Method = GetSigningMethod(method); token.Method == nil {
return token, parts, NewValidationError("signing method (alg) is unavailable.", ValidationErrorUnverifiable)
}
} else {
return token, parts, NewValidationError("signing method (alg) is unspecified.", ValidationErrorUnverifiable)
}
return token, parts, nil
}

View file

@ -7,6 +7,7 @@ import (
)
// Implements the RSA family of signing methods signing methods
// Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation
type SigningMethodRSA struct {
Name string
Hash crypto.Hash
@ -44,7 +45,7 @@ func (m *SigningMethodRSA) Alg() string {
}
// Implements the Verify method from SigningMethod
// For this signing method, must be an rsa.PublicKey structure.
// For this signing method, must be an *rsa.PublicKey structure.
func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error {
var err error
@ -73,7 +74,7 @@ func (m *SigningMethodRSA) Verify(signingString, signature string, key interface
}
// Implements the Sign method from SigningMethod
// For this signing method, must be an rsa.PrivateKey structure.
// For this signing method, must be an *rsa.PrivateKey structure.
func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) {
var rsaKey *rsa.PrivateKey
var ok bool

View file

@ -39,6 +39,38 @@ func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
return pkey, nil
}
// Parse PEM encoded PKCS1 or PKCS8 private key protected with password
func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
var err error
// Parse PEM block
var block *pem.Block
if block, _ = pem.Decode(key); block == nil {
return nil, ErrKeyMustBePEMEncoded
}
var parsedKey interface{}
var blockDecrypted []byte
if blockDecrypted, err = x509.DecryptPEMBlock(block, []byte(password)); err != nil {
return nil, err
}
if parsedKey, err = x509.ParsePKCS1PrivateKey(blockDecrypted); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(blockDecrypted); err != nil {
return nil, err
}
}
var pkey *rsa.PrivateKey
var ok bool
if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok {
return nil, ErrNotRSAPrivateKey
}
return pkey, nil
}
// Parse PEM encoded PKCS1 or PKCS8 public key
func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
var err error

View file

@ -482,6 +482,7 @@ func (c *Client) createOrderForIdentifiers(domains []string) (orderResource, err
orderRes := orderResource{
URL: hdr.Get("Location"),
Domains: domains,
orderMessage: response,
}
return orderRes, nil
@ -590,7 +591,7 @@ func (c *Client) requestCertificateForOrder(order orderResource, bundle bool, pr
}
// determine certificate name(s) based on the authorization resources
commonName := order.Identifiers[0].Value
commonName := order.Domains[0]
var san []string
for _, auth := range order.Identifiers {
san = append(san, auth.Value)
@ -606,12 +607,7 @@ func (c *Client) requestCertificateForOrder(order orderResource, bundle bool, pr
}
func (c *Client) requestCertificateForCsr(order orderResource, bundle bool, csr []byte, privateKeyPem []byte) (CertificateResource, error) {
commonName := order.Identifiers[0].Value
var authURLs []string
for _, auth := range order.Identifiers[1:] {
authURLs = append(authURLs, auth.Value)
}
commonName := order.Domains[0]
csrString := base64.RawURLEncoding.EncodeToString(csr)
var retOrder orderMessage

View file

@ -34,7 +34,8 @@ type accountMessage struct {
}
type orderResource struct {
URL string `json:"url,omitempty"`
URL string `json:"url,omitempty"`
Domains []string `json:"domains,omitempty"`
orderMessage `json:"body,omitempty"`
}

View file

@ -4,14 +4,13 @@
package azure
import (
"context"
"fmt"
"os"
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/arm/dns"
"strings"
"github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2017-09-01/dns"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure"
@ -26,6 +25,8 @@ type DNSProvider struct {
subscriptionId string
tenantId string
resourceGroup string
context context.Context
}
// NewDNSProvider returns a DNSProvider instance configured for azure.
@ -53,6 +54,8 @@ func NewDNSProviderCredentials(clientId, clientSecret, subscriptionId, tenantId,
subscriptionId: subscriptionId,
tenantId: tenantId,
resourceGroup: resourceGroup,
// TODO: A timeout can be added here for cancellation purposes.
context: context.Background(),
}, nil
}
@ -82,7 +85,7 @@ func (c *DNSProvider) Present(domain, token, keyAuth string) error {
TxtRecords: &[]dns.TxtRecord{dns.TxtRecord{Value: &[]string{value}}},
},
}
_, err = rsc.CreateOrUpdate(c.resourceGroup, zone, relative, dns.TXT, rec, "", "")
_, err = rsc.CreateOrUpdate(c.context, c.resourceGroup, zone, relative, dns.TXT, rec, "", "")
if err != nil {
return err
@ -109,7 +112,7 @@ func (c *DNSProvider) CleanUp(domain, token, keyAuth string) error {
rsc := dns.NewRecordSetsClient(c.subscriptionId)
spt, err := c.newServicePrincipalTokenFromCredentials(azure.PublicCloud.ResourceManagerEndpoint)
rsc.Authorizer = autorest.NewBearerAuthorizer(spt)
_, err = rsc.Delete(c.resourceGroup, zone, relative, dns.TXT, "")
_, err = rsc.Delete(c.context, c.resourceGroup, zone, relative, dns.TXT, "")
if err != nil {
return err
}
@ -130,7 +133,7 @@ func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
dc := dns.NewZonesClient(c.subscriptionId)
dc.Authorizer = autorest.NewBearerAuthorizer(spt)
zone, err := dc.Get(c.resourceGroup, acmev2.UnFqdn(authZone))
zone, err := dc.Get(c.context, c.resourceGroup, acmev2.UnFqdn(authZone))
if err != nil {
return "", err

View file

@ -72,7 +72,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
authZone = acmev2.UnFqdn(authZone)
reqURL := fmt.Sprintf("%s/v2/domains/%s/records", digitalOceanBaseURL, authZone)
reqData := txtRecordRequest{RecordType: "TXT", Name: fqdn, Data: value, TTL: 60}
reqData := txtRecordRequest{RecordType: "TXT", Name: fqdn, Data: value, TTL: 30}
body, err := json.Marshal(reqData)
if err != nil {
return err
@ -169,5 +169,5 @@ var digitalOceanBaseURL = "https://api.digitalocean.com"
// Timeout returns the timeout and interval to use when checking for DNS
// propagation. Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return 90 * time.Second, 5 * time.Second
return 60 * time.Second, 5 * time.Second
}