Merge pull request #13767 from hashicorp/f-bump-autorest-dep
core: Bump AutoRest Dep
This commit is contained in:
commit
53ff003826
|
@ -16,6 +16,7 @@ and Responding. A typical pattern is:
|
||||||
DoRetryForAttempts(5, time.Second))
|
DoRetryForAttempts(5, time.Second))
|
||||||
|
|
||||||
err = Respond(resp,
|
err = Respond(resp,
|
||||||
|
ByDiscardingBody(),
|
||||||
ByClosing())
|
ByClosing())
|
||||||
|
|
||||||
Each phase relies on decorators to modify and / or manage processing. Decorators may first modify
|
Each phase relies on decorators to modify and / or manage processing. Decorators may first modify
|
||||||
|
|
|
@ -3,12 +3,13 @@ package azure
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Azure/go-autorest/autorest"
|
|
||||||
"github.com/Azure/go-autorest/autorest/date"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Azure/go-autorest/autorest"
|
||||||
|
"github.com/Azure/go-autorest/autorest/date"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -19,93 +19,108 @@ var environments = map[string]Environment{
|
||||||
|
|
||||||
// Environment represents a set of endpoints for each of Azure's Clouds.
|
// Environment represents a set of endpoints for each of Azure's Clouds.
|
||||||
type Environment struct {
|
type Environment struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ManagementPortalURL string `json:"managementPortalURL"`
|
ManagementPortalURL string `json:"managementPortalURL"`
|
||||||
PublishSettingsURL string `json:"publishSettingsURL"`
|
PublishSettingsURL string `json:"publishSettingsURL"`
|
||||||
ServiceManagementEndpoint string `json:"serviceManagementEndpoint"`
|
ServiceManagementEndpoint string `json:"serviceManagementEndpoint"`
|
||||||
ResourceManagerEndpoint string `json:"resourceManagerEndpoint"`
|
ResourceManagerEndpoint string `json:"resourceManagerEndpoint"`
|
||||||
ActiveDirectoryEndpoint string `json:"activeDirectoryEndpoint"`
|
ActiveDirectoryEndpoint string `json:"activeDirectoryEndpoint"`
|
||||||
GalleryEndpoint string `json:"galleryEndpoint"`
|
GalleryEndpoint string `json:"galleryEndpoint"`
|
||||||
KeyVaultEndpoint string `json:"keyVaultEndpoint"`
|
KeyVaultEndpoint string `json:"keyVaultEndpoint"`
|
||||||
GraphEndpoint string `json:"graphEndpoint"`
|
GraphEndpoint string `json:"graphEndpoint"`
|
||||||
StorageEndpointSuffix string `json:"storageEndpointSuffix"`
|
StorageEndpointSuffix string `json:"storageEndpointSuffix"`
|
||||||
SQLDatabaseDNSSuffix string `json:"sqlDatabaseDNSSuffix"`
|
SQLDatabaseDNSSuffix string `json:"sqlDatabaseDNSSuffix"`
|
||||||
TrafficManagerDNSSuffix string `json:"trafficManagerDNSSuffix"`
|
TrafficManagerDNSSuffix string `json:"trafficManagerDNSSuffix"`
|
||||||
KeyVaultDNSSuffix string `json:"keyVaultDNSSuffix"`
|
KeyVaultDNSSuffix string `json:"keyVaultDNSSuffix"`
|
||||||
ServiceBusEndpointSuffix string `json:"serviceBusEndpointSuffix"`
|
ServiceBusEndpointSuffix string `json:"serviceBusEndpointSuffix"`
|
||||||
|
ServiceManagementVMDNSSuffix string `json:"serviceManagementVMDNSSuffix"`
|
||||||
|
ResourceManagerVMDNSSuffix string `json:"resourceManagerVMDNSSuffix"`
|
||||||
|
ContainerRegistryDNSSuffix string `json:"containerRegistryDNSSuffix"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// PublicCloud is the default public Azure cloud environment
|
// PublicCloud is the default public Azure cloud environment
|
||||||
PublicCloud = Environment{
|
PublicCloud = Environment{
|
||||||
Name: "AzurePublicCloud",
|
Name: "AzurePublicCloud",
|
||||||
ManagementPortalURL: "https://manage.windowsazure.com/",
|
ManagementPortalURL: "https://manage.windowsazure.com/",
|
||||||
PublishSettingsURL: "https://manage.windowsazure.com/publishsettings/index",
|
PublishSettingsURL: "https://manage.windowsazure.com/publishsettings/index",
|
||||||
ServiceManagementEndpoint: "https://management.core.windows.net/",
|
ServiceManagementEndpoint: "https://management.core.windows.net/",
|
||||||
ResourceManagerEndpoint: "https://management.azure.com/",
|
ResourceManagerEndpoint: "https://management.azure.com/",
|
||||||
ActiveDirectoryEndpoint: "https://login.microsoftonline.com/",
|
ActiveDirectoryEndpoint: "https://login.microsoftonline.com/",
|
||||||
GalleryEndpoint: "https://gallery.azure.com/",
|
GalleryEndpoint: "https://gallery.azure.com/",
|
||||||
KeyVaultEndpoint: "https://vault.azure.net/",
|
KeyVaultEndpoint: "https://vault.azure.net/",
|
||||||
GraphEndpoint: "https://graph.windows.net/",
|
GraphEndpoint: "https://graph.windows.net/",
|
||||||
StorageEndpointSuffix: "core.windows.net",
|
StorageEndpointSuffix: "core.windows.net",
|
||||||
SQLDatabaseDNSSuffix: "database.windows.net",
|
SQLDatabaseDNSSuffix: "database.windows.net",
|
||||||
TrafficManagerDNSSuffix: "trafficmanager.net",
|
TrafficManagerDNSSuffix: "trafficmanager.net",
|
||||||
KeyVaultDNSSuffix: "vault.azure.net",
|
KeyVaultDNSSuffix: "vault.azure.net",
|
||||||
ServiceBusEndpointSuffix: "servicebus.azure.com",
|
ServiceBusEndpointSuffix: "servicebus.azure.com",
|
||||||
|
ServiceManagementVMDNSSuffix: "cloudapp.net",
|
||||||
|
ResourceManagerVMDNSSuffix: "cloudapp.azure.com",
|
||||||
|
ContainerRegistryDNSSuffix: "azurecr.io",
|
||||||
}
|
}
|
||||||
|
|
||||||
// USGovernmentCloud is the cloud environment for the US Government
|
// USGovernmentCloud is the cloud environment for the US Government
|
||||||
USGovernmentCloud = Environment{
|
USGovernmentCloud = Environment{
|
||||||
Name: "AzureUSGovernmentCloud",
|
Name: "AzureUSGovernmentCloud",
|
||||||
ManagementPortalURL: "https://manage.windowsazure.us/",
|
ManagementPortalURL: "https://manage.windowsazure.us/",
|
||||||
PublishSettingsURL: "https://manage.windowsazure.us/publishsettings/index",
|
PublishSettingsURL: "https://manage.windowsazure.us/publishsettings/index",
|
||||||
ServiceManagementEndpoint: "https://management.core.usgovcloudapi.net/",
|
ServiceManagementEndpoint: "https://management.core.usgovcloudapi.net/",
|
||||||
ResourceManagerEndpoint: "https://management.usgovcloudapi.net/",
|
ResourceManagerEndpoint: "https://management.usgovcloudapi.net/",
|
||||||
ActiveDirectoryEndpoint: "https://login.microsoftonline.com/",
|
ActiveDirectoryEndpoint: "https://login.microsoftonline.com/",
|
||||||
GalleryEndpoint: "https://gallery.usgovcloudapi.net/",
|
GalleryEndpoint: "https://gallery.usgovcloudapi.net/",
|
||||||
KeyVaultEndpoint: "https://vault.usgovcloudapi.net/",
|
KeyVaultEndpoint: "https://vault.usgovcloudapi.net/",
|
||||||
GraphEndpoint: "https://graph.usgovcloudapi.net/",
|
GraphEndpoint: "https://graph.usgovcloudapi.net/",
|
||||||
StorageEndpointSuffix: "core.usgovcloudapi.net",
|
StorageEndpointSuffix: "core.usgovcloudapi.net",
|
||||||
SQLDatabaseDNSSuffix: "database.usgovcloudapi.net",
|
SQLDatabaseDNSSuffix: "database.usgovcloudapi.net",
|
||||||
TrafficManagerDNSSuffix: "usgovtrafficmanager.net",
|
TrafficManagerDNSSuffix: "usgovtrafficmanager.net",
|
||||||
KeyVaultDNSSuffix: "vault.usgovcloudapi.net",
|
KeyVaultDNSSuffix: "vault.usgovcloudapi.net",
|
||||||
ServiceBusEndpointSuffix: "servicebus.usgovcloudapi.net",
|
ServiceBusEndpointSuffix: "servicebus.usgovcloudapi.net",
|
||||||
|
ServiceManagementVMDNSSuffix: "usgovcloudapp.net",
|
||||||
|
ResourceManagerVMDNSSuffix: "cloudapp.windowsazure.us",
|
||||||
|
ContainerRegistryDNSSuffix: "azurecr.io",
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChinaCloud is the cloud environment operated in China
|
// ChinaCloud is the cloud environment operated in China
|
||||||
ChinaCloud = Environment{
|
ChinaCloud = Environment{
|
||||||
Name: "AzureChinaCloud",
|
Name: "AzureChinaCloud",
|
||||||
ManagementPortalURL: "https://manage.chinacloudapi.com/",
|
ManagementPortalURL: "https://manage.chinacloudapi.com/",
|
||||||
PublishSettingsURL: "https://manage.chinacloudapi.com/publishsettings/index",
|
PublishSettingsURL: "https://manage.chinacloudapi.com/publishsettings/index",
|
||||||
ServiceManagementEndpoint: "https://management.core.chinacloudapi.cn/",
|
ServiceManagementEndpoint: "https://management.core.chinacloudapi.cn/",
|
||||||
ResourceManagerEndpoint: "https://management.chinacloudapi.cn/",
|
ResourceManagerEndpoint: "https://management.chinacloudapi.cn/",
|
||||||
ActiveDirectoryEndpoint: "https://login.chinacloudapi.cn/?api-version=1.0",
|
ActiveDirectoryEndpoint: "https://login.chinacloudapi.cn/",
|
||||||
GalleryEndpoint: "https://gallery.chinacloudapi.cn/",
|
GalleryEndpoint: "https://gallery.chinacloudapi.cn/",
|
||||||
KeyVaultEndpoint: "https://vault.azure.cn/",
|
KeyVaultEndpoint: "https://vault.azure.cn/",
|
||||||
GraphEndpoint: "https://graph.chinacloudapi.cn/",
|
GraphEndpoint: "https://graph.chinacloudapi.cn/",
|
||||||
StorageEndpointSuffix: "core.chinacloudapi.cn",
|
StorageEndpointSuffix: "core.chinacloudapi.cn",
|
||||||
SQLDatabaseDNSSuffix: "database.chinacloudapi.cn",
|
SQLDatabaseDNSSuffix: "database.chinacloudapi.cn",
|
||||||
TrafficManagerDNSSuffix: "trafficmanager.cn",
|
TrafficManagerDNSSuffix: "trafficmanager.cn",
|
||||||
KeyVaultDNSSuffix: "vault.azure.cn",
|
KeyVaultDNSSuffix: "vault.azure.cn",
|
||||||
ServiceBusEndpointSuffix: "servicebus.chinacloudapi.net",
|
ServiceBusEndpointSuffix: "servicebus.chinacloudapi.net",
|
||||||
|
ServiceManagementVMDNSSuffix: "chinacloudapp.cn",
|
||||||
|
ResourceManagerVMDNSSuffix: "cloudapp.azure.cn",
|
||||||
|
ContainerRegistryDNSSuffix: "azurecr.io",
|
||||||
}
|
}
|
||||||
|
|
||||||
// GermanCloud is the cloud environment operated in Germany
|
// GermanCloud is the cloud environment operated in Germany
|
||||||
GermanCloud = Environment{
|
GermanCloud = Environment{
|
||||||
Name: "AzureGermanCloud",
|
Name: "AzureGermanCloud",
|
||||||
ManagementPortalURL: "http://portal.microsoftazure.de/",
|
ManagementPortalURL: "http://portal.microsoftazure.de/",
|
||||||
PublishSettingsURL: "https://manage.microsoftazure.de/publishsettings/index",
|
PublishSettingsURL: "https://manage.microsoftazure.de/publishsettings/index",
|
||||||
ServiceManagementEndpoint: "https://management.core.cloudapi.de/",
|
ServiceManagementEndpoint: "https://management.core.cloudapi.de/",
|
||||||
ResourceManagerEndpoint: "https://management.microsoftazure.de/",
|
ResourceManagerEndpoint: "https://management.microsoftazure.de/",
|
||||||
ActiveDirectoryEndpoint: "https://login.microsoftonline.de/",
|
ActiveDirectoryEndpoint: "https://login.microsoftonline.de/",
|
||||||
GalleryEndpoint: "https://gallery.cloudapi.de/",
|
GalleryEndpoint: "https://gallery.cloudapi.de/",
|
||||||
KeyVaultEndpoint: "https://vault.microsoftazure.de/",
|
KeyVaultEndpoint: "https://vault.microsoftazure.de/",
|
||||||
GraphEndpoint: "https://graph.cloudapi.de/",
|
GraphEndpoint: "https://graph.cloudapi.de/",
|
||||||
StorageEndpointSuffix: "core.cloudapi.de",
|
StorageEndpointSuffix: "core.cloudapi.de",
|
||||||
SQLDatabaseDNSSuffix: "database.cloudapi.de",
|
SQLDatabaseDNSSuffix: "database.cloudapi.de",
|
||||||
TrafficManagerDNSSuffix: "azuretrafficmanager.de",
|
TrafficManagerDNSSuffix: "azuretrafficmanager.de",
|
||||||
KeyVaultDNSSuffix: "vault.microsoftazure.de",
|
KeyVaultDNSSuffix: "vault.microsoftazure.de",
|
||||||
ServiceBusEndpointSuffix: "servicebus.cloudapi.de",
|
ServiceBusEndpointSuffix: "servicebus.cloudapi.de",
|
||||||
|
ServiceManagementVMDNSSuffix: "azurecloudapp.de",
|
||||||
|
ResourceManagerVMDNSSuffix: "cloudapp.microsoftazure.de",
|
||||||
|
ContainerRegistryDNSSuffix: "azurecr.io",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -121,8 +136,13 @@ func EnvironmentFromName(name string) (Environment, error) {
|
||||||
|
|
||||||
// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls
|
// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls
|
||||||
func (env Environment) OAuthConfigForTenant(tenantID string) (*OAuthConfig, error) {
|
func (env Environment) OAuthConfigForTenant(tenantID string) (*OAuthConfig, error) {
|
||||||
|
return OAuthConfigForTenant(env.ActiveDirectoryEndpoint, tenantID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls for target cloud auth endpoint
|
||||||
|
func OAuthConfigForTenant(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
|
||||||
template := "%s/oauth2/%s?api-version=%s"
|
template := "%s/oauth2/%s?api-version=%s"
|
||||||
u, err := url.Parse(env.ActiveDirectoryEndpoint)
|
u, err := url.Parse(activeDirectoryEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ type ServicePrincipalNoSecret struct {
|
||||||
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret
|
// SetAuthenticationValues is a method of the interface ServicePrincipalSecret
|
||||||
// It only returns an error for the ServicePrincipalNoSecret type
|
// It only returns an error for the ServicePrincipalNoSecret type
|
||||||
func (noSecret *ServicePrincipalNoSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
func (noSecret *ServicePrincipalNoSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error {
|
||||||
return fmt.Errorf("Manually created ServicePrincipalToken does not contain secret material to retrieve a new access token.")
|
return fmt.Errorf("Manually created ServicePrincipalToken does not contain secret material to retrieve a new access token")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServicePrincipalSecret is an interface that allows various secret mechanism to fill the form
|
// ServicePrincipalSecret is an interface that allows various secret mechanism to fill the form
|
||||||
|
@ -138,7 +138,7 @@ func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalTo
|
||||||
token := jwt.New(jwt.SigningMethodRS256)
|
token := jwt.New(jwt.SigningMethodRS256)
|
||||||
token.Header["x5t"] = thumbprint
|
token.Header["x5t"] = thumbprint
|
||||||
token.Claims = jwt.MapClaims{
|
token.Claims = jwt.MapClaims{
|
||||||
"aud": spt.oauthConfig.TokenEndpoint,
|
"aud": spt.oauthConfig.TokenEndpoint.String(),
|
||||||
"iss": spt.clientID,
|
"iss": spt.clientID,
|
||||||
"sub": spt.clientID,
|
"sub": spt.clientID,
|
||||||
"jti": base64.URLEncoding.EncodeToString(jti),
|
"jti": base64.URLEncoding.EncodeToString(jti),
|
||||||
|
@ -302,7 +302,7 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error {
|
||||||
|
|
||||||
var newToken Token
|
var newToken Token
|
||||||
err = autorest.Respond(resp,
|
err = autorest.Respond(resp,
|
||||||
autorest.WithErrorUnlessOK(),
|
autorest.WithErrorUnlessStatusCode(http.StatusOK),
|
||||||
autorest.ByUnmarshallingJSON(&newToken),
|
autorest.ByUnmarshallingJSON(&newToken),
|
||||||
autorest.ByClosing())
|
autorest.ByClosing())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/cookiejar"
|
"net/http/cookiejar"
|
||||||
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,13 +23,24 @@ const (
|
||||||
DefaultRetryAttempts = 3
|
DefaultRetryAttempts = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
var statusCodesForRetry = []int{
|
var (
|
||||||
http.StatusRequestTimeout, // 408
|
// defaultUserAgent builds a string containing the Go version, system archityecture and OS,
|
||||||
http.StatusInternalServerError, // 500
|
// and the go-autorest version.
|
||||||
http.StatusBadGateway, // 502
|
defaultUserAgent = fmt.Sprintf("Go/%s (%s-%s) go-autorest/%s",
|
||||||
http.StatusServiceUnavailable, // 503
|
runtime.Version(),
|
||||||
http.StatusGatewayTimeout, // 504
|
runtime.GOARCH,
|
||||||
}
|
runtime.GOOS,
|
||||||
|
Version(),
|
||||||
|
)
|
||||||
|
|
||||||
|
statusCodesForRetry = []int{
|
||||||
|
http.StatusRequestTimeout, // 408
|
||||||
|
http.StatusInternalServerError, // 500
|
||||||
|
http.StatusBadGateway, // 502
|
||||||
|
http.StatusServiceUnavailable, // 503
|
||||||
|
http.StatusGatewayTimeout, // 504
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
requestFormat = `HTTP Request Begin ===================================================
|
requestFormat = `HTTP Request Begin ===================================================
|
||||||
|
@ -140,13 +152,24 @@ type Client struct {
|
||||||
// NewClientWithUserAgent returns an instance of a Client with the UserAgent set to the passed
|
// NewClientWithUserAgent returns an instance of a Client with the UserAgent set to the passed
|
||||||
// string.
|
// string.
|
||||||
func NewClientWithUserAgent(ua string) Client {
|
func NewClientWithUserAgent(ua string) Client {
|
||||||
return Client{
|
c := Client{
|
||||||
PollingDelay: DefaultPollingDelay,
|
PollingDelay: DefaultPollingDelay,
|
||||||
PollingDuration: DefaultPollingDuration,
|
PollingDuration: DefaultPollingDuration,
|
||||||
RetryAttempts: DefaultRetryAttempts,
|
RetryAttempts: DefaultRetryAttempts,
|
||||||
RetryDuration: 30 * time.Second,
|
RetryDuration: 30 * time.Second,
|
||||||
UserAgent: ua,
|
UserAgent: defaultUserAgent,
|
||||||
}
|
}
|
||||||
|
c.AddToUserAgent(ua)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddToUserAgent adds an extension to the current user agent
|
||||||
|
func (c *Client) AddToUserAgent(extension string) error {
|
||||||
|
if extension != "" {
|
||||||
|
c.UserAgent = fmt.Sprintf("%s %s", c.UserAgent, extension)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Extension was empty, User Agent stayed as %s", c.UserAgent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do implements the Sender interface by invoking the active Sender after applying authorization.
|
// Do implements the Sender interface by invoking the active Sender after applying authorization.
|
||||||
|
|
|
@ -28,6 +28,9 @@ type DetailedError struct {
|
||||||
|
|
||||||
// Message is the error message.
|
// Message is the error message.
|
||||||
Message string
|
Message string
|
||||||
|
|
||||||
|
// Service Error is the response body of failed API in bytes
|
||||||
|
ServiceError []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewError creates a new Error conforming object from the passed packageType, method, and
|
// NewError creates a new Error conforming object from the passed packageType, method, and
|
||||||
|
|
|
@ -183,6 +183,16 @@ func WithBaseURL(baseURL string) PrepareDecorator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithCustomBaseURL returns a PrepareDecorator that replaces brace-enclosed keys within the
|
||||||
|
// request base URL (i.e., http.Request.URL) with the corresponding values from the passed map.
|
||||||
|
func WithCustomBaseURL(baseURL string, urlParameters map[string]interface{}) PrepareDecorator {
|
||||||
|
parameters := ensureValueStrings(urlParameters)
|
||||||
|
for key, value := range parameters {
|
||||||
|
baseURL = strings.Replace(baseURL, "{"+key+"}", value, -1)
|
||||||
|
}
|
||||||
|
return WithBaseURL(baseURL)
|
||||||
|
}
|
||||||
|
|
||||||
// WithFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) into the
|
// WithFormData returns a PrepareDecoratore that "URL encodes" (e.g., bar=baz&foo=quux) into the
|
||||||
// http.Request body.
|
// http.Request body.
|
||||||
func WithFormData(v url.Values) PrepareDecorator {
|
func WithFormData(v url.Values) PrepareDecorator {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -87,6 +88,24 @@ func ByCopying(b *bytes.Buffer) RespondDecorator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ByDiscardingBody returns a RespondDecorator that first invokes the passed Responder after which
|
||||||
|
// it copies the remaining bytes (if any) in the response body to ioutil.Discard. Since the passed
|
||||||
|
// Responder is invoked prior to discarding the response body, the decorator may occur anywhere
|
||||||
|
// within the set.
|
||||||
|
func ByDiscardingBody() RespondDecorator {
|
||||||
|
return func(r Responder) Responder {
|
||||||
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
|
err := r.Respond(resp)
|
||||||
|
if err == nil && resp != nil && resp.Body != nil {
|
||||||
|
if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil {
|
||||||
|
return fmt.Errorf("Error discarding the response body: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ByClosing returns a RespondDecorator that first invokes the passed Responder after which it
|
// ByClosing returns a RespondDecorator that first invokes the passed Responder after which it
|
||||||
// closes the response body. Since the passed Responder is invoked prior to closing the response
|
// closes the response body. Since the passed Responder is invoked prior to closing the response
|
||||||
// body, the decorator may occur anywhere within the set.
|
// body, the decorator may occur anywhere within the set.
|
||||||
|
@ -128,6 +147,8 @@ func ByUnmarshallingJSON(v interface{}) RespondDecorator {
|
||||||
err := r.Respond(resp)
|
err := r.Respond(resp)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
b, errInner := ioutil.ReadAll(resp.Body)
|
b, errInner := ioutil.ReadAll(resp.Body)
|
||||||
|
// Some responses might include a BOM, remove for successful unmarshalling
|
||||||
|
b = bytes.TrimPrefix(b, []byte("\xef\xbb\xbf"))
|
||||||
if errInner != nil {
|
if errInner != nil {
|
||||||
err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner)
|
err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner)
|
||||||
} else if len(strings.Trim(string(b), " ")) > 0 {
|
} else if len(strings.Trim(string(b), " ")) > 0 {
|
||||||
|
@ -165,17 +186,24 @@ func ByUnmarshallingXML(v interface{}) RespondDecorator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithErrorUnlessStatusCode returns a RespondDecorator that emits an error unless the response
|
// WithErrorUnlessStatusCode returns a RespondDecorator that emits an error unless the response
|
||||||
// StatusCode is among the set passed. Since these are artificial errors, the response body
|
// StatusCode is among the set passed. On error, response body is fully read into a buffer and
|
||||||
// may still require closing.
|
// presented in the returned error, as well as in the response body.
|
||||||
func WithErrorUnlessStatusCode(codes ...int) RespondDecorator {
|
func WithErrorUnlessStatusCode(codes ...int) RespondDecorator {
|
||||||
return func(r Responder) Responder {
|
return func(r Responder) Responder {
|
||||||
return ResponderFunc(func(resp *http.Response) error {
|
return ResponderFunc(func(resp *http.Response) error {
|
||||||
err := r.Respond(resp)
|
err := r.Respond(resp)
|
||||||
if err == nil && !ResponseHasStatusCode(resp, codes...) {
|
if err == nil && !ResponseHasStatusCode(resp, codes...) {
|
||||||
err = NewErrorWithResponse("autorest", "WithErrorUnlessStatusCode", resp, "%v %v failed with %s",
|
derr := NewErrorWithResponse("autorest", "WithErrorUnlessStatusCode", resp, "%v %v failed with %s",
|
||||||
resp.Request.Method,
|
resp.Request.Method,
|
||||||
resp.Request.URL,
|
resp.Request.URL,
|
||||||
resp.Status)
|
resp.Status)
|
||||||
|
if resp.Body != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
b, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
derr.ServiceError = b
|
||||||
|
resp.Body = ioutil.NopCloser(bytes.NewReader(b))
|
||||||
|
}
|
||||||
|
err = derr
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
|
@ -73,7 +73,7 @@ func SendWithSender(s Sender, r *http.Request, decorators ...SendDecorator) (*ht
|
||||||
func AfterDelay(d time.Duration) SendDecorator {
|
func AfterDelay(d time.Duration) SendDecorator {
|
||||||
return func(s Sender) Sender {
|
return func(s Sender) Sender {
|
||||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
if !DelayForBackoff(d, 1, r.Cancel) {
|
if !DelayForBackoff(d, 0, r.Cancel) {
|
||||||
return nil, fmt.Errorf("autorest: AfterDelay canceled before full delay")
|
return nil, fmt.Errorf("autorest: AfterDelay canceled before full delay")
|
||||||
}
|
}
|
||||||
return s.Do(r)
|
return s.Do(r)
|
||||||
|
@ -97,7 +97,7 @@ func DoCloseIfError() SendDecorator {
|
||||||
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
return SenderFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
resp, err := s.Do(r)
|
resp, err := s.Do(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Respond(resp, ByClosing())
|
Respond(resp, ByDiscardingBody(), ByClosing())
|
||||||
}
|
}
|
||||||
return resp, err
|
return resp, err
|
||||||
})
|
})
|
||||||
|
@ -156,6 +156,7 @@ func DoPollForStatusCodes(duration time.Duration, delay time.Duration, codes ...
|
||||||
|
|
||||||
for err == nil && ResponseHasStatusCode(resp, codes...) {
|
for err == nil && ResponseHasStatusCode(resp, codes...) {
|
||||||
Respond(resp,
|
Respond(resp,
|
||||||
|
ByDiscardingBody(),
|
||||||
ByClosing())
|
ByClosing())
|
||||||
resp, err = SendWithSender(s, r,
|
resp, err = SendWithSender(s, r,
|
||||||
AfterDelay(GetRetryAfter(resp, delay)))
|
AfterDelay(GetRetryAfter(resp, delay)))
|
||||||
|
@ -257,6 +258,8 @@ func WithLogging(logger *log.Logger) SendDecorator {
|
||||||
// passed attempt (i.e., an exponential backoff delay). Backoff duration is in seconds and can set
|
// passed attempt (i.e., an exponential backoff delay). Backoff duration is in seconds and can set
|
||||||
// to zero for no delay. The delay may be canceled by closing the passed channel. If terminated early,
|
// to zero for no delay. The delay may be canceled by closing the passed channel. If terminated early,
|
||||||
// returns false.
|
// returns false.
|
||||||
|
// Note: Passing attempt 1 will result in doubling "backoff" duration. Treat this as a zero-based attempt
|
||||||
|
// count.
|
||||||
func DelayForBackoff(backoff time.Duration, attempt int, cancel <-chan struct{}) bool {
|
func DelayForBackoff(backoff time.Duration, attempt int, cancel <-chan struct{}) bool {
|
||||||
select {
|
select {
|
||||||
case <-time.After(time.Duration(backoff.Seconds()*math.Pow(2, float64(attempt))) * time.Second):
|
case <-time.After(time.Duration(backoff.Seconds()*math.Pow(2, float64(attempt))) * time.Second):
|
||||||
|
|
|
@ -2,17 +2,28 @@ package autorest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
major = "7"
|
major = 7
|
||||||
minor = "0"
|
minor = 3
|
||||||
patch = "0"
|
patch = 1
|
||||||
tag = ""
|
tag = ""
|
||||||
semVerFormat = "%s.%s.%s%s"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var versionLock sync.Once
|
||||||
|
var version string
|
||||||
|
|
||||||
// Version returns the semantic version (see http://semver.org).
|
// Version returns the semantic version (see http://semver.org).
|
||||||
func Version() string {
|
func Version() string {
|
||||||
return fmt.Sprintf(semVerFormat, major, minor, patch, tag)
|
versionLock.Do(func() {
|
||||||
|
version = fmt.Sprintf("v%d.%d.%d", major, minor, patch)
|
||||||
|
|
||||||
|
if trimmed := strings.TrimPrefix(tag, "-"); trimmed != "" {
|
||||||
|
version = fmt.Sprintf("%s-%s", version, trimmed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return version
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,48 +276,48 @@
|
||||||
"revisionTime": "2016-06-22T17:32:16Z"
|
"revisionTime": "2016-06-22T17:32:16Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "eVSHe6GIHj9/ziFrQLZ1SC7Nn6k=",
|
"checksumSHA1": "U2+FgaMOPEFg/yHLD5RbiXI1cq4=",
|
||||||
"comment": "v7.0.5",
|
"comment": "v7.0.5",
|
||||||
"path": "github.com/Azure/go-autorest/autorest",
|
"path": "github.com/Azure/go-autorest/autorest",
|
||||||
"revision": "0781901f19f1e7db3034d97ec57af753db0bf808",
|
"revision": "a2fdd780c9a50455cecd249b00bdc3eb73a78e31",
|
||||||
"revisionTime": "2016-10-03T18:39:13Z",
|
"revisionTime": "2017-04-06T20:28:05Z",
|
||||||
"version": "v7.2.1",
|
"version": "v7.3.1",
|
||||||
"versionExact": "v7.2.1"
|
"versionExact": "v7.3.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "z8FwqeLK0Pluo7FYC5k2MVBoils=",
|
"checksumSHA1": "ghrnc4vZv6q8zzeakZnrS8CGFhE=",
|
||||||
"comment": "v7.0.5",
|
"comment": "v7.0.5",
|
||||||
"path": "github.com/Azure/go-autorest/autorest/azure",
|
"path": "github.com/Azure/go-autorest/autorest/azure",
|
||||||
"revision": "0781901f19f1e7db3034d97ec57af753db0bf808",
|
"revision": "a2fdd780c9a50455cecd249b00bdc3eb73a78e31",
|
||||||
"revisionTime": "2016-10-03T18:39:13Z",
|
"revisionTime": "2017-04-06T20:28:05Z",
|
||||||
"version": "v7.2.1",
|
"version": "v7.3.1",
|
||||||
"versionExact": "v7.2.1"
|
"versionExact": "v7.3.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "q9Qz8PAxK5FTOZwgYKe5Lj38u4c=",
|
"checksumSHA1": "q9Qz8PAxK5FTOZwgYKe5Lj38u4c=",
|
||||||
"comment": "v7.0.5",
|
"comment": "v7.0.5",
|
||||||
"path": "github.com/Azure/go-autorest/autorest/date",
|
"path": "github.com/Azure/go-autorest/autorest/date",
|
||||||
"revision": "0781901f19f1e7db3034d97ec57af753db0bf808",
|
"revision": "a2fdd780c9a50455cecd249b00bdc3eb73a78e31",
|
||||||
"revisionTime": "2016-10-03T18:39:13Z",
|
"revisionTime": "2017-04-06T20:28:05Z",
|
||||||
"version": "v7.2.1",
|
"version": "v7.3.1",
|
||||||
"versionExact": "v7.2.1"
|
"versionExact": "v7.3.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "Ev8qCsbFjDlMlX0N2tYAhYQFpUc=",
|
"checksumSHA1": "Ev8qCsbFjDlMlX0N2tYAhYQFpUc=",
|
||||||
"comment": "v7.0.5",
|
"comment": "v7.0.5",
|
||||||
"path": "github.com/Azure/go-autorest/autorest/to",
|
"path": "github.com/Azure/go-autorest/autorest/to",
|
||||||
"revision": "0781901f19f1e7db3034d97ec57af753db0bf808",
|
"revision": "a2fdd780c9a50455cecd249b00bdc3eb73a78e31",
|
||||||
"revisionTime": "2016-10-03T18:39:13Z",
|
"revisionTime": "2017-04-06T20:28:05Z",
|
||||||
"version": "v7.2.1",
|
"version": "v7.3.1",
|
||||||
"versionExact": "v7.2.1"
|
"versionExact": "v7.3.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "oBixceM+55gdk47iff8DSEIh3po=",
|
"checksumSHA1": "oBixceM+55gdk47iff8DSEIh3po=",
|
||||||
"path": "github.com/Azure/go-autorest/autorest/validation",
|
"path": "github.com/Azure/go-autorest/autorest/validation",
|
||||||
"revision": "0781901f19f1e7db3034d97ec57af753db0bf808",
|
"revision": "a2fdd780c9a50455cecd249b00bdc3eb73a78e31",
|
||||||
"revisionTime": "2016-10-03T18:39:13Z",
|
"revisionTime": "2017-04-06T20:28:05Z",
|
||||||
"version": "v7.2.1",
|
"version": "v7.3.1",
|
||||||
"versionExact": "v7.2.1"
|
"versionExact": "v7.3.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "ICScouhAqYHoJEpJlJMYg7EzgyY=",
|
"checksumSHA1": "ICScouhAqYHoJEpJlJMYg7EzgyY=",
|
||||||
|
|
Loading…
Reference in New Issue