diff --git a/backend/remote-state/azure/arm_client.go b/backend/remote-state/azure/arm_client.go new file mode 100644 index 000000000..90e4b261d --- /dev/null +++ b/backend/remote-state/azure/arm_client.go @@ -0,0 +1,131 @@ +package azure + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources" + armStorage "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/storage/mgmt/storage" + "github.com/Azure/azure-sdk-for-go/storage" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/hashicorp/go-azure-helpers/authentication" + "github.com/hashicorp/terraform/httpclient" +) + +type ArmClient struct { + // These Clients are only initialized if an Access Key isn't provided + groupsClient *resources.GroupsClient + storageAccountsClient *armStorage.AccountsClient + + accessKey string + environment azure.Environment + resourceGroupName string + storageAccountName string +} + +func buildArmClient(config BackendConfig) (*ArmClient, error) { + env, err := authentication.DetermineEnvironment(config.Environment) + if err != nil { + return nil, err + } + client := ArmClient{ + environment: *env, + resourceGroupName: config.ResourceGroupName, + storageAccountName: config.StorageAccountName, + } + + // if we have an Access Key - we don't need the other clients + if config.AccessKey != "" { + client.accessKey = config.AccessKey + return &client, nil + } + + builder := authentication.Builder{ + ClientID: config.ClientID, + ClientSecret: config.ClientSecret, + SubscriptionID: config.SubscriptionID, + TenantID: config.TenantID, + Environment: config.Environment, + + // Feature Toggles + SupportsClientSecretAuth: true, + // TODO: support for Azure CLI / Client Certificate / MSI + } + armConfig, err := builder.Build() + if err != nil { + return nil, fmt.Errorf("Error building ARM Config: %+v", err) + } + + oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, armConfig.TenantID) + if err != nil { + return nil, err + } + + auth, err := armConfig.GetAuthorizationToken(oauthConfig, env.ResourceManagerEndpoint) + if err != nil { + return nil, err + } + + accountsClient := armStorage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, armConfig.SubscriptionID) + client.configureClient(&accountsClient.Client, auth) + client.storageAccountsClient = &accountsClient + + groupsClient := resources.NewGroupsClientWithBaseURI(env.ResourceManagerEndpoint, armConfig.SubscriptionID) + client.configureClient(&groupsClient.Client, auth) + client.groupsClient = &groupsClient + + return &client, nil +} + +func (c ArmClient) getBlobClient(ctx context.Context) (*storage.BlobStorageClient, error) { + if c.accessKey != "" { + storageClient, err := storage.NewBasicClientOnSovereignCloud(c.storageAccountName, c.accessKey, c.environment) + if err != nil { + return nil, fmt.Errorf("Error creating storage client for storage account %q: %s", c.storageAccountName, err) + } + client := storageClient.GetBlobService() + return &client, nil + } + + keys, err := c.storageAccountsClient.ListKeys(ctx, c.resourceGroupName, c.storageAccountName) + if err != nil { + return nil, fmt.Errorf("Error retrieving keys for Storage Account %q: %s", c.storageAccountName, err) + } + + if keys.Keys == nil { + return nil, fmt.Errorf("Nil key returned for storage account %q", c.storageAccountName) + } + + accessKeys := *keys.Keys + accessKey := accessKeys[0].Value + + storageClient, err := storage.NewBasicClientOnSovereignCloud(c.storageAccountName, *accessKey, c.environment) + if err != nil { + return nil, fmt.Errorf("Error creating storage client for storage account %q: %s", c.storageAccountName, err) + } + client := storageClient.GetBlobService() + return &client, nil +} + +func (c *ArmClient) configureClient(client *autorest.Client, auth autorest.Authorizer) { + client.UserAgent = buildUserAgent() + client.Authorizer = auth + client.Sender = buildSender() + client.SkipResourceProviderRegistration = false + client.PollingDuration = 60 * time.Minute +} + +func buildUserAgent() string { + userAgent := httpclient.UserAgentString() + + // append the CloudShell version to the user agent if it exists + if azureAgent := os.Getenv("AZURE_HTTP_USER_AGENT"); azureAgent != "" { + userAgent = fmt.Sprintf("%s %s", userAgent, azureAgent) + } + + return userAgent +} diff --git a/backend/remote-state/azure/backend.go b/backend/remote-state/azure/backend.go index fb91f259e..a930cbb02 100644 --- a/backend/remote-state/azure/backend.go +++ b/backend/remote-state/azure/backend.go @@ -4,17 +4,11 @@ import ( "context" "fmt" - armStorage "github.com/Azure/azure-sdk-for-go/arm/storage" - "github.com/Azure/azure-sdk-for-go/storage" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/helper/schema" ) -// New creates a new backend for S3 remote state. +// New creates a new backend for Azure remote state. func New() backend.Backend { s := &schema.Backend{ Schema: map[string]*schema.Schema{ @@ -40,7 +34,7 @@ func New() backend.Backend { Type: schema.TypeString, Optional: true, Description: "The Azure cloud environment.", - DefaultFunc: schema.EnvDefaultFunc("ARM_ENVIRONMENT", ""), + DefaultFunc: schema.EnvDefaultFunc("ARM_ENVIRONMENT", "public"), }, "access_key": { @@ -83,6 +77,9 @@ func New() backend.Backend { Description: "The Tenant ID.", DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""), }, + + // TODO: rename these fields + // TODO: support for custom resource manager endpoints }, } @@ -95,22 +92,23 @@ type Backend struct { *schema.Backend // The fields below are set from configure - blobClient storage.BlobStorageClient - + armClient *ArmClient containerName string keyName string - leaseID string } type BackendConfig struct { - AccessKey string - Environment string - ClientID string - ClientSecret string - ResourceGroupName string + // Required StorageAccountName string - SubscriptionID string - TenantID string + + // Optional + AccessKey string + ClientID string + ClientSecret string + Environment string + ResourceGroupName string + SubscriptionID string + TenantID string } func (b *Backend) configure(ctx context.Context) error { @@ -135,92 +133,15 @@ func (b *Backend) configure(ctx context.Context) error { TenantID: data.Get("arm_tenant_id").(string), } - blobClient, err := getBlobClient(config) + armClient, err := buildArmClient(config) if err != nil { return err } - b.blobClient = blobClient + if config.AccessKey == "" && config.ResourceGroupName == "" { + return fmt.Errorf("Either an Access Key or the Resource Group for the Storage Account must be specified") + } + + b.armClient = armClient return nil } - -func getBlobClient(config BackendConfig) (storage.BlobStorageClient, error) { - var client storage.BlobStorageClient - - env, err := getAzureEnvironment(config.Environment) - if err != nil { - return client, err - } - - accessKey, err := getAccessKey(config, env) - if err != nil { - return client, err - } - - storageClient, err := storage.NewClient(config.StorageAccountName, accessKey, env.StorageEndpointSuffix, - storage.DefaultAPIVersion, true) - if err != nil { - return client, fmt.Errorf("Error creating storage client for storage account %q: %s", config.StorageAccountName, err) - } - - client = storageClient.GetBlobService() - return client, nil -} - -func getAccessKey(config BackendConfig, env azure.Environment) (string, error) { - if config.AccessKey != "" { - return config.AccessKey, nil - } - - rgOk := config.ResourceGroupName != "" - subOk := config.SubscriptionID != "" - clientIDOk := config.ClientID != "" - clientSecretOK := config.ClientSecret != "" - tenantIDOk := config.TenantID != "" - if !rgOk || !subOk || !clientIDOk || !clientSecretOK || !tenantIDOk { - return "", fmt.Errorf("resource_group_name and credentials must be provided when access_key is absent") - } - - oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, config.TenantID) - if err != nil { - return "", err - } - - spt, err := adal.NewServicePrincipalToken(*oauthConfig, config.ClientID, config.ClientSecret, env.ResourceManagerEndpoint) - if err != nil { - return "", err - } - - accountsClient := armStorage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, config.SubscriptionID) - accountsClient.Authorizer = autorest.NewBearerAuthorizer(spt) - - keys, err := accountsClient.ListKeys(config.ResourceGroupName, config.StorageAccountName) - if err != nil { - return "", fmt.Errorf("Error retrieving keys for storage account %q: %s", config.StorageAccountName, err) - } - - if keys.Keys == nil { - return "", fmt.Errorf("Nil key returned for storage account %q", config.StorageAccountName) - } - - accessKeys := *keys.Keys - return *accessKeys[0].Value, nil -} - -func getAzureEnvironment(environment string) (azure.Environment, error) { - if environment == "" { - return azure.PublicCloud, nil - } - - env, err := azure.EnvironmentFromName(environment) - if err != nil { - // try again with wrapped value to support readable values like german instead of AZUREGERMANCLOUD - var innerErr error - env, innerErr = azure.EnvironmentFromName(fmt.Sprintf("AZURE%sCLOUD", environment)) - if innerErr != nil { - return env, fmt.Errorf("invalid 'environment' configuration: %s", err) - } - } - - return env, nil -} diff --git a/backend/remote-state/azure/backend_state.go b/backend/remote-state/azure/backend_state.go index 439d060ed..cd0054eda 100644 --- a/backend/remote-state/azure/backend_state.go +++ b/backend/remote-state/azure/backend_state.go @@ -1,12 +1,12 @@ package azure import ( + "context" "fmt" "sort" "strings" "github.com/Azure/azure-sdk-for-go/storage" - "github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state/remote" @@ -25,7 +25,12 @@ func (b *Backend) Workspaces() ([]string, error) { Prefix: prefix, } - container := b.blobClient.GetContainerReference(b.containerName) + ctx := context.TODO() + client, err := b.armClient.getBlobClient(ctx) + if err != nil { + return nil, err + } + container := client.GetContainerReference(b.containerName) resp, err := container.ListBlobs(params) if err != nil { return nil, err @@ -58,7 +63,13 @@ func (b *Backend) DeleteWorkspace(name string) error { return fmt.Errorf("can't delete default state") } - containerReference := b.blobClient.GetContainerReference(b.containerName) + ctx := context.TODO() + client, err := b.armClient.getBlobClient(ctx) + if err != nil { + return err + } + + containerReference := client.GetContainerReference(b.containerName) blobReference := containerReference.GetBlobReference(b.path(name)) options := &storage.DeleteBlobOptions{} @@ -66,8 +77,14 @@ func (b *Backend) DeleteWorkspace(name string) error { } func (b *Backend) StateMgr(name string) (state.State, error) { + ctx := context.TODO() + blobClient, err := b.armClient.getBlobClient(ctx) + if err != nil { + return nil, err + } + client := &RemoteClient{ - blobClient: b.blobClient, + blobClient: *blobClient, containerName: b.containerName, keyName: b.path(name), } diff --git a/backend/remote-state/azure/backend_test.go b/backend/remote-state/azure/backend_test.go index 9c8f69a20..1df684e1a 100644 --- a/backend/remote-state/azure/backend_test.go +++ b/backend/remote-state/azure/backend_test.go @@ -1,29 +1,14 @@ package azure import ( - "fmt" + "context" "os" "testing" - "github.com/Azure/azure-sdk-for-go/arm/resources/resources" - armStorage "github.com/Azure/azure-sdk-for-go/arm/storage" - "github.com/Azure/azure-sdk-for-go/storage" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/adal" - "github.com/Azure/go-autorest/autorest/azure" "github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/helper/acctest" ) -// verify that we are doing ACC tests or the Azure tests specifically -func testACC(t *testing.T) { - skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_AZURE_TEST") == "" - if skip { - t.Log("azure backend tests require setting TF_ACC or TF_AZURE_TEST") - t.Skip() - } -} - func TestBackend_impl(t *testing.T) { var _ backend.Backend = new(Backend) } @@ -50,183 +35,129 @@ func TestBackendConfig(t *testing.T) { } } -func TestBackend(t *testing.T) { - testACC(t) +func TestBackendAccessKeyBasic(t *testing.T) { + testAccAzureBackend(t) + rs := acctest.RandString(4) + res := testResourceNames(rs, "testState") + armClient := buildTestClient(t, res) - keyName := "testState" - res := setupResources(t, keyName) - defer destroyResources(t, res.resourceGroupName) + ctx := context.TODO() + err := armClient.buildTestResources(ctx, &res) + if err != nil { + armClient.destroyTestResources(ctx, res) + t.Fatalf("Error creating Test Resources: %q", err) + } + defer armClient.destroyTestResources(ctx, res) b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ "storage_account_name": res.storageAccountName, - "container_name": res.containerName, - "key": keyName, - "access_key": res.accessKey, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "access_key": res.storageAccountAccessKey, })).(*Backend) backend.TestBackendStates(t, b) } -func TestBackendLocked(t *testing.T) { - testACC(t) +func TestBackendServicePrincipalBasic(t *testing.T) { + testAccAzureBackend(t) + rs := acctest.RandString(4) + res := testResourceNames(rs, "testState") + armClient := buildTestClient(t, res) - keyName := "testState" - res := setupResources(t, keyName) - defer destroyResources(t, res.resourceGroupName) + ctx := context.TODO() + err := armClient.buildTestResources(ctx, &res) + if err != nil { + armClient.destroyTestResources(ctx, res) + t.Fatalf("Error creating Test Resources: %q", err) + } + defer armClient.destroyTestResources(ctx, res) + + b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ + "storage_account_name": res.storageAccountName, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "resource_group_name": res.resourceGroup, + "arm_subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"), + "arm_tenant_id": os.Getenv("ARM_TENANT_ID"), + "arm_client_id": os.Getenv("ARM_CLIENT_ID"), + "arm_client_secret": os.Getenv("ARM_CLIENT_SECRET"), + "environment": os.Getenv("ARM_ENVIRONMENT"), + })).(*Backend) + + backend.TestBackendStates(t, b) +} + +func TestBackendAccessKeyLocked(t *testing.T) { + testAccAzureBackend(t) + rs := acctest.RandString(4) + res := testResourceNames(rs, "testState") + armClient := buildTestClient(t, res) + + ctx := context.TODO() + err := armClient.buildTestResources(ctx, &res) + if err != nil { + armClient.destroyTestResources(ctx, res) + t.Fatalf("Error creating Test Resources: %q", err) + } + defer armClient.destroyTestResources(ctx, res) b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ "storage_account_name": res.storageAccountName, - "container_name": res.containerName, - "key": keyName, - "access_key": res.accessKey, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "access_key": res.storageAccountAccessKey, })).(*Backend) b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ "storage_account_name": res.storageAccountName, - "container_name": res.containerName, - "key": keyName, - "access_key": res.accessKey, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "access_key": res.storageAccountAccessKey, })).(*Backend) backend.TestBackendStateLocks(t, b1, b2) backend.TestBackendStateForceUnlock(t, b1, b2) } -type testResources struct { - resourceGroupName string - storageAccountName string - containerName string - keyName string - accessKey string -} - -func setupResources(t *testing.T, keyName string) testResources { - clients := getTestClient(t) - - ri := acctest.RandInt() +func TestBackendServicePrincipalLocked(t *testing.T) { + testAccAzureBackend(t) rs := acctest.RandString(4) - res := testResources{ - resourceGroupName: fmt.Sprintf("terraform-backend-testing-%d", ri), - storageAccountName: fmt.Sprintf("tfbackendtesting%s", rs), - containerName: "terraform", - keyName: keyName, - } + res := testResourceNames(rs, "testState") + armClient := buildTestClient(t, res) - location := os.Getenv("ARM_LOCATION") - if location == "" { - location = "westus" - } - - t.Logf("creating resource group %s", res.resourceGroupName) - _, err := clients.groupsClient.CreateOrUpdate(res.resourceGroupName, resources.Group{Location: &location}) + ctx := context.TODO() + err := armClient.buildTestResources(ctx, &res) if err != nil { - t.Fatalf("failed to create test resource group: %s", err) + armClient.destroyTestResources(ctx, res) + t.Fatalf("Error creating Test Resources: %q", err) } + defer armClient.destroyTestResources(ctx, res) - t.Logf("creating storage account %s", res.storageAccountName) - _, createError := clients.storageAccountsClient.Create(res.resourceGroupName, res.storageAccountName, armStorage.AccountCreateParameters{ - Sku: &armStorage.Sku{ - Name: armStorage.StandardLRS, - Tier: armStorage.Standard, - }, - Location: &location, - }, make(chan struct{})) - createErr := <-createError - if createErr != nil { - destroyResources(t, res.resourceGroupName) - t.Fatalf("failed to create test storage account: %s", err) - } + b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ + "storage_account_name": res.storageAccountName, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "access_key": res.storageAccountAccessKey, + "arm_subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"), + "arm_tenant_id": os.Getenv("ARM_TENANT_ID"), + "arm_client_id": os.Getenv("ARM_CLIENT_ID"), + "arm_client_secret": os.Getenv("ARM_CLIENT_SECRET"), + "environment": os.Getenv("ARM_ENVIRONMENT"), + })).(*Backend) - t.Log("fetching access key for storage account") - resp, err := clients.storageAccountsClient.ListKeys(res.resourceGroupName, res.storageAccountName) - if err != nil { - destroyResources(t, res.resourceGroupName) - t.Fatalf("failed to list storage account keys %s:", err) - } + b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ + "storage_account_name": res.storageAccountName, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "access_key": res.storageAccountAccessKey, + "arm_subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"), + "arm_tenant_id": os.Getenv("ARM_TENANT_ID"), + "arm_client_id": os.Getenv("ARM_CLIENT_ID"), + "arm_client_secret": os.Getenv("ARM_CLIENT_SECRET"), + "environment": os.Getenv("ARM_ENVIRONMENT"), + })).(*Backend) - keys := *resp.Keys - res.accessKey = *keys[0].Value - - storageClient, err := storage.NewClient(res.storageAccountName, res.accessKey, - clients.environment.StorageEndpointSuffix, storage.DefaultAPIVersion, true) - if err != nil { - destroyResources(t, res.resourceGroupName) - t.Fatalf("failed to list storage account keys %s:", err) - } - - t.Logf("creating container %s", res.containerName) - blobService := storageClient.GetBlobService() - container := blobService.GetContainerReference(res.containerName) - err = container.Create(&storage.CreateContainerOptions{}) - if err != nil { - destroyResources(t, res.resourceGroupName) - t.Fatalf("failed to create storage container: %s", err) - } - - return res -} - -func destroyResources(t *testing.T, resourceGroupName string) { - warning := "WARNING: Failed to delete the test Azure resources. They may incur charges. (error was %s)" - - clients := getTestClient(t) - - t.Log("destroying created resources") - - // destroying is simple as deleting the resource group will destroy everything else - _, deleteErr := clients.groupsClient.Delete(resourceGroupName, make(chan struct{})) - err := <-deleteErr - if err != nil { - t.Logf(warning, err) - return - } - - t.Log("Azure resources destroyed") -} - -type testClient struct { - subscriptionID string - tenantID string - clientID string - clientSecret string - environment azure.Environment - groupsClient resources.GroupsClient - storageAccountsClient armStorage.AccountsClient -} - -func getTestClient(t *testing.T) testClient { - client := testClient{ - subscriptionID: os.Getenv("ARM_SUBSCRIPTION_ID"), - tenantID: os.Getenv("ARM_TENANT_ID"), - clientID: os.Getenv("ARM_CLIENT_ID"), - clientSecret: os.Getenv("ARM_CLIENT_SECRET"), - } - - if client.subscriptionID == "" || client.tenantID == "" || client.clientID == "" || client.clientSecret == "" { - t.Fatal("Azure credentials missing or incomplete") - } - - env, err := getAzureEnvironment(os.Getenv("ARM_ENVIRONMENT")) - if err != nil { - t.Fatalf("Failed to detect Azure environment from ARM_ENVIRONMENT value: %s", os.Getenv("ARM_ENVIRONMENT")) - } - client.environment = env - - oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, client.tenantID) - if err != nil { - t.Fatalf("Failed to get OAuth config: %s", err) - } - - spt, err := adal.NewServicePrincipalToken(*oauthConfig, client.clientID, client.clientSecret, env.ResourceManagerEndpoint) - if err != nil { - t.Fatalf("Failed to create Service Principal Token: %s", err) - } - - client.groupsClient = resources.NewGroupsClientWithBaseURI(env.ResourceManagerEndpoint, client.subscriptionID) - client.groupsClient.Authorizer = autorest.NewBearerAuthorizer(spt) - - client.storageAccountsClient = armStorage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, client.subscriptionID) - client.storageAccountsClient.Authorizer = autorest.NewBearerAuthorizer(spt) - - return client + backend.TestBackendStateLocks(t, b1, b2) + backend.TestBackendStateForceUnlock(t, b1, b2) } diff --git a/backend/remote-state/azure/client.go b/backend/remote-state/azure/client.go index d474bae95..acbbaf8cb 100644 --- a/backend/remote-state/azure/client.go +++ b/backend/remote-state/azure/client.go @@ -9,9 +9,8 @@ import ( "log" "github.com/Azure/azure-sdk-for-go/storage" - multierror "github.com/hashicorp/go-multierror" - uuid "github.com/hashicorp/go-uuid" - + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state/remote" "github.com/hashicorp/terraform/states" diff --git a/backend/remote-state/azure/client_test.go b/backend/remote-state/azure/client_test.go index 9d8c7bad9..d3edfd39b 100644 --- a/backend/remote-state/azure/client_test.go +++ b/backend/remote-state/azure/client_test.go @@ -1,6 +1,8 @@ package azure import ( + "context" + "os" "testing" "github.com/Azure/azure-sdk-for-go/storage" @@ -14,18 +16,25 @@ func TestRemoteClient_impl(t *testing.T) { var _ remote.ClientLocker = new(RemoteClient) } -func TestRemoteClient(t *testing.T) { - testACC(t) +func TestRemoteClientAccessKeyBasic(t *testing.T) { + testAccAzureBackend(t) + rs := acctest.RandString(4) + res := testResourceNames(rs, "testState") + armClient := buildTestClient(t, res) - keyName := "testState" - res := setupResources(t, keyName) - defer destroyResources(t, res.resourceGroupName) + ctx := context.TODO() + err := armClient.buildTestResources(ctx, &res) + if err != nil { + armClient.destroyTestResources(ctx, res) + t.Fatalf("Error creating Test Resources: %q", err) + } + defer armClient.destroyTestResources(ctx, res) b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ "storage_account_name": res.storageAccountName, - "container_name": res.containerName, - "key": keyName, - "access_key": res.accessKey, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "access_key": res.storageAccountAccessKey, })).(*Backend) state, err := b.StateMgr(backend.DefaultStateName) @@ -36,25 +45,117 @@ func TestRemoteClient(t *testing.T) { remote.TestClient(t, state.(*remote.State).Client) } -func TestRemoteClientLocks(t *testing.T) { - testACC(t) +func TestRemoteClientServicePrincipalBasic(t *testing.T) { + testAccAzureBackend(t) + rs := acctest.RandString(4) + res := testResourceNames(rs, "testState") + armClient := buildTestClient(t, res) - keyName := "testState" - res := setupResources(t, keyName) - defer destroyResources(t, res.resourceGroupName) + ctx := context.TODO() + err := armClient.buildTestResources(ctx, &res) + if err != nil { + armClient.destroyTestResources(ctx, res) + t.Fatalf("Error creating Test Resources: %q", err) + } + defer armClient.destroyTestResources(ctx, res) + + b := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ + "storage_account_name": res.storageAccountName, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "resource_group_name": res.resourceGroup, + "arm_subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"), + "arm_tenant_id": os.Getenv("ARM_TENANT_ID"), + "arm_client_id": os.Getenv("ARM_CLIENT_ID"), + "arm_client_secret": os.Getenv("ARM_CLIENT_SECRET"), + "environment": os.Getenv("ARM_ENVIRONMENT"), + })).(*Backend) + + state, err := b.StateMgr(backend.DefaultStateName) + if err != nil { + t.Fatal(err) + } + + remote.TestClient(t, state.(*remote.State).Client) +} + +func TestRemoteClientAccessKeyLocks(t *testing.T) { + testAccAzureBackend(t) + rs := acctest.RandString(4) + res := testResourceNames(rs, "testState") + armClient := buildTestClient(t, res) + + ctx := context.TODO() + err := armClient.buildTestResources(ctx, &res) + if err != nil { + armClient.destroyTestResources(ctx, res) + t.Fatalf("Error creating Test Resources: %q", err) + } + defer armClient.destroyTestResources(ctx, res) b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ "storage_account_name": res.storageAccountName, - "container_name": res.containerName, - "key": keyName, - "access_key": res.accessKey, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "access_key": res.storageAccountAccessKey, })).(*Backend) b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ "storage_account_name": res.storageAccountName, - "container_name": res.containerName, - "key": keyName, - "access_key": res.accessKey, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "access_key": res.storageAccountAccessKey, + })).(*Backend) + + s1, err := b1.StateMgr(backend.DefaultStateName) + if err != nil { + t.Fatal(err) + } + + s2, err := b2.StateMgr(backend.DefaultStateName) + if err != nil { + t.Fatal(err) + } + + remote.TestRemoteLocks(t, s1.(*remote.State).Client, s2.(*remote.State).Client) +} + +func TestRemoteClientServicePrincipalLocks(t *testing.T) { + testAccAzureBackend(t) + rs := acctest.RandString(4) + res := testResourceNames(rs, "testState") + armClient := buildTestClient(t, res) + + ctx := context.TODO() + err := armClient.buildTestResources(ctx, &res) + if err != nil { + armClient.destroyTestResources(ctx, res) + t.Fatalf("Error creating Test Resources: %q", err) + } + defer armClient.destroyTestResources(ctx, res) + + b1 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ + "storage_account_name": res.storageAccountName, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "resource_group_name": res.resourceGroup, + "arm_subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"), + "arm_tenant_id": os.Getenv("ARM_TENANT_ID"), + "arm_client_id": os.Getenv("ARM_CLIENT_ID"), + "arm_client_secret": os.Getenv("ARM_CLIENT_SECRET"), + "environment": os.Getenv("ARM_ENVIRONMENT"), + })).(*Backend) + + b2 := backend.TestBackendConfig(t, New(), backend.TestWrapConfig(map[string]interface{}{ + "storage_account_name": res.storageAccountName, + "container_name": res.storageContainerName, + "key": res.storageKeyName, + "resource_group_name": res.resourceGroup, + "arm_subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"), + "arm_tenant_id": os.Getenv("ARM_TENANT_ID"), + "arm_client_id": os.Getenv("ARM_CLIENT_ID"), + "arm_client_secret": os.Getenv("ARM_CLIENT_SECRET"), + "environment": os.Getenv("ARM_ENVIRONMENT"), })).(*Backend) s1, err := b1.StateMgr(backend.DefaultStateName) @@ -71,22 +172,28 @@ func TestRemoteClientLocks(t *testing.T) { } func TestPutMaintainsMetaData(t *testing.T) { - testACC(t) + testAccAzureBackend(t) + rs := acctest.RandString(4) + res := testResourceNames(rs, "testState") + armClient := buildTestClient(t, res) + + ctx := context.TODO() + err := armClient.buildTestResources(ctx, &res) + if err != nil { + armClient.destroyTestResources(ctx, res) + t.Fatalf("Error creating Test Resources: %q", err) + } + defer armClient.destroyTestResources(ctx, res) - keyName := "testState" headerName := "acceptancetest" expectedValue := "f3b56bad-33ad-4b93-a600-7a66e9cbd1eb" - res := setupResources(t, keyName) - defer destroyResources(t, res.resourceGroupName) - config := getBackendConfig(t, res) - blobClient, err := getBlobClient(config) + client, err := armClient.getBlobClient(ctx) if err != nil { - t.Fatalf("Error getting Blob Client: %+v", err) + t.Fatalf("Error building Blob Client: %+v", err) } - - containerReference := blobClient.GetContainerReference(res.containerName) - blobReference := containerReference.GetBlobReference(keyName) + containerReference := client.GetContainerReference(res.storageContainerName) + blobReference := containerReference.GetBlobReference(res.storageKeyName) err = blobReference.CreateBlockBlob(&storage.PutBlobOptions{}) if err != nil { @@ -106,9 +213,10 @@ func TestPutMaintainsMetaData(t *testing.T) { // update the metadata using the Backend remoteClient := RemoteClient{ - keyName: res.keyName, - containerName: res.containerName, - blobClient: blobClient, + keyName: res.storageKeyName, + containerName: res.storageContainerName, + + blobClient: *client, } bytes := []byte(acctest.RandString(20)) @@ -127,17 +235,3 @@ func TestPutMaintainsMetaData(t *testing.T) { t.Fatalf("%q was not set to %q in the MetaData: %+v", headerName, expectedValue, blobReference.Metadata) } } - -func getBackendConfig(t *testing.T, res testResources) BackendConfig { - clients := getTestClient(t) - return BackendConfig{ - ClientID: clients.clientID, - ClientSecret: clients.clientSecret, - Environment: clients.environment.Name, - SubscriptionID: clients.subscriptionID, - TenantID: clients.tenantID, - - ResourceGroupName: res.resourceGroupName, - StorageAccountName: res.storageAccountName, - } -} diff --git a/backend/remote-state/azure/helpers_test.go b/backend/remote-state/azure/helpers_test.go new file mode 100644 index 000000000..9e2d8d343 --- /dev/null +++ b/backend/remote-state/azure/helpers_test.go @@ -0,0 +1,137 @@ +package azure + +import ( + "context" + "fmt" + "log" + "os" + "testing" + + "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources" + armStorage "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/storage/mgmt/storage" + "github.com/Azure/azure-sdk-for-go/storage" +) + +// verify that we are doing ACC tests or the Azure tests specifically +func testAccAzureBackend(t *testing.T) { + skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_AZURE_TEST") == "" + if skip { + t.Log("azure backend tests require setting TF_ACC or TF_AZURE_TEST") + t.Skip() + } +} + +func buildTestClient(t *testing.T, res resourceNames) *ArmClient { + subscriptionID := os.Getenv("ARM_SUBSCRIPTION_ID") + tenantID := os.Getenv("ARM_TENANT_ID") + clientID := os.Getenv("ARM_CLIENT_ID") + clientSecret := os.Getenv("ARM_CLIENT_SECRET") + environment := os.Getenv("ARM_ENVIRONMENT") + + // location isn't used in this method, but is in the other test methods + location := os.Getenv("ARM_LOCATION") + + if subscriptionID == "" || tenantID == "" || clientID == "" || clientSecret == "" || environment == "" || location == "" { + t.Fatal("Azure credentials missing or incomplete") + } + + armClient, err := buildArmClient(BackendConfig{ + SubscriptionID: subscriptionID, + TenantID: tenantID, + ClientID: clientID, + ClientSecret: clientSecret, + Environment: environment, + ResourceGroupName: res.resourceGroup, + StorageAccountName: res.storageAccountName, + }) + if err != nil { + t.Fatalf("Failed to build ArmClient: %+v", err) + } + + return armClient +} + +type resourceNames struct { + resourceGroup string + location string + storageAccountName string + storageContainerName string + storageKeyName string + storageAccountAccessKey string +} + +func testResourceNames(rString string, keyName string) resourceNames { + return resourceNames{ + resourceGroup: fmt.Sprintf("acctestrg-backend-%s", rString), + location: os.Getenv("ARM_LOCATION"), + storageAccountName: fmt.Sprintf("acctestsa%s", rString), + storageContainerName: "acctestcont", + storageKeyName: keyName, + } +} + +func (c *ArmClient) buildTestResources(ctx context.Context, names *resourceNames) error { + log.Printf("Creating Resource Group %q", names.resourceGroup) + _, err := c.groupsClient.CreateOrUpdate(ctx, names.resourceGroup, resources.Group{Location: &names.location}) + if err != nil { + return fmt.Errorf("failed to create test resource group: %s", err) + } + + log.Printf("Creating Storage Account %q in Resource Group %q", names.storageAccountName, names.resourceGroup) + future, err := c.storageAccountsClient.Create(ctx, names.resourceGroup, names.storageAccountName, armStorage.AccountCreateParameters{ + Sku: &armStorage.Sku{ + Name: armStorage.StandardLRS, + Tier: armStorage.Standard, + }, + Location: &names.location, + }) + if err != nil { + return fmt.Errorf("failed to create test storage account: %s", err) + } + + err = future.WaitForCompletionRef(ctx, c.storageAccountsClient.Client) + if err != nil { + return fmt.Errorf("failed waiting for the creation of storage account: %s", err) + } + + log.Printf("fetching access key for storage account") + resp, err := c.storageAccountsClient.ListKeys(ctx, names.resourceGroup, names.storageAccountName) + if err != nil { + return fmt.Errorf("failed to list storage account keys %s:", err) + } + + keys := *resp.Keys + accessKey := *keys[0].Value + names.storageAccountAccessKey = accessKey + + storageClient, err := storage.NewBasicClientOnSovereignCloud(names.storageAccountName, accessKey, c.environment) + if err != nil { + return fmt.Errorf("failed to list storage account keys %s:", err) + } + + log.Printf("Creating Container %q in Storage Account %q (Resource Group %q)", names.storageContainerName, names.storageAccountName, names.resourceGroup) + blobService := storageClient.GetBlobService() + container := blobService.GetContainerReference(names.storageContainerName) + err = container.Create(&storage.CreateContainerOptions{}) + if err != nil { + return fmt.Errorf("failed to create storage container: %s", err) + } + + return nil +} + +func (c ArmClient) destroyTestResources(ctx context.Context, resources resourceNames) error { + log.Printf("[DEBUG] Deleting Resource Group %q..", resources.resourceGroup) + future, err := c.groupsClient.Delete(ctx, resources.resourceGroup) + if err != nil { + return fmt.Errorf("Error deleting Resource Group: %+v", err) + } + + log.Printf("[DEBUG] Waiting for deletion of Resource Group %q..", resources.resourceGroup) + err = future.WaitForCompletionRef(ctx, c.groupsClient.Client) + if err != nil { + return fmt.Errorf("Error waiting for the deletion of Resource Group: %+v", err) + } + + return nil +} diff --git a/backend/remote-state/azure/sender.go b/backend/remote-state/azure/sender.go new file mode 100644 index 000000000..90a2fb5bd --- /dev/null +++ b/backend/remote-state/azure/sender.go @@ -0,0 +1,64 @@ +package azure + +import ( + "log" + "net/http" + "net/http/httputil" + + "github.com/Azure/go-autorest/autorest" + "github.com/hashicorp/terraform/helper/logging" +) + +func buildSender() autorest.Sender { + return autorest.DecorateSender(&http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + }, + }, withRequestLogging()) +} + +func withRequestLogging() autorest.SendDecorator { + return func(s autorest.Sender) autorest.Sender { + return autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { + // only log if logging's enabled + logLevel := logging.LogLevel() + if logLevel == "" { + return s.Do(r) + } + + // strip the authorization header prior to printing + authHeaderName := "Authorization" + auth := r.Header.Get(authHeaderName) + if auth != "" { + r.Header.Del(authHeaderName) + } + + // dump request to wire format + if dump, err := httputil.DumpRequestOut(r, true); err == nil { + log.Printf("[DEBUG] Azure Backend Request: \n%s\n", dump) + } else { + // fallback to basic message + log.Printf("[DEBUG] Azure Backend Request: %s to %s\n", r.Method, r.URL) + } + + // add the auth header back + if auth != "" { + r.Header.Add(authHeaderName, auth) + } + + resp, err := s.Do(r) + if resp != nil { + // dump response to wire format + if dump, err2 := httputil.DumpResponse(resp, true); err2 == nil { + log.Printf("[DEBUG] Azure Backend Response for %s: \n%s\n", r.URL, dump) + } else { + // fallback to basic message + log.Printf("[DEBUG] Azure Backend Response: %s for %s\n", resp.Status, r.URL) + } + } else { + log.Printf("[DEBUG] Request to %s completed with no response", r.URL) + } + return resp, err + }) + } +} diff --git a/go.mod b/go.mod index 6a471e152..b538a88e9 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,8 @@ module github.com/hashicorp/terraform require ( cloud.google.com/go v0.15.0 - github.com/Azure/azure-sdk-for-go v10.3.0-beta+incompatible - github.com/Azure/go-autorest v8.3.1+incompatible + github.com/Azure/azure-sdk-for-go v21.3.0+incompatible + github.com/Azure/go-autorest v10.15.4+incompatible github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006 // indirect github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290 // indirect github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 // indirect @@ -33,6 +33,7 @@ require ( github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect github.com/davecgh/go-spew v1.1.1 github.com/dgrijalva/jwt-go v0.0.0-20160617170158-f0777076321a // indirect + github.com/dimchansky/utfbom v1.0.0 // indirect github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31 // indirect github.com/dylanmei/iso8601 v0.1.0 // indirect github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08 @@ -54,6 +55,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.5.1 // indirect github.com/hashicorp/consul v0.0.0-20171026175957-610f3c86a089 github.com/hashicorp/errwrap v1.0.0 + github.com/hashicorp/go-azure-helpers v0.0.0-20181120094008-dd1e326c8888 github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de github.com/hashicorp/go-cleanhttp v0.5.0 github.com/hashicorp/go-getter v0.0.0-20180327010114-90bb99a48d86 @@ -86,6 +88,7 @@ require ( github.com/kardianos/osext v0.0.0-20160811001526-c2c54e542fb7 github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba // indirect github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82 + github.com/marstr/guid v1.1.0 // indirect github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c // indirect github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9 // indirect github.com/masterzen/winrm v0.0.0-20180224160350-7e40f93ae939 @@ -135,7 +138,7 @@ require ( go.uber.org/atomic v1.3.2 // indirect go.uber.org/multierr v1.1.0 // indirect go.uber.org/zap v1.9.1 // indirect - golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b + golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 golang.org/x/net v0.0.0-20181017193950-04a2e542c03f golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced golang.org/x/sys v0.0.0-20180925112736-b09afc3d579e // indirect diff --git a/go.sum b/go.sum index 43301678d..cb66a0493 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,11 @@ cloud.google.com/go v0.15.0 h1:/e2wXYguItvFu4fJCvhMRPIwwrimuUxI+aCVx/ahLjg= cloud.google.com/go v0.15.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/Azure/azure-sdk-for-go v10.3.0-beta+incompatible h1:TP+nmGmOP7psi7CvIq/1pCliRBRj73vmMTDjaPrTnr8= -github.com/Azure/azure-sdk-for-go v10.3.0-beta+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-autorest v8.3.1+incompatible h1:1+jMCOJcCh3GmI7FGJVOo8AlfPWDyjS7fLbbkZGzEGY= -github.com/Azure/go-autorest v8.3.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/azure-sdk-for-go v21.3.0+incompatible h1:YFvAka2WKAl2xnJkYV1e1b7E2z88AgFszDzWU18ejMY= +github.com/Azure/azure-sdk-for-go v21.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v22.2.2+incompatible h1:dnM65i68vx79S5ugocLMoJB6As2U1IXxa995LdjIQ28= +github.com/Azure/go-autorest v10.15.4+incompatible h1:q+DRrRdbCnkY7f2WxQBx58TwCGkEdMAK/hkZ10g0Pzk= +github.com/Azure/go-autorest v10.15.4+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006 h1:dVyNL14dq1500JomYVzJTVi0XEcZFCYwwiNpDeCfoes= github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290 h1:K9I21XUHNbYD3GNMmJBN0UKJCpdP+glftwNZ7Bo8kqY= @@ -69,6 +70,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v0.0.0-20160617170158-f0777076321a h1:pzKxqfSfp4kqrm6jfyVYYkWhf+e1hPRt3rX+Yj/3UBU= github.com/dgrijalva/jwt-go v0.0.0-20160617170158-f0777076321a/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.0.0 h1:fGC2kkf4qOoKqZ4q7iIh+Vef4ubC1c38UDsEyZynZPc= +github.com/dimchansky/utfbom v1.0.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31 h1:Dzuw9GtbmllUqEcoHfScT9YpKFUssSiZ5PgZkIGf/YQ= github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI= @@ -119,6 +122,8 @@ github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357 h1:Rem2+U35z1QtP github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-azure-helpers v0.0.0-20181120094008-dd1e326c8888 h1:QdenIfqH8llhlVDlGQWVUhg+L8pDT9VteOlMstWRl+w= +github.com/hashicorp/go-azure-helpers v0.0.0-20181120094008-dd1e326c8888/go.mod h1:e+GPy2nvD+spqsdjUyw5tbo73rBbu955QBaV9GZoBEA= github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de h1:XDCSythtg8aWSRSO29uwhgh7b127fWr+m5SemqjSUL8= github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de/go.mod h1:xIwEieBHERyEvaeKF/TcHh1Hu+lxPM+n2vT1+g9I4m4= github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= @@ -197,6 +202,8 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3v github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82 h1:wnfcqULT+N2seWf6y4yHzmi7GD2kNx4Ute0qArktD48= github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82/go.mod h1:y54tfGmO3NKssKveTEFFzH8C/akrSOy/iW9qEAUDV84= +github.com/marstr/guid v1.1.0 h1:/M4H/1G4avsieL6BbUwCOBzulmoeKVP5ux/3mQNnbyI= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c h1:FMUOnVGy8nWk1cvlMCAoftRItQGMxI0vzJ3dQjeZTCE= github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c/go.mod h1:mf8fjOu33zCqxUjuiU3I8S1lJMyEAlH+0F2+M5xl3hE= github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9 h1:SmVbOZFWAlyQshuMfOkiAx1f5oUTsOGG5IXplAEYeeM= @@ -325,6 +332,8 @@ golang.org/x/crypto v0.0.0-20180816225734-aabede6cba87/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b h1:2b9XGzhjiYsYPnKXoEfL7klWZQIt8IfyRCz62gCqqlQ= golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 h1:kkXA53yGe04D0adEYJwEVQjeBppL01Exg+fnMjfUraU= +golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332 h1:efGso+ep0DjyCBJPjvoz0HI6UldX4Md2F1rZFe1ir0E= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/vendor/github.com/Azure/azure-sdk-for-go/NOTICE b/vendor/github.com/Azure/azure-sdk-for-go/NOTICE new file mode 100644 index 000000000..2d1d72608 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/NOTICE @@ -0,0 +1,5 @@ +Microsoft Azure-SDK-for-Go +Copyright 2014-2017 Microsoft + +This product includes software developed at +the Microsoft Corporation (https://www.microsoft.com). diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/models.go b/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/models.go deleted file mode 100644 index dd0f06f5f..000000000 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/models.go +++ /dev/null @@ -1,457 +0,0 @@ -package resources - -// Copyright (c) Microsoft and contributors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. - -import ( - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/date" - "github.com/Azure/go-autorest/autorest/to" - "net/http" -) - -// DeploymentMode enumerates the values for deployment mode. -type DeploymentMode string - -const ( - // Complete specifies the complete state for deployment mode. - Complete DeploymentMode = "Complete" - // Incremental specifies the incremental state for deployment mode. - Incremental DeploymentMode = "Incremental" -) - -// ResourceIdentityType enumerates the values for resource identity type. -type ResourceIdentityType string - -const ( - // SystemAssigned specifies the system assigned state for resource identity - // type. - SystemAssigned ResourceIdentityType = "SystemAssigned" -) - -// AliasPathType is the type of the paths for alias. -type AliasPathType struct { - Path *string `json:"path,omitempty"` - APIVersions *[]string `json:"apiVersions,omitempty"` -} - -// AliasType is the alias type. -type AliasType struct { - Name *string `json:"name,omitempty"` - Paths *[]AliasPathType `json:"paths,omitempty"` -} - -// BasicDependency is deployment dependency information. -type BasicDependency struct { - ID *string `json:"id,omitempty"` - ResourceType *string `json:"resourceType,omitempty"` - ResourceName *string `json:"resourceName,omitempty"` -} - -// DebugSetting is -type DebugSetting struct { - DetailLevel *string `json:"detailLevel,omitempty"` -} - -// Dependency is deployment dependency information. -type Dependency struct { - DependsOn *[]BasicDependency `json:"dependsOn,omitempty"` - ID *string `json:"id,omitempty"` - ResourceType *string `json:"resourceType,omitempty"` - ResourceName *string `json:"resourceName,omitempty"` -} - -// Deployment is deployment operation parameters. -type Deployment struct { - Properties *DeploymentProperties `json:"properties,omitempty"` -} - -// DeploymentExportResult is the deployment export result. -type DeploymentExportResult struct { - autorest.Response `json:"-"` - Template *map[string]interface{} `json:"template,omitempty"` -} - -// DeploymentExtended is deployment information. -type DeploymentExtended struct { - autorest.Response `json:"-"` - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Properties *DeploymentPropertiesExtended `json:"properties,omitempty"` -} - -// DeploymentExtendedFilter is deployment filter. -type DeploymentExtendedFilter struct { - ProvisioningState *string `json:"provisioningState,omitempty"` -} - -// DeploymentListResult is list of deployments. -type DeploymentListResult struct { - autorest.Response `json:"-"` - Value *[]DeploymentExtended `json:"value,omitempty"` - NextLink *string `json:"nextLink,omitempty"` -} - -// DeploymentListResultPreparer prepares a request to retrieve the next set of results. It returns -// nil if no more results exist. -func (client DeploymentListResult) DeploymentListResultPreparer() (*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))) -} - -// DeploymentOperation is deployment operation information. -type DeploymentOperation struct { - autorest.Response `json:"-"` - ID *string `json:"id,omitempty"` - OperationID *string `json:"operationId,omitempty"` - Properties *DeploymentOperationProperties `json:"properties,omitempty"` -} - -// DeploymentOperationProperties is deployment operation properties. -type DeploymentOperationProperties struct { - ProvisioningState *string `json:"provisioningState,omitempty"` - Timestamp *date.Time `json:"timestamp,omitempty"` - ServiceRequestID *string `json:"serviceRequestId,omitempty"` - StatusCode *string `json:"statusCode,omitempty"` - StatusMessage *map[string]interface{} `json:"statusMessage,omitempty"` - TargetResource *TargetResource `json:"targetResource,omitempty"` - Request *HTTPMessage `json:"request,omitempty"` - Response *HTTPMessage `json:"response,omitempty"` -} - -// DeploymentOperationsListResult is list of deployment operations. -type DeploymentOperationsListResult struct { - autorest.Response `json:"-"` - Value *[]DeploymentOperation `json:"value,omitempty"` - NextLink *string `json:"nextLink,omitempty"` -} - -// DeploymentOperationsListResultPreparer prepares a request to retrieve the next set of results. It returns -// nil if no more results exist. -func (client DeploymentOperationsListResult) DeploymentOperationsListResultPreparer() (*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))) -} - -// DeploymentProperties is deployment properties. -type DeploymentProperties struct { - Template *map[string]interface{} `json:"template,omitempty"` - TemplateLink *TemplateLink `json:"templateLink,omitempty"` - Parameters *map[string]interface{} `json:"parameters,omitempty"` - ParametersLink *ParametersLink `json:"parametersLink,omitempty"` - Mode DeploymentMode `json:"mode,omitempty"` - DebugSetting *DebugSetting `json:"debugSetting,omitempty"` -} - -// DeploymentPropertiesExtended is deployment properties with additional -// details. -type DeploymentPropertiesExtended struct { - ProvisioningState *string `json:"provisioningState,omitempty"` - CorrelationID *string `json:"correlationId,omitempty"` - Timestamp *date.Time `json:"timestamp,omitempty"` - Outputs *map[string]interface{} `json:"outputs,omitempty"` - Providers *[]Provider `json:"providers,omitempty"` - Dependencies *[]Dependency `json:"dependencies,omitempty"` - Template *map[string]interface{} `json:"template,omitempty"` - TemplateLink *TemplateLink `json:"templateLink,omitempty"` - Parameters *map[string]interface{} `json:"parameters,omitempty"` - ParametersLink *ParametersLink `json:"parametersLink,omitempty"` - Mode DeploymentMode `json:"mode,omitempty"` - DebugSetting *DebugSetting `json:"debugSetting,omitempty"` -} - -// DeploymentValidateResult is information from validate template deployment -// response. -type DeploymentValidateResult struct { - autorest.Response `json:"-"` - Error *ManagementErrorWithDetails `json:"error,omitempty"` - Properties *DeploymentPropertiesExtended `json:"properties,omitempty"` -} - -// ExportTemplateRequest is export resource group template request parameters. -type ExportTemplateRequest struct { - ResourcesProperty *[]string `json:"resources,omitempty"` - Options *string `json:"options,omitempty"` -} - -// GenericResource is resource information. -type GenericResource 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"` - Plan *Plan `json:"plan,omitempty"` - Properties *map[string]interface{} `json:"properties,omitempty"` - Kind *string `json:"kind,omitempty"` - ManagedBy *string `json:"managedBy,omitempty"` - Sku *Sku `json:"sku,omitempty"` - Identity *Identity `json:"identity,omitempty"` -} - -// GenericResourceFilter is resource filter. -type GenericResourceFilter struct { - ResourceType *string `json:"resourceType,omitempty"` - Tagname *string `json:"tagname,omitempty"` - Tagvalue *string `json:"tagvalue,omitempty"` -} - -// Group is resource group information. -type Group struct { - autorest.Response `json:"-"` - ID *string `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Properties *GroupProperties `json:"properties,omitempty"` - Location *string `json:"location,omitempty"` - ManagedBy *string `json:"managedBy,omitempty"` - Tags *map[string]*string `json:"tags,omitempty"` -} - -// GroupExportResult is -type GroupExportResult struct { - autorest.Response `json:"-"` - Template *map[string]interface{} `json:"template,omitempty"` - Error *ManagementErrorWithDetails `json:"error,omitempty"` -} - -// GroupFilter is resource group filter. -type GroupFilter struct { - TagName *string `json:"tagName,omitempty"` - TagValue *string `json:"tagValue,omitempty"` -} - -// GroupListResult is list of resource groups. -type GroupListResult struct { - autorest.Response `json:"-"` - Value *[]Group `json:"value,omitempty"` - NextLink *string `json:"nextLink,omitempty"` -} - -// GroupListResultPreparer prepares a request to retrieve the next set of results. It returns -// nil if no more results exist. -func (client GroupListResult) GroupListResultPreparer() (*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))) -} - -// GroupProperties is the resource group properties. -type GroupProperties struct { - ProvisioningState *string `json:"provisioningState,omitempty"` -} - -// HTTPMessage is -type HTTPMessage struct { - Content *map[string]interface{} `json:"content,omitempty"` -} - -// Identity is identity for the resource. -type Identity struct { - PrincipalID *string `json:"principalId,omitempty"` - TenantID *string `json:"tenantId,omitempty"` - Type ResourceIdentityType `json:"type,omitempty"` -} - -// ListResult is list of resource groups. -type ListResult struct { - autorest.Response `json:"-"` - Value *[]GenericResource `json:"value,omitempty"` - NextLink *string `json:"nextLink,omitempty"` -} - -// ListResultPreparer prepares a request to retrieve the next set of results. It returns -// nil if no more results exist. -func (client ListResult) ListResultPreparer() (*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))) -} - -// ManagementErrorWithDetails is -type ManagementErrorWithDetails struct { - Code *string `json:"code,omitempty"` - Message *string `json:"message,omitempty"` - Target *string `json:"target,omitempty"` - Details *[]ManagementErrorWithDetails `json:"details,omitempty"` -} - -// MoveInfo is parameters of move resources. -type MoveInfo struct { - ResourcesProperty *[]string `json:"resources,omitempty"` - TargetResourceGroup *string `json:"targetResourceGroup,omitempty"` -} - -// ParametersLink is entity representing the reference to the deployment -// paramaters. -type ParametersLink struct { - URI *string `json:"uri,omitempty"` - ContentVersion *string `json:"contentVersion,omitempty"` -} - -// Plan is plan for the resource. -type Plan struct { - Name *string `json:"name,omitempty"` - Publisher *string `json:"publisher,omitempty"` - Product *string `json:"product,omitempty"` - PromotionCode *string `json:"promotionCode,omitempty"` -} - -// Provider is resource provider information. -type Provider struct { - autorest.Response `json:"-"` - ID *string `json:"id,omitempty"` - Namespace *string `json:"namespace,omitempty"` - RegistrationState *string `json:"registrationState,omitempty"` - ResourceTypes *[]ProviderResourceType `json:"resourceTypes,omitempty"` -} - -// ProviderListResult is list of resource providers. -type ProviderListResult struct { - autorest.Response `json:"-"` - Value *[]Provider `json:"value,omitempty"` - NextLink *string `json:"nextLink,omitempty"` -} - -// ProviderListResultPreparer prepares a request to retrieve the next set of results. It returns -// nil if no more results exist. -func (client ProviderListResult) ProviderListResultPreparer() (*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))) -} - -// ProviderOperationDisplayProperties is resource provider operation's display -// properties. -type ProviderOperationDisplayProperties struct { - Publisher *string `json:"publisher,omitempty"` - Provider *string `json:"provider,omitempty"` - Resource *string `json:"resource,omitempty"` - Operation *string `json:"operation,omitempty"` - Description *string `json:"description,omitempty"` -} - -// ProviderResourceType is resource type managed by the resource provider. -type ProviderResourceType struct { - ResourceType *string `json:"resourceType,omitempty"` - Locations *[]string `json:"locations,omitempty"` - Aliases *[]AliasType `json:"aliases,omitempty"` - APIVersions *[]string `json:"apiVersions,omitempty"` - Properties *map[string]*string `json:"properties,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"` -} - -// Sku is sKU for the resource. -type Sku struct { - Name *string `json:"name,omitempty"` - Tier *string `json:"tier,omitempty"` - Size *string `json:"size,omitempty"` - Family *string `json:"family,omitempty"` - Model *string `json:"model,omitempty"` - Capacity *int32 `json:"capacity,omitempty"` -} - -// SubResource is -type SubResource struct { - ID *string `json:"id,omitempty"` -} - -// TagCount is tag count. -type TagCount struct { - Type *string `json:"type,omitempty"` - Value *int32 `json:"value,omitempty"` -} - -// TagDetails is tag details. -type TagDetails struct { - autorest.Response `json:"-"` - ID *string `json:"id,omitempty"` - TagName *string `json:"tagName,omitempty"` - Count *TagCount `json:"count,omitempty"` - Values *[]TagValue `json:"values,omitempty"` -} - -// TagsListResult is list of subscription tags. -type TagsListResult struct { - autorest.Response `json:"-"` - Value *[]TagDetails `json:"value,omitempty"` - NextLink *string `json:"nextLink,omitempty"` -} - -// TagsListResultPreparer prepares a request to retrieve the next set of results. It returns -// nil if no more results exist. -func (client TagsListResult) TagsListResultPreparer() (*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))) -} - -// TagValue is tag information. -type TagValue struct { - autorest.Response `json:"-"` - ID *string `json:"id,omitempty"` - TagValue *string `json:"tagValue,omitempty"` - Count *TagCount `json:"count,omitempty"` -} - -// TargetResource is target resource. -type TargetResource struct { - ID *string `json:"id,omitempty"` - ResourceName *string `json:"resourceName,omitempty"` - ResourceType *string `json:"resourceType,omitempty"` -} - -// TemplateLink is entity representing the reference to the template. -type TemplateLink struct { - URI *string `json:"uri,omitempty"` - ContentVersion *string `json:"contentVersion,omitempty"` -} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/resourcesgroup.go b/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/resourcesgroup.go deleted file mode 100644 index a7179dda8..000000000 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/resourcesgroup.go +++ /dev/null @@ -1,898 +0,0 @@ -package resources - -// Copyright (c) Microsoft and contributors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. - -import ( - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/validation" - "net/http" -) - -// GroupClient is the provides operations for working with resources and -// resource groups. -type GroupClient struct { - ManagementClient -} - -// NewGroupClient creates an instance of the GroupClient client. -func NewGroupClient(subscriptionID string) GroupClient { - return NewGroupClientWithBaseURI(DefaultBaseURI, subscriptionID) -} - -// NewGroupClientWithBaseURI creates an instance of the GroupClient client. -func NewGroupClientWithBaseURI(baseURI string, subscriptionID string) GroupClient { - return GroupClient{NewWithBaseURI(baseURI, subscriptionID)} -} - -// CheckExistence checks whether a resource exists. -// -// resourceGroupName is the name of the resource group containing the resource -// to check. The name is case insensitive. resourceProviderNamespace is the -// resource provider of the resource to check. parentResourcePath is the parent -// resource identity. resourceType is the resource type. resourceName is the -// name of the resource to check whether it exists. -func (client GroupClient) CheckExistence(resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (result autorest.Response, err error) { - if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.GroupClient", "CheckExistence") - } - - req, err := client.CheckExistencePreparer(resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CheckExistence", nil, "Failure preparing request") - return - } - - resp, err := client.CheckExistenceSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CheckExistence", resp, "Failure sending request") - return - } - - result, err = client.CheckExistenceResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CheckExistence", resp, "Failure responding to request") - } - - return -} - -// CheckExistencePreparer prepares the CheckExistence request. -func (client GroupClient) CheckExistencePreparer(resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "parentResourcePath": parentResourcePath, - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceName": autorest.Encode("path", resourceName), - "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), - "resourceType": resourceType, - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsHead(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) -} - -// CheckExistenceSender sends the CheckExistence request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) CheckExistenceSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) -} - -// CheckExistenceResponder handles the response to the CheckExistence request. The method always -// closes the http.Response Body. -func (client GroupClient) CheckExistenceResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent, http.StatusNotFound), - autorest.ByClosing()) - result.Response = resp - return -} - -// CheckExistenceByID checks by ID whether a resource exists. -// -// resourceID is the fully qualified ID of the resource, including the resource -// name and resource type. Use the format, -// /subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name} -func (client GroupClient) CheckExistenceByID(resourceID string) (result autorest.Response, err error) { - req, err := client.CheckExistenceByIDPreparer(resourceID) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CheckExistenceByID", nil, "Failure preparing request") - return - } - - resp, err := client.CheckExistenceByIDSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CheckExistenceByID", resp, "Failure sending request") - return - } - - result, err = client.CheckExistenceByIDResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CheckExistenceByID", resp, "Failure responding to request") - } - - return -} - -// CheckExistenceByIDPreparer prepares the CheckExistenceByID request. -func (client GroupClient) CheckExistenceByIDPreparer(resourceID string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceId": resourceID, - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsHead(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/{resourceId}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) -} - -// CheckExistenceByIDSender sends the CheckExistenceByID request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) CheckExistenceByIDSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) -} - -// CheckExistenceByIDResponder handles the response to the CheckExistenceByID request. The method always -// closes the http.Response Body. -func (client GroupClient) CheckExistenceByIDResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent, http.StatusNotFound), - autorest.ByClosing()) - result.Response = resp - return -} - -// CreateOrUpdate creates a resource. This method may poll for completion. -// Polling can be canceled by passing the cancel channel argument. The channel -// will be used to cancel polling and any outstanding HTTP requests. -// -// resourceGroupName is the name of the resource group for the resource. The -// name is case insensitive. resourceProviderNamespace is the namespace of the -// resource provider. parentResourcePath is the parent resource identity. -// resourceType is the resource type of the resource to create. resourceName is -// the name of the resource to create. parameters is parameters for creating or -// updating the resource. -func (client GroupClient) CreateOrUpdate(resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string, parameters GenericResource, cancel <-chan struct{}) (<-chan GenericResource, <-chan error) { - resultChan := make(chan GenericResource, 1) - errChan := make(chan error, 1) - if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: parameters, - Constraints: []validation.Constraint{{Target: "parameters.Kind", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{{Target: "parameters.Kind", Name: validation.Pattern, Rule: `^[-\w\._,\(\)]+$`, Chain: nil}}}}}}); err != nil { - errChan <- validation.NewErrorWithValidationError(err, "resources.GroupClient", "CreateOrUpdate") - close(errChan) - close(resultChan) - return resultChan, errChan - } - - go func() { - var err error - var result GenericResource - defer func() { - resultChan <- result - errChan <- err - close(resultChan) - close(errChan) - }() - req, err := client.CreateOrUpdatePreparer(resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName, parameters, cancel) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CreateOrUpdate", nil, "Failure preparing request") - return - } - - resp, err := client.CreateOrUpdateSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CreateOrUpdate", resp, "Failure sending request") - return - } - - result, err = client.CreateOrUpdateResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CreateOrUpdate", resp, "Failure responding to request") - } - }() - return resultChan, errChan -} - -// CreateOrUpdatePreparer prepares the CreateOrUpdate request. -func (client GroupClient) CreateOrUpdatePreparer(resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string, parameters GenericResource, cancel <-chan struct{}) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "parentResourcePath": parentResourcePath, - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceName": autorest.Encode("path", resourceName), - "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), - "resourceType": resourceType, - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsJSON(), - autorest.AsPut(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{Cancel: cancel}) -} - -// CreateOrUpdateSender sends the CreateOrUpdate request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) CreateOrUpdateSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, - req, - azure.DoPollForAsynchronous(client.PollingDelay)) -} - -// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always -// closes the http.Response Body. -func (client GroupClient) CreateOrUpdateResponder(resp *http.Response) (result GenericResource, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusCreated, http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// CreateOrUpdateByID create a resource by ID. 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. -// -// resourceID is the fully qualified ID of the resource, including the resource -// name and resource type. Use the format, -// /subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name} -// parameters is create or update resource parameters. -func (client GroupClient) CreateOrUpdateByID(resourceID string, parameters GenericResource, cancel <-chan struct{}) (<-chan GenericResource, <-chan error) { - resultChan := make(chan GenericResource, 1) - errChan := make(chan error, 1) - if err := validation.Validate([]validation.Validation{ - {TargetValue: parameters, - Constraints: []validation.Constraint{{Target: "parameters.Kind", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{{Target: "parameters.Kind", Name: validation.Pattern, Rule: `^[-\w\._,\(\)]+$`, Chain: nil}}}}}}); err != nil { - errChan <- validation.NewErrorWithValidationError(err, "resources.GroupClient", "CreateOrUpdateByID") - close(errChan) - close(resultChan) - return resultChan, errChan - } - - go func() { - var err error - var result GenericResource - defer func() { - resultChan <- result - errChan <- err - close(resultChan) - close(errChan) - }() - req, err := client.CreateOrUpdateByIDPreparer(resourceID, parameters, cancel) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CreateOrUpdateByID", nil, "Failure preparing request") - return - } - - resp, err := client.CreateOrUpdateByIDSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CreateOrUpdateByID", resp, "Failure sending request") - return - } - - result, err = client.CreateOrUpdateByIDResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "CreateOrUpdateByID", resp, "Failure responding to request") - } - }() - return resultChan, errChan -} - -// CreateOrUpdateByIDPreparer prepares the CreateOrUpdateByID request. -func (client GroupClient) CreateOrUpdateByIDPreparer(resourceID string, parameters GenericResource, cancel <-chan struct{}) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceId": resourceID, - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsJSON(), - autorest.AsPut(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/{resourceId}", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{Cancel: cancel}) -} - -// CreateOrUpdateByIDSender sends the CreateOrUpdateByID request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) CreateOrUpdateByIDSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, - req, - azure.DoPollForAsynchronous(client.PollingDelay)) -} - -// CreateOrUpdateByIDResponder handles the response to the CreateOrUpdateByID request. The method always -// closes the http.Response Body. -func (client GroupClient) CreateOrUpdateByIDResponder(resp *http.Response) (result GenericResource, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusCreated, http.StatusOK, http.StatusAccepted), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// Delete deletes a resource. This method may poll for completion. Polling can -// be canceled by passing the cancel channel argument. The channel will be used -// to cancel polling and any outstanding HTTP requests. -// -// resourceGroupName is the name of the resource group that contains the -// resource to delete. The name is case insensitive. resourceProviderNamespace -// is the namespace of the resource provider. parentResourcePath is the parent -// resource identity. resourceType is the resource type. resourceName is the -// name of the resource to delete. -func (client GroupClient) Delete(resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string, cancel <-chan struct{}) (<-chan autorest.Response, <-chan error) { - resultChan := make(chan autorest.Response, 1) - errChan := make(chan error, 1) - if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - errChan <- validation.NewErrorWithValidationError(err, "resources.GroupClient", "Delete") - close(errChan) - close(resultChan) - return resultChan, errChan - } - - go func() { - var err error - var result autorest.Response - defer func() { - resultChan <- result - errChan <- err - close(resultChan) - close(errChan) - }() - req, err := client.DeletePreparer(resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName, cancel) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "Delete", nil, "Failure preparing request") - return - } - - resp, err := client.DeleteSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "resources.GroupClient", "Delete", resp, "Failure sending request") - return - } - - result, err = client.DeleteResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "Delete", resp, "Failure responding to request") - } - }() - return resultChan, errChan -} - -// DeletePreparer prepares the Delete request. -func (client GroupClient) DeletePreparer(resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string, cancel <-chan struct{}) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "parentResourcePath": parentResourcePath, - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceName": autorest.Encode("path", resourceName), - "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), - "resourceType": resourceType, - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsDelete(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{Cancel: cancel}) -} - -// DeleteSender sends the Delete request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) DeleteSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, - req, - azure.DoPollForAsynchronous(client.PollingDelay)) -} - -// DeleteResponder handles the response to the Delete request. The method always -// closes the http.Response Body. -func (client GroupClient) DeleteResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent, http.StatusAccepted), - autorest.ByClosing()) - result.Response = resp - return -} - -// DeleteByID deletes a resource by ID. 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. -// -// resourceID is the fully qualified ID of the resource, including the resource -// name and resource type. Use the format, -// /subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name} -func (client GroupClient) DeleteByID(resourceID string, cancel <-chan struct{}) (<-chan autorest.Response, <-chan error) { - resultChan := make(chan autorest.Response, 1) - errChan := make(chan error, 1) - go func() { - var err error - var result autorest.Response - defer func() { - resultChan <- result - errChan <- err - close(resultChan) - close(errChan) - }() - req, err := client.DeleteByIDPreparer(resourceID, cancel) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "DeleteByID", nil, "Failure preparing request") - return - } - - resp, err := client.DeleteByIDSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "resources.GroupClient", "DeleteByID", resp, "Failure sending request") - return - } - - result, err = client.DeleteByIDResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "DeleteByID", resp, "Failure responding to request") - } - }() - return resultChan, errChan -} - -// DeleteByIDPreparer prepares the DeleteByID request. -func (client GroupClient) DeleteByIDPreparer(resourceID string, cancel <-chan struct{}) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceId": resourceID, - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsDelete(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/{resourceId}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{Cancel: cancel}) -} - -// DeleteByIDSender sends the DeleteByID request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) DeleteByIDSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, - req, - azure.DoPollForAsynchronous(client.PollingDelay)) -} - -// DeleteByIDResponder handles the response to the DeleteByID request. The method always -// closes the http.Response Body. -func (client GroupClient) DeleteByIDResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent, http.StatusAccepted), - autorest.ByClosing()) - result.Response = resp - return -} - -// Get gets a resource. -// -// resourceGroupName is the name of the resource group containing the resource -// to get. The name is case insensitive. resourceProviderNamespace is the -// namespace of the resource provider. parentResourcePath is the parent -// resource identity. resourceType is the resource type of the resource. -// resourceName is the name of the resource to get. -func (client GroupClient) Get(resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (result GenericResource, err error) { - if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.GroupClient", "Get") - } - - req, err := client.GetPreparer(resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "Get", nil, "Failure preparing request") - return - } - - resp, err := client.GetSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "resources.GroupClient", "Get", resp, "Failure sending request") - return - } - - result, err = client.GetResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "Get", resp, "Failure responding to request") - } - - return -} - -// GetPreparer prepares the Get request. -func (client GroupClient) GetPreparer(resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "parentResourcePath": parentResourcePath, - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "resourceName": autorest.Encode("path", resourceName), - "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), - "resourceType": resourceType, - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) -} - -// GetSender sends the Get request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) GetSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) -} - -// GetResponder handles the response to the Get request. The method always -// closes the http.Response Body. -func (client GroupClient) GetResponder(resp *http.Response) (result GenericResource, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// GetByID gets a resource by ID. -// -// resourceID is the fully qualified ID of the resource, including the resource -// name and resource type. Use the format, -// /subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name} -func (client GroupClient) GetByID(resourceID string) (result GenericResource, err error) { - req, err := client.GetByIDPreparer(resourceID) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "GetByID", nil, "Failure preparing request") - return - } - - resp, err := client.GetByIDSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "resources.GroupClient", "GetByID", resp, "Failure sending request") - return - } - - result, err = client.GetByIDResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "GetByID", resp, "Failure responding to request") - } - - return -} - -// GetByIDPreparer prepares the GetByID request. -func (client GroupClient) GetByIDPreparer(resourceID string) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "resourceId": resourceID, - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/{resourceId}", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) -} - -// GetByIDSender sends the GetByID request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) GetByIDSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) -} - -// GetByIDResponder handles the response to the GetByID request. The method always -// closes the http.Response Body. -func (client GroupClient) GetByIDResponder(resp *http.Response) (result GenericResource, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// List get all the resources in a subscription. -// -// filter is the filter to apply on the operation. expand is the $expand query -// parameter. top is the number of results to return. If null is passed, -// returns all resource groups. -func (client GroupClient) List(filter string, expand string, top *int32) (result ListResult, err error) { - req, err := client.ListPreparer(filter, expand, top) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "List", nil, "Failure preparing request") - return - } - - resp, err := client.ListSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "resources.GroupClient", "List", resp, "Failure sending request") - return - } - - result, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "List", resp, "Failure responding to request") - } - - return -} - -// ListPreparer prepares the List request. -func (client GroupClient) ListPreparer(filter string, expand string, top *int32) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - if len(filter) > 0 { - queryParameters["$filter"] = autorest.Encode("query", filter) - } - if len(expand) > 0 { - queryParameters["$expand"] = autorest.Encode("query", expand) - } - if top != nil { - queryParameters["$top"] = autorest.Encode("query", *top) - } - - preparer := autorest.CreatePreparer( - autorest.AsGet(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resources", pathParameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) -} - -// ListSender sends the List request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) ListSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) -} - -// ListResponder handles the response to the List request. The method always -// closes the http.Response Body. -func (client GroupClient) ListResponder(resp *http.Response) (result ListResult, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// ListNextResults retrieves the next set of results, if any. -func (client GroupClient) ListNextResults(lastResults ListResult) (result ListResult, err error) { - req, err := lastResults.ListResultPreparer() - if err != nil { - return result, autorest.NewErrorWithError(err, "resources.GroupClient", "List", 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, "resources.GroupClient", "List", resp, "Failure sending next results request") - } - - result, err = client.ListResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "List", resp, "Failure responding to next results request") - } - - return -} - -// MoveResources the resources to move must be in the same source resource -// group. The target resource group may be in a different subscription. When -// moving resources, both the source group and the target group are locked for -// the duration of the operation. Write and delete operations are blocked on -// the groups until the move completes. 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. -// -// sourceResourceGroupName is the name of the resource group containing the -// rsources to move. parameters is parameters for moving resources. -func (client GroupClient) MoveResources(sourceResourceGroupName string, parameters MoveInfo, cancel <-chan struct{}) (<-chan autorest.Response, <-chan error) { - resultChan := make(chan autorest.Response, 1) - errChan := make(chan error, 1) - if err := validation.Validate([]validation.Validation{ - {TargetValue: sourceResourceGroupName, - Constraints: []validation.Constraint{{Target: "sourceResourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "sourceResourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "sourceResourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - errChan <- validation.NewErrorWithValidationError(err, "resources.GroupClient", "MoveResources") - close(errChan) - close(resultChan) - return resultChan, errChan - } - - go func() { - var err error - var result autorest.Response - defer func() { - resultChan <- result - errChan <- err - close(resultChan) - close(errChan) - }() - req, err := client.MoveResourcesPreparer(sourceResourceGroupName, parameters, cancel) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "MoveResources", nil, "Failure preparing request") - return - } - - resp, err := client.MoveResourcesSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "resources.GroupClient", "MoveResources", resp, "Failure sending request") - return - } - - result, err = client.MoveResourcesResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupClient", "MoveResources", resp, "Failure responding to request") - } - }() - return resultChan, errChan -} - -// MoveResourcesPreparer prepares the MoveResources request. -func (client GroupClient) MoveResourcesPreparer(sourceResourceGroupName string, parameters MoveInfo, cancel <-chan struct{}) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "sourceResourceGroupName": autorest.Encode("path", sourceResourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2016-09-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsJSON(), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{sourceResourceGroupName}/moveResources", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{Cancel: cancel}) -} - -// MoveResourcesSender sends the MoveResources request. The method will close the -// http.Response Body if it receives an error. -func (client GroupClient) MoveResourcesSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, - req, - azure.DoPollForAsynchronous(client.PollingDelay)) -} - -// MoveResourcesResponder handles the response to the MoveResources request. The method always -// closes the http.Response Body. -func (client GroupClient) MoveResourcesResponder(resp *http.Response) (result autorest.Response, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent), - autorest.ByClosing()) - result.Response = resp - return -} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/models.go b/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/models.go deleted file mode 100644 index 2e2030184..000000000 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/models.go +++ /dev/null @@ -1,452 +0,0 @@ -package storage - -// Copyright (c) Microsoft and contributors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. - -import ( - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/date" -) - -// AccessTier enumerates the values for access tier. -type AccessTier string - -const ( - // Cool specifies the cool state for access tier. - Cool AccessTier = "Cool" - // Hot specifies the hot state for access tier. - Hot AccessTier = "Hot" -) - -// AccountStatus enumerates the values for account status. -type AccountStatus string - -const ( - // Available specifies the available state for account status. - Available AccountStatus = "available" - // Unavailable specifies the unavailable state for account status. - Unavailable AccountStatus = "unavailable" -) - -// HTTPProtocol enumerates the values for http protocol. -type HTTPProtocol string - -const ( - // HTTPS specifies the https state for http protocol. - HTTPS HTTPProtocol = "https" - // Httpshttp specifies the httpshttp state for http protocol. - Httpshttp HTTPProtocol = "https,http" -) - -// KeyPermission enumerates the values for key permission. -type KeyPermission string - -const ( - // Full specifies the full state for key permission. - Full KeyPermission = "Full" - // Read specifies the read state for key permission. - Read KeyPermission = "Read" -) - -// Kind enumerates the values for kind. -type Kind string - -const ( - // BlobStorage specifies the blob storage state for kind. - BlobStorage Kind = "BlobStorage" - // Storage specifies the storage state for kind. - Storage Kind = "Storage" -) - -// Permissions enumerates the values for permissions. -type Permissions string - -const ( - // A specifies the a state for permissions. - A Permissions = "a" - // C specifies the c state for permissions. - C Permissions = "c" - // D specifies the d state for permissions. - D Permissions = "d" - // L specifies the l state for permissions. - L Permissions = "l" - // P specifies the p state for permissions. - P Permissions = "p" - // R specifies the r state for permissions. - R Permissions = "r" - // U specifies the u state for permissions. - U Permissions = "u" - // W specifies the w state for permissions. - W Permissions = "w" -) - -// Permissions1 enumerates the values for permissions 1. -type Permissions1 string - -const ( - // Permissions1A specifies the permissions 1a state for permissions 1. - Permissions1A Permissions1 = "a" - // Permissions1C specifies the permissions 1c state for permissions 1. - Permissions1C Permissions1 = "c" - // Permissions1D specifies the permissions 1d state for permissions 1. - Permissions1D Permissions1 = "d" - // Permissions1L specifies the permissions 1l state for permissions 1. - Permissions1L Permissions1 = "l" - // Permissions1P specifies the permissions 1p state for permissions 1. - Permissions1P Permissions1 = "p" - // Permissions1R specifies the permissions 1r state for permissions 1. - Permissions1R Permissions1 = "r" - // Permissions1U specifies the permissions 1u state for permissions 1. - Permissions1U Permissions1 = "u" - // Permissions1W specifies the permissions 1w state for permissions 1. - Permissions1W Permissions1 = "w" -) - -// ProvisioningState enumerates the values for provisioning state. -type ProvisioningState string - -const ( - // Creating specifies the creating state for provisioning state. - Creating ProvisioningState = "Creating" - // ResolvingDNS specifies the resolving dns state for provisioning state. - ResolvingDNS ProvisioningState = "ResolvingDNS" - // Succeeded specifies the succeeded state for provisioning state. - Succeeded ProvisioningState = "Succeeded" -) - -// Reason enumerates the values for reason. -type Reason string - -const ( - // AccountNameInvalid specifies the account name invalid state for reason. - AccountNameInvalid Reason = "AccountNameInvalid" - // AlreadyExists specifies the already exists state for reason. - AlreadyExists Reason = "AlreadyExists" -) - -// ResourceEnum enumerates the values for resource enum. -type ResourceEnum string - -const ( - // ResourceEnumB specifies the resource enum b state for resource enum. - ResourceEnumB ResourceEnum = "b" - // ResourceEnumC specifies the resource enum c state for resource enum. - ResourceEnumC ResourceEnum = "c" - // ResourceEnumF specifies the resource enum f state for resource enum. - ResourceEnumF ResourceEnum = "f" - // ResourceEnumS specifies the resource enum s state for resource enum. - ResourceEnumS ResourceEnum = "s" -) - -// ResourceTypes enumerates the values for resource types. -type ResourceTypes string - -const ( - // ResourceTypesC specifies the resource types c state for resource types. - ResourceTypesC ResourceTypes = "c" - // ResourceTypesO specifies the resource types o state for resource types. - ResourceTypesO ResourceTypes = "o" - // ResourceTypesS specifies the resource types s state for resource types. - ResourceTypesS ResourceTypes = "s" -) - -// Services enumerates the values for services. -type Services string - -const ( - // B specifies the b state for services. - B Services = "b" - // F specifies the f state for services. - F Services = "f" - // Q specifies the q state for services. - Q Services = "q" - // T specifies the t state for services. - T Services = "t" -) - -// SkuName enumerates the values for sku name. -type SkuName string - -const ( - // PremiumLRS specifies the premium lrs state for sku name. - PremiumLRS SkuName = "Premium_LRS" - // StandardGRS specifies the standard grs state for sku name. - StandardGRS SkuName = "Standard_GRS" - // StandardLRS specifies the standard lrs state for sku name. - StandardLRS SkuName = "Standard_LRS" - // StandardRAGRS specifies the standard ragrs state for sku name. - StandardRAGRS SkuName = "Standard_RAGRS" - // StandardZRS specifies the standard zrs state for sku name. - StandardZRS SkuName = "Standard_ZRS" -) - -// SkuTier enumerates the values for sku tier. -type SkuTier string - -const ( - // Premium specifies the premium state for sku tier. - Premium SkuTier = "Premium" - // Standard specifies the standard state for sku tier. - Standard SkuTier = "Standard" -) - -// UsageUnit enumerates the values for usage unit. -type UsageUnit string - -const ( - // Bytes specifies the bytes state for usage unit. - Bytes UsageUnit = "Bytes" - // BytesPerSecond specifies the bytes per second state for usage unit. - BytesPerSecond UsageUnit = "BytesPerSecond" - // Count specifies the count state for usage unit. - Count UsageUnit = "Count" - // CountsPerSecond specifies the counts per second state for usage unit. - CountsPerSecond UsageUnit = "CountsPerSecond" - // Percent specifies the percent state for usage unit. - Percent UsageUnit = "Percent" - // Seconds specifies the seconds state for usage unit. - Seconds UsageUnit = "Seconds" -) - -// Account is the storage account. -type Account 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"` - Sku *Sku `json:"sku,omitempty"` - Kind Kind `json:"kind,omitempty"` - *AccountProperties `json:"properties,omitempty"` -} - -// AccountCheckNameAvailabilityParameters is the parameters used to check the -// availabity of the storage account name. -type AccountCheckNameAvailabilityParameters struct { - Name *string `json:"name,omitempty"` - Type *string `json:"type,omitempty"` -} - -// AccountCreateParameters is the parameters used when creating a storage -// account. -type AccountCreateParameters struct { - Sku *Sku `json:"sku,omitempty"` - Kind Kind `json:"kind,omitempty"` - Location *string `json:"location,omitempty"` - Tags *map[string]*string `json:"tags,omitempty"` - *AccountPropertiesCreateParameters `json:"properties,omitempty"` -} - -// AccountKey is an access key for the storage account. -type AccountKey struct { - KeyName *string `json:"keyName,omitempty"` - Value *string `json:"value,omitempty"` - Permissions KeyPermission `json:"permissions,omitempty"` -} - -// AccountListKeysResult is the response from the ListKeys operation. -type AccountListKeysResult struct { - autorest.Response `json:"-"` - Keys *[]AccountKey `json:"keys,omitempty"` -} - -// AccountListResult is the response from the List Storage Accounts operation. -type AccountListResult struct { - autorest.Response `json:"-"` - Value *[]Account `json:"value,omitempty"` -} - -// AccountProperties is properties of the storage account. -type AccountProperties struct { - ProvisioningState ProvisioningState `json:"provisioningState,omitempty"` - PrimaryEndpoints *Endpoints `json:"primaryEndpoints,omitempty"` - PrimaryLocation *string `json:"primaryLocation,omitempty"` - StatusOfPrimary AccountStatus `json:"statusOfPrimary,omitempty"` - LastGeoFailoverTime *date.Time `json:"lastGeoFailoverTime,omitempty"` - SecondaryLocation *string `json:"secondaryLocation,omitempty"` - StatusOfSecondary AccountStatus `json:"statusOfSecondary,omitempty"` - CreationTime *date.Time `json:"creationTime,omitempty"` - CustomDomain *CustomDomain `json:"customDomain,omitempty"` - SecondaryEndpoints *Endpoints `json:"secondaryEndpoints,omitempty"` - Encryption *Encryption `json:"encryption,omitempty"` - AccessTier AccessTier `json:"accessTier,omitempty"` - EnableHTTPSTrafficOnly *bool `json:"supportsHttpsTrafficOnly,omitempty"` -} - -// AccountPropertiesCreateParameters is the parameters used to create the -// storage account. -type AccountPropertiesCreateParameters struct { - CustomDomain *CustomDomain `json:"customDomain,omitempty"` - Encryption *Encryption `json:"encryption,omitempty"` - AccessTier AccessTier `json:"accessTier,omitempty"` - EnableHTTPSTrafficOnly *bool `json:"supportsHttpsTrafficOnly,omitempty"` -} - -// AccountPropertiesUpdateParameters is the parameters used when updating a -// storage account. -type AccountPropertiesUpdateParameters struct { - CustomDomain *CustomDomain `json:"customDomain,omitempty"` - Encryption *Encryption `json:"encryption,omitempty"` - AccessTier AccessTier `json:"accessTier,omitempty"` - EnableHTTPSTrafficOnly *bool `json:"supportsHttpsTrafficOnly,omitempty"` -} - -// AccountRegenerateKeyParameters is the parameters used to regenerate the -// storage account key. -type AccountRegenerateKeyParameters struct { - KeyName *string `json:"keyName,omitempty"` -} - -// AccountSasParameters is the parameters to list SAS credentials of a storage -// account. -type AccountSasParameters struct { - Services Services `json:"signedServices,omitempty"` - ResourceTypes ResourceTypes `json:"signedResourceTypes,omitempty"` - Permissions Permissions `json:"signedPermission,omitempty"` - IPAddressOrRange *string `json:"signedIp,omitempty"` - Protocols HTTPProtocol `json:"signedProtocol,omitempty"` - SharedAccessStartTime *date.Time `json:"signedStart,omitempty"` - SharedAccessExpiryTime *date.Time `json:"signedExpiry,omitempty"` - KeyToSign *string `json:"keyToSign,omitempty"` -} - -// AccountUpdateParameters is the parameters that can be provided when updating -// the storage account properties. -type AccountUpdateParameters struct { - Sku *Sku `json:"sku,omitempty"` - Tags *map[string]*string `json:"tags,omitempty"` - *AccountPropertiesUpdateParameters `json:"properties,omitempty"` -} - -// CheckNameAvailabilityResult is the CheckNameAvailability operation response. -type CheckNameAvailabilityResult struct { - autorest.Response `json:"-"` - NameAvailable *bool `json:"nameAvailable,omitempty"` - Reason Reason `json:"reason,omitempty"` - Message *string `json:"message,omitempty"` -} - -// CustomDomain is the custom domain assigned to this storage account. This can -// be set via Update. -type CustomDomain struct { - Name *string `json:"name,omitempty"` - UseSubDomain *bool `json:"useSubDomain,omitempty"` -} - -// Encryption is the encryption settings on the storage account. -type Encryption struct { - Services *EncryptionServices `json:"services,omitempty"` - KeySource *string `json:"keySource,omitempty"` -} - -// EncryptionService is a service that allows server-side encryption to be -// used. -type EncryptionService struct { - Enabled *bool `json:"enabled,omitempty"` - LastEnabledTime *date.Time `json:"lastEnabledTime,omitempty"` -} - -// EncryptionServices is a list of services that support encryption. -type EncryptionServices struct { - Blob *EncryptionService `json:"blob,omitempty"` - File *EncryptionService `json:"file,omitempty"` - Table *EncryptionService `json:"table,omitempty"` - Queue *EncryptionService `json:"queue,omitempty"` -} - -// Endpoints is the URIs that are used to perform a retrieval of a public blob, -// queue, or table object. -type Endpoints struct { - Blob *string `json:"blob,omitempty"` - Queue *string `json:"queue,omitempty"` - Table *string `json:"table,omitempty"` - File *string `json:"file,omitempty"` -} - -// ListAccountSasResponse is the List SAS credentials operation response. -type ListAccountSasResponse struct { - autorest.Response `json:"-"` - AccountSasToken *string `json:"accountSasToken,omitempty"` -} - -// ListServiceSasResponse is the List service SAS credentials operation -// response. -type ListServiceSasResponse struct { - autorest.Response `json:"-"` - ServiceSasToken *string `json:"serviceSasToken,omitempty"` -} - -// Resource is describes a storage resource. -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"` -} - -// ServiceSasParameters is the parameters to list service SAS credentials of a -// speicific resource. -type ServiceSasParameters struct { - CanonicalizedResource *string `json:"canonicalizedResource,omitempty"` - Resource Resource `json:"signedResource,omitempty"` - Permissions Permissions `json:"signedPermission,omitempty"` - IPAddressOrRange *string `json:"signedIp,omitempty"` - Protocols HTTPProtocol `json:"signedProtocol,omitempty"` - SharedAccessStartTime *date.Time `json:"signedStart,omitempty"` - SharedAccessExpiryTime *date.Time `json:"signedExpiry,omitempty"` - Identifier *string `json:"signedIdentifier,omitempty"` - PartitionKeyStart *string `json:"startPk,omitempty"` - PartitionKeyEnd *string `json:"endPk,omitempty"` - RowKeyStart *string `json:"startRk,omitempty"` - RowKeyEnd *string `json:"endRk,omitempty"` - KeyToSign *string `json:"keyToSign,omitempty"` - CacheControl *string `json:"rscc,omitempty"` - ContentDisposition *string `json:"rscd,omitempty"` - ContentEncoding *string `json:"rsce,omitempty"` - ContentLanguage *string `json:"rscl,omitempty"` - ContentType *string `json:"rsct,omitempty"` -} - -// Sku is the SKU of the storage account. -type Sku struct { - Name SkuName `json:"name,omitempty"` - Tier SkuTier `json:"tier,omitempty"` -} - -// Usage is describes Storage Resource Usage. -type Usage struct { - Unit UsageUnit `json:"unit,omitempty"` - CurrentValue *int32 `json:"currentValue,omitempty"` - Limit *int32 `json:"limit,omitempty"` - Name *UsageName `json:"name,omitempty"` -} - -// UsageListResult is the response from the List Usages operation. -type UsageListResult struct { - autorest.Response `json:"-"` - Value *[]Usage `json:"value,omitempty"` -} - -// UsageName is the usage names that can be used; currently limited to -// StorageAccount. -type UsageName struct { - Value *string `json:"value,omitempty"` - LocalizedValue *string `json:"localizedValue,omitempty"` -} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources/models.go b/vendor/github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources/models.go new file mode 100644 index 000000000..c1e080fbd --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources/models.go @@ -0,0 +1,163 @@ +// +build go1.9 + +// Copyright 2018 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 code was auto-generated by: +// github.com/Azure/azure-sdk-for-go/tools/profileBuilder + +package resources + +import original "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources" + +const ( + DefaultBaseURI = original.DefaultBaseURI +) + +type BaseClient = original.BaseClient +type DeploymentOperationsClient = original.DeploymentOperationsClient +type DeploymentsClient = original.DeploymentsClient +type GroupsClient = original.GroupsClient +type DeploymentMode = original.DeploymentMode + +const ( + Complete DeploymentMode = original.Complete + Incremental DeploymentMode = original.Incremental +) + +type ResourceIdentityType = original.ResourceIdentityType + +const ( + SystemAssigned ResourceIdentityType = original.SystemAssigned +) + +type AliasPathType = original.AliasPathType +type AliasType = original.AliasType +type BasicDependency = original.BasicDependency +type DebugSetting = original.DebugSetting +type Dependency = original.Dependency +type Deployment = original.Deployment +type DeploymentExportResult = original.DeploymentExportResult +type DeploymentExtended = original.DeploymentExtended +type DeploymentExtendedFilter = original.DeploymentExtendedFilter +type DeploymentListResult = original.DeploymentListResult +type DeploymentListResultIterator = original.DeploymentListResultIterator +type DeploymentListResultPage = original.DeploymentListResultPage +type DeploymentOperation = original.DeploymentOperation +type DeploymentOperationProperties = original.DeploymentOperationProperties +type DeploymentOperationsListResult = original.DeploymentOperationsListResult +type DeploymentOperationsListResultIterator = original.DeploymentOperationsListResultIterator +type DeploymentOperationsListResultPage = original.DeploymentOperationsListResultPage +type DeploymentProperties = original.DeploymentProperties +type DeploymentPropertiesExtended = original.DeploymentPropertiesExtended +type DeploymentsCreateOrUpdateFuture = original.DeploymentsCreateOrUpdateFuture +type DeploymentsDeleteFuture = original.DeploymentsDeleteFuture +type DeploymentValidateResult = original.DeploymentValidateResult +type ExportTemplateRequest = original.ExportTemplateRequest +type GenericResource = original.GenericResource +type GenericResourceFilter = original.GenericResourceFilter +type Group = original.Group +type GroupExportResult = original.GroupExportResult +type GroupFilter = original.GroupFilter +type GroupListResult = original.GroupListResult +type GroupListResultIterator = original.GroupListResultIterator +type GroupListResultPage = original.GroupListResultPage +type GroupProperties = original.GroupProperties +type GroupsDeleteFuture = original.GroupsDeleteFuture +type HTTPMessage = original.HTTPMessage +type Identity = original.Identity +type ListResult = original.ListResult +type ListResultIterator = original.ListResultIterator +type ListResultPage = original.ListResultPage +type ManagementErrorWithDetails = original.ManagementErrorWithDetails +type MoveInfo = original.MoveInfo +type MoveResourcesFuture = original.MoveResourcesFuture +type ParametersLink = original.ParametersLink +type Plan = original.Plan +type Provider = original.Provider +type ProviderListResult = original.ProviderListResult +type ProviderListResultIterator = original.ProviderListResultIterator +type ProviderListResultPage = original.ProviderListResultPage +type ProviderOperationDisplayProperties = original.ProviderOperationDisplayProperties +type ProviderResourceType = original.ProviderResourceType +type Resource = original.Resource +type Sku = original.Sku +type SubResource = original.SubResource +type TagCount = original.TagCount +type TagDetails = original.TagDetails +type TagsListResult = original.TagsListResult +type TagsListResultIterator = original.TagsListResultIterator +type TagsListResultPage = original.TagsListResultPage +type TagValue = original.TagValue +type TargetResource = original.TargetResource +type TemplateLink = original.TemplateLink +type UpdateFuture = original.UpdateFuture +type ProvidersClient = original.ProvidersClient +type Client = original.Client +type TagsClient = original.TagsClient + +func New(subscriptionID string) BaseClient { + return original.New(subscriptionID) +} +func NewWithBaseURI(baseURI string, subscriptionID string) BaseClient { + return original.NewWithBaseURI(baseURI, subscriptionID) +} +func NewDeploymentOperationsClient(subscriptionID string) DeploymentOperationsClient { + return original.NewDeploymentOperationsClient(subscriptionID) +} +func NewDeploymentOperationsClientWithBaseURI(baseURI string, subscriptionID string) DeploymentOperationsClient { + return original.NewDeploymentOperationsClientWithBaseURI(baseURI, subscriptionID) +} +func NewDeploymentsClient(subscriptionID string) DeploymentsClient { + return original.NewDeploymentsClient(subscriptionID) +} +func NewDeploymentsClientWithBaseURI(baseURI string, subscriptionID string) DeploymentsClient { + return original.NewDeploymentsClientWithBaseURI(baseURI, subscriptionID) +} +func NewGroupsClient(subscriptionID string) GroupsClient { + return original.NewGroupsClient(subscriptionID) +} +func NewGroupsClientWithBaseURI(baseURI string, subscriptionID string) GroupsClient { + return original.NewGroupsClientWithBaseURI(baseURI, subscriptionID) +} +func PossibleDeploymentModeValues() []DeploymentMode { + return original.PossibleDeploymentModeValues() +} +func PossibleResourceIdentityTypeValues() []ResourceIdentityType { + return original.PossibleResourceIdentityTypeValues() +} +func NewProvidersClient(subscriptionID string) ProvidersClient { + return original.NewProvidersClient(subscriptionID) +} +func NewProvidersClientWithBaseURI(baseURI string, subscriptionID string) ProvidersClient { + return original.NewProvidersClientWithBaseURI(baseURI, subscriptionID) +} +func NewClient(subscriptionID string) Client { + return original.NewClient(subscriptionID) +} +func NewClientWithBaseURI(baseURI string, subscriptionID string) Client { + return original.NewClientWithBaseURI(baseURI, subscriptionID) +} +func NewTagsClient(subscriptionID string) TagsClient { + return original.NewTagsClient(subscriptionID) +} +func NewTagsClientWithBaseURI(baseURI string, subscriptionID string) TagsClient { + return original.NewTagsClientWithBaseURI(baseURI, subscriptionID) +} +func UserAgent() string { + return original.UserAgent() + " profiles/2017-03-09" +} +func Version() string { + return original.Version() +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/storage/mgmt/storage/models.go b/vendor/github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/storage/mgmt/storage/models.go new file mode 100644 index 000000000..d638c2a81 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/storage/mgmt/storage/models.go @@ -0,0 +1,177 @@ +// +build go1.9 + +// Copyright 2018 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 code was auto-generated by: +// github.com/Azure/azure-sdk-for-go/tools/profileBuilder + +package storage + +import original "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage" + +type AccountsClient = original.AccountsClient + +const ( + DefaultBaseURI = original.DefaultBaseURI +) + +type BaseClient = original.BaseClient +type AccessTier = original.AccessTier + +const ( + Cool AccessTier = original.Cool + Hot AccessTier = original.Hot +) + +type AccountStatus = original.AccountStatus + +const ( + Available AccountStatus = original.Available + Unavailable AccountStatus = original.Unavailable +) + +type KeyPermission = original.KeyPermission + +const ( + FULL KeyPermission = original.FULL + READ KeyPermission = original.READ +) + +type Kind = original.Kind + +const ( + BlobStorage Kind = original.BlobStorage + Storage Kind = original.Storage +) + +type ProvisioningState = original.ProvisioningState + +const ( + Creating ProvisioningState = original.Creating + ResolvingDNS ProvisioningState = original.ResolvingDNS + Succeeded ProvisioningState = original.Succeeded +) + +type Reason = original.Reason + +const ( + AccountNameInvalid Reason = original.AccountNameInvalid + AlreadyExists Reason = original.AlreadyExists +) + +type SkuName = original.SkuName + +const ( + PremiumLRS SkuName = original.PremiumLRS + StandardGRS SkuName = original.StandardGRS + StandardLRS SkuName = original.StandardLRS + StandardRAGRS SkuName = original.StandardRAGRS + StandardZRS SkuName = original.StandardZRS +) + +type SkuTier = original.SkuTier + +const ( + Premium SkuTier = original.Premium + Standard SkuTier = original.Standard +) + +type UsageUnit = original.UsageUnit + +const ( + Bytes UsageUnit = original.Bytes + BytesPerSecond UsageUnit = original.BytesPerSecond + Count UsageUnit = original.Count + CountsPerSecond UsageUnit = original.CountsPerSecond + Percent UsageUnit = original.Percent + Seconds UsageUnit = original.Seconds +) + +type Account = original.Account +type AccountCheckNameAvailabilityParameters = original.AccountCheckNameAvailabilityParameters +type AccountCreateParameters = original.AccountCreateParameters +type AccountKey = original.AccountKey +type AccountListKeysResult = original.AccountListKeysResult +type AccountListResult = original.AccountListResult +type AccountProperties = original.AccountProperties +type AccountPropertiesCreateParameters = original.AccountPropertiesCreateParameters +type AccountPropertiesUpdateParameters = original.AccountPropertiesUpdateParameters +type AccountRegenerateKeyParameters = original.AccountRegenerateKeyParameters +type AccountsCreateFuture = original.AccountsCreateFuture +type AccountUpdateParameters = original.AccountUpdateParameters +type CheckNameAvailabilityResult = original.CheckNameAvailabilityResult +type CustomDomain = original.CustomDomain +type Encryption = original.Encryption +type EncryptionService = original.EncryptionService +type EncryptionServices = original.EncryptionServices +type Endpoints = original.Endpoints +type Resource = original.Resource +type Sku = original.Sku +type Usage = original.Usage +type UsageListResult = original.UsageListResult +type UsageName = original.UsageName +type UsageClient = original.UsageClient + +func NewAccountsClient(subscriptionID string) AccountsClient { + return original.NewAccountsClient(subscriptionID) +} +func NewAccountsClientWithBaseURI(baseURI string, subscriptionID string) AccountsClient { + return original.NewAccountsClientWithBaseURI(baseURI, subscriptionID) +} +func New(subscriptionID string) BaseClient { + return original.New(subscriptionID) +} +func NewWithBaseURI(baseURI string, subscriptionID string) BaseClient { + return original.NewWithBaseURI(baseURI, subscriptionID) +} +func PossibleAccessTierValues() []AccessTier { + return original.PossibleAccessTierValues() +} +func PossibleAccountStatusValues() []AccountStatus { + return original.PossibleAccountStatusValues() +} +func PossibleKeyPermissionValues() []KeyPermission { + return original.PossibleKeyPermissionValues() +} +func PossibleKindValues() []Kind { + return original.PossibleKindValues() +} +func PossibleProvisioningStateValues() []ProvisioningState { + return original.PossibleProvisioningStateValues() +} +func PossibleReasonValues() []Reason { + return original.PossibleReasonValues() +} +func PossibleSkuNameValues() []SkuName { + return original.PossibleSkuNameValues() +} +func PossibleSkuTierValues() []SkuTier { + return original.PossibleSkuTierValues() +} +func PossibleUsageUnitValues() []UsageUnit { + return original.PossibleUsageUnitValues() +} +func NewUsageClient(subscriptionID string) UsageClient { + return original.NewUsageClient(subscriptionID) +} +func NewUsageClientWithBaseURI(baseURI string, subscriptionID string) UsageClient { + return original.NewUsageClientWithBaseURI(baseURI, subscriptionID) +} +func UserAgent() string { + return original.UserAgent() + " profiles/2017-03-09" +} +func Version() string { + return original.Version() +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/client.go b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/client.go similarity index 68% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/client.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/client.go index 3e13c72f9..a25b93f11 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/client.go @@ -1,7 +1,6 @@ -// Package resources implements the Azure ARM Resources service API version -// 2016-09-01. +// Package resources implements the Azure ARM Resources service API version 2016-02-01. +// // -// Provides operations for working with resources and resource groups. package resources // Copyright (c) Microsoft and contributors. All rights reserved. @@ -18,9 +17,8 @@ package resources // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. import ( "github.com/Azure/go-autorest/autorest" @@ -31,21 +29,21 @@ const ( DefaultBaseURI = "https://management.azure.com" ) -// ManagementClient is the base client for Resources. -type ManagementClient struct { +// BaseClient is the base client for Resources. +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, diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/deploymentoperations.go b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/deploymentoperations.go similarity index 66% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/deploymentoperations.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/deploymentoperations.go index 34d12aac6..215e1ffba 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/deploymentoperations.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/deploymentoperations.go @@ -14,54 +14,47 @@ package resources // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. import ( + "context" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/validation" "net/http" ) -// DeploymentOperationsClient is the provides operations for working with -// resources and resource groups. +// DeploymentOperationsClient is the client for the DeploymentOperations methods of the Resources service. type DeploymentOperationsClient struct { - ManagementClient + BaseClient } -// NewDeploymentOperationsClient creates an instance of the -// DeploymentOperationsClient client. +// NewDeploymentOperationsClient creates an instance of the DeploymentOperationsClient client. func NewDeploymentOperationsClient(subscriptionID string) DeploymentOperationsClient { return NewDeploymentOperationsClientWithBaseURI(DefaultBaseURI, subscriptionID) } -// NewDeploymentOperationsClientWithBaseURI creates an instance of the -// DeploymentOperationsClient client. +// NewDeploymentOperationsClientWithBaseURI creates an instance of the DeploymentOperationsClient client. func NewDeploymentOperationsClientWithBaseURI(baseURI string, subscriptionID string) DeploymentOperationsClient { return DeploymentOperationsClient{NewWithBaseURI(baseURI, subscriptionID)} } -// Get gets a deployments operation. -// -// resourceGroupName is the name of the resource group. The name is case -// insensitive. deploymentName is the name of the deployment. operationID is -// the ID of the operation to get. -func (client DeploymentOperationsClient) Get(resourceGroupName string, deploymentName string, operationID string) (result DeploymentOperation, err error) { +// Get get a list of deployments operations. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// deploymentName - the name of the deployment. +// operationID - operation Id. +func (client DeploymentOperationsClient) Get(ctx context.Context, resourceGroupName string, deploymentName string, operationID string) (result DeploymentOperation, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: deploymentName, - Constraints: []validation.Constraint{{Target: "deploymentName", Name: validation.MaxLength, Rule: 64, Chain: nil}, - {Target: "deploymentName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "deploymentName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.DeploymentOperationsClient", "Get") + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.DeploymentOperationsClient", "Get", err.Error()) } - req, err := client.GetPreparer(resourceGroupName, deploymentName, operationID) + req, err := client.GetPreparer(ctx, resourceGroupName, deploymentName, operationID) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentOperationsClient", "Get", nil, "Failure preparing request") return @@ -83,7 +76,7 @@ func (client DeploymentOperationsClient) Get(resourceGroupName string, deploymen } // GetPreparer prepares the Get request. -func (client DeploymentOperationsClient) GetPreparer(resourceGroupName string, deploymentName string, operationID string) (*http.Request, error) { +func (client DeploymentOperationsClient) GetPreparer(ctx context.Context, resourceGroupName string, deploymentName string, operationID string) (*http.Request, error) { pathParameters := map[string]interface{}{ "deploymentName": autorest.Encode("path", deploymentName), "operationId": autorest.Encode("path", operationID), @@ -91,7 +84,7 @@ func (client DeploymentOperationsClient) GetPreparer(resourceGroupName string, d "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -101,13 +94,14 @@ func (client DeploymentOperationsClient) GetPreparer(resourceGroupName string, d autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/deployments/{deploymentName}/operations/{operationId}", 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 DeploymentOperationsClient) 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 @@ -123,25 +117,22 @@ func (client DeploymentOperationsClient) GetResponder(resp *http.Response) (resu return } -// List gets all deployments operations for a deployment. -// -// resourceGroupName is the name of the resource group. The name is case -// insensitive. deploymentName is the name of the deployment with the operation -// to get. top is the number of results to return. -func (client DeploymentOperationsClient) List(resourceGroupName string, deploymentName string, top *int32) (result DeploymentOperationsListResult, err error) { +// List gets a list of deployments operations. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// deploymentName - the name of the deployment. +// top - query parameters. +func (client DeploymentOperationsClient) List(ctx context.Context, resourceGroupName string, deploymentName string, top *int32) (result DeploymentOperationsListResultPage, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: deploymentName, - Constraints: []validation.Constraint{{Target: "deploymentName", Name: validation.MaxLength, Rule: 64, Chain: nil}, - {Target: "deploymentName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "deploymentName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.DeploymentOperationsClient", "List") + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.DeploymentOperationsClient", "List", err.Error()) } - req, err := client.ListPreparer(resourceGroupName, deploymentName, top) + result.fn = client.listNextResults + req, err := client.ListPreparer(ctx, resourceGroupName, deploymentName, top) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentOperationsClient", "List", nil, "Failure preparing request") return @@ -149,12 +140,12 @@ func (client DeploymentOperationsClient) List(resourceGroupName string, deployme resp, err := client.ListSender(req) if err != nil { - result.Response = autorest.Response{Response: resp} + result.dolr.Response = autorest.Response{Response: resp} err = autorest.NewErrorWithError(err, "resources.DeploymentOperationsClient", "List", resp, "Failure sending request") return } - result, err = client.ListResponder(resp) + result.dolr, err = client.ListResponder(resp) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentOperationsClient", "List", resp, "Failure responding to request") } @@ -163,14 +154,14 @@ func (client DeploymentOperationsClient) List(resourceGroupName string, deployme } // ListPreparer prepares the List request. -func (client DeploymentOperationsClient) ListPreparer(resourceGroupName string, deploymentName string, top *int32) (*http.Request, error) { +func (client DeploymentOperationsClient) ListPreparer(ctx context.Context, resourceGroupName string, deploymentName string, top *int32) (*http.Request, error) { pathParameters := map[string]interface{}{ "deploymentName": autorest.Encode("path", deploymentName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -183,13 +174,14 @@ func (client DeploymentOperationsClient) ListPreparer(resourceGroupName string, autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/deployments/{deploymentName}/operations", 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 DeploymentOperationsClient) 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 @@ -205,26 +197,29 @@ func (client DeploymentOperationsClient) ListResponder(resp *http.Response) (res return } -// ListNextResults retrieves the next set of results, if any. -func (client DeploymentOperationsClient) ListNextResults(lastResults DeploymentOperationsListResult) (result DeploymentOperationsListResult, err error) { - req, err := lastResults.DeploymentOperationsListResultPreparer() +// listNextResults retrieves the next set of results, if any. +func (client DeploymentOperationsClient) listNextResults(lastResults DeploymentOperationsListResult) (result DeploymentOperationsListResult, err error) { + req, err := lastResults.deploymentOperationsListResultPreparer() if err != nil { - return result, autorest.NewErrorWithError(err, "resources.DeploymentOperationsClient", "List", nil, "Failure preparing next results request") + return result, autorest.NewErrorWithError(err, "resources.DeploymentOperationsClient", "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, "resources.DeploymentOperationsClient", "List", resp, "Failure sending next results request") + return result, autorest.NewErrorWithError(err, "resources.DeploymentOperationsClient", "listNextResults", resp, "Failure sending next results request") } - result, err = client.ListResponder(resp) if err != nil { - err = autorest.NewErrorWithError(err, "resources.DeploymentOperationsClient", "List", resp, "Failure responding to next results request") + err = autorest.NewErrorWithError(err, "resources.DeploymentOperationsClient", "listNextResults", resp, "Failure responding to next results request") } - + return +} + +// ListComplete enumerates all values, automatically crossing page boundaries as required. +func (client DeploymentOperationsClient) ListComplete(ctx context.Context, resourceGroupName string, deploymentName string, top *int32) (result DeploymentOperationsListResultIterator, err error) { + result.page, err = client.List(ctx, resourceGroupName, deploymentName, top) return } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/deployments.go b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/deployments.go similarity index 60% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/deployments.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/deployments.go index 7c3e19288..db4c7ca6a 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/deployments.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/deployments.go @@ -14,21 +14,20 @@ package resources // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. import ( + "context" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/validation" "net/http" ) -// DeploymentsClient is the provides operations for working with resources and -// resource groups. +// DeploymentsClient is the client for the Deployments methods of the Resources service. type DeploymentsClient struct { - ManagementClient + BaseClient } // NewDeploymentsClient creates an instance of the DeploymentsClient client. @@ -36,33 +35,25 @@ func NewDeploymentsClient(subscriptionID string) DeploymentsClient { return NewDeploymentsClientWithBaseURI(DefaultBaseURI, subscriptionID) } -// NewDeploymentsClientWithBaseURI creates an instance of the DeploymentsClient -// client. +// NewDeploymentsClientWithBaseURI creates an instance of the DeploymentsClient client. func NewDeploymentsClientWithBaseURI(baseURI string, subscriptionID string) DeploymentsClient { return DeploymentsClient{NewWithBaseURI(baseURI, subscriptionID)} } -// Cancel you can cancel a deployment only if the provisioningState is Accepted -// or Running. After the deployment is canceled, the provisioningState is set -// to Canceled. Canceling a template deployment stops the currently running -// template deployment and leaves the resource group partially deployed. -// -// resourceGroupName is the name of the resource group. The name is case -// insensitive. deploymentName is the name of the deployment to cancel. -func (client DeploymentsClient) Cancel(resourceGroupName string, deploymentName string) (result autorest.Response, err error) { +// Cancel cancel a currently running template deployment. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// deploymentName - the name of the deployment. +func (client DeploymentsClient) Cancel(ctx context.Context, resourceGroupName string, deploymentName string) (result autorest.Response, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: deploymentName, - Constraints: []validation.Constraint{{Target: "deploymentName", Name: validation.MaxLength, Rule: 64, Chain: nil}, - {Target: "deploymentName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "deploymentName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.DeploymentsClient", "Cancel") + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.DeploymentsClient", "Cancel", err.Error()) } - req, err := client.CancelPreparer(resourceGroupName, deploymentName) + req, err := client.CancelPreparer(ctx, resourceGroupName, deploymentName) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "Cancel", nil, "Failure preparing request") return @@ -84,14 +75,14 @@ func (client DeploymentsClient) Cancel(resourceGroupName string, deploymentName } // CancelPreparer prepares the Cancel request. -func (client DeploymentsClient) CancelPreparer(resourceGroupName string, deploymentName string) (*http.Request, error) { +func (client DeploymentsClient) CancelPreparer(ctx context.Context, resourceGroupName string, deploymentName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "deploymentName": autorest.Encode("path", deploymentName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -101,13 +92,14 @@ func (client DeploymentsClient) CancelPreparer(resourceGroupName string, deploym autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}/cancel", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // CancelSender sends the Cancel request. The method will close the // http.Response Body if it receives an error. func (client DeploymentsClient) CancelSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // CancelResponder handles the response to the Cancel request. The method always @@ -122,25 +114,20 @@ func (client DeploymentsClient) CancelResponder(resp *http.Response) (result aut return } -// CheckExistence checks whether the deployment exists. -// -// resourceGroupName is the name of the resource group with the deployment to -// check. The name is case insensitive. deploymentName is the name of the -// deployment to check. -func (client DeploymentsClient) CheckExistence(resourceGroupName string, deploymentName string) (result autorest.Response, err error) { +// CheckExistence checks whether deployment exists. +// Parameters: +// resourceGroupName - the name of the resource group to check. The name is case insensitive. +// deploymentName - the name of the deployment. +func (client DeploymentsClient) CheckExistence(ctx context.Context, resourceGroupName string, deploymentName string) (result autorest.Response, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: deploymentName, - Constraints: []validation.Constraint{{Target: "deploymentName", Name: validation.MaxLength, Rule: 64, Chain: nil}, - {Target: "deploymentName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "deploymentName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.DeploymentsClient", "CheckExistence") + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.DeploymentsClient", "CheckExistence", err.Error()) } - req, err := client.CheckExistencePreparer(resourceGroupName, deploymentName) + req, err := client.CheckExistencePreparer(ctx, resourceGroupName, deploymentName) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "CheckExistence", nil, "Failure preparing request") return @@ -162,14 +149,14 @@ func (client DeploymentsClient) CheckExistence(resourceGroupName string, deploym } // CheckExistencePreparer prepares the CheckExistence request. -func (client DeploymentsClient) CheckExistencePreparer(resourceGroupName string, deploymentName string) (*http.Request, error) { +func (client DeploymentsClient) CheckExistencePreparer(ctx context.Context, resourceGroupName string, deploymentName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "deploymentName": autorest.Encode("path", deploymentName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -179,13 +166,14 @@ func (client DeploymentsClient) CheckExistencePreparer(resourceGroupName string, autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // CheckExistenceSender sends the CheckExistence request. The method will close the // http.Response Body if it receives an error. func (client DeploymentsClient) CheckExistenceSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // CheckExistenceResponder handles the response to the CheckExistence request. The method always @@ -200,99 +188,76 @@ func (client DeploymentsClient) CheckExistenceResponder(resp *http.Response) (re return } -// CreateOrUpdate you can provide the template and parameters directly in the -// request or link to JSON files. This method may poll for completion. Polling -// can be canceled by passing the cancel channel argument. The channel will be -// used to cancel polling and any outstanding HTTP requests. -// -// resourceGroupName is the name of the resource group to deploy the resources -// to. The name is case insensitive. The resource group must already exist. -// deploymentName is the name of the deployment. parameters is additional -// parameters supplied to the operation. -func (client DeploymentsClient) CreateOrUpdate(resourceGroupName string, deploymentName string, parameters Deployment, cancel <-chan struct{}) (<-chan DeploymentExtended, <-chan error) { - resultChan := make(chan DeploymentExtended, 1) - errChan := make(chan error, 1) +// CreateOrUpdate create a named template deployment using a template. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// deploymentName - the name of the deployment. +// parameters - additional parameters supplied to the operation. +func (client DeploymentsClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, deploymentName string, parameters Deployment) (result DeploymentsCreateOrUpdateFuture, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: deploymentName, - Constraints: []validation.Constraint{{Target: "deploymentName", Name: validation.MaxLength, Rule: 64, Chain: nil}, - {Target: "deploymentName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "deploymentName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, {TargetValue: parameters, - Constraints: []validation.Constraint{{Target: "parameters.Properties", Name: validation.Null, Rule: true, + Constraints: []validation.Constraint{{Target: "parameters.Properties", Name: validation.Null, Rule: false, Chain: []validation.Constraint{{Target: "parameters.Properties.TemplateLink", Name: validation.Null, Rule: false, Chain: []validation.Constraint{{Target: "parameters.Properties.TemplateLink.URI", Name: validation.Null, Rule: true, Chain: nil}}}, {Target: "parameters.Properties.ParametersLink", Name: validation.Null, Rule: false, Chain: []validation.Constraint{{Target: "parameters.Properties.ParametersLink.URI", Name: validation.Null, Rule: true, Chain: nil}}}, }}}}}); err != nil { - errChan <- validation.NewErrorWithValidationError(err, "resources.DeploymentsClient", "CreateOrUpdate") - close(errChan) - close(resultChan) - return resultChan, errChan + return result, validation.NewError("resources.DeploymentsClient", "CreateOrUpdate", err.Error()) } - go func() { - var err error - var result DeploymentExtended - defer func() { - resultChan <- result - errChan <- err - close(resultChan) - close(errChan) - }() - req, err := client.CreateOrUpdatePreparer(resourceGroupName, deploymentName, parameters, cancel) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "CreateOrUpdate", nil, "Failure preparing request") - return - } + req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, deploymentName, parameters) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "CreateOrUpdate", nil, "Failure preparing request") + return + } - resp, err := client.CreateOrUpdateSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "CreateOrUpdate", resp, "Failure sending request") - return - } + result, err = client.CreateOrUpdateSender(req) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "CreateOrUpdate", result.Response(), "Failure sending request") + return + } - result, err = client.CreateOrUpdateResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "CreateOrUpdate", resp, "Failure responding to request") - } - }() - return resultChan, errChan + return } // CreateOrUpdatePreparer prepares the CreateOrUpdate request. -func (client DeploymentsClient) CreateOrUpdatePreparer(resourceGroupName string, deploymentName string, parameters Deployment, cancel <-chan struct{}) (*http.Request, error) { +func (client DeploymentsClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, deploymentName string, parameters Deployment) (*http.Request, error) { pathParameters := map[string]interface{}{ "deploymentName": autorest.Encode("path", deploymentName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-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.Resources/deployments/{deploymentName}", pathParameters), autorest.WithJSON(parameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{Cancel: cancel}) + 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 DeploymentsClient) CreateOrUpdateSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, - req, - azure.DoPollForAsynchronous(client.PollingDelay)) +func (client DeploymentsClient) CreateOrUpdateSender(req *http.Request) (future DeploymentsCreateOrUpdateFuture, err error) { + var resp *http.Response + resp, err = autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) + if err != nil { + return + } + future.Future, err = azure.NewFutureFromResponse(resp) + return } // CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always @@ -308,80 +273,43 @@ func (client DeploymentsClient) CreateOrUpdateResponder(resp *http.Response) (re return } -// Delete a template deployment that is currently running cannot be deleted. -// Deleting a template deployment removes the associated deployment operations. -// Deleting a template deployment does not affect the state of the resource -// group. This is an asynchronous operation that returns a status of 202 until -// the template deployment is successfully deleted. The Location response -// header contains the URI that is used to obtain the status of the process. -// While the process is running, a call to the URI in the Location header -// returns a status of 202. When the process finishes, the URI in the Location -// header returns a status of 204 on success. If the asynchronous request -// failed, the URI in the Location header returns an error-level status code. -// This method may poll for completion. Polling can be canceled by passing the -// cancel channel argument. The channel will be used to cancel polling and any -// outstanding HTTP requests. -// -// resourceGroupName is the name of the resource group with the deployment to -// delete. The name is case insensitive. deploymentName is the name of the -// deployment to delete. -func (client DeploymentsClient) Delete(resourceGroupName string, deploymentName string, cancel <-chan struct{}) (<-chan autorest.Response, <-chan error) { - resultChan := make(chan autorest.Response, 1) - errChan := make(chan error, 1) +// Delete delete deployment. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// deploymentName - the name of the deployment to be deleted. +func (client DeploymentsClient) Delete(ctx context.Context, resourceGroupName string, deploymentName string) (result DeploymentsDeleteFuture, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: deploymentName, - Constraints: []validation.Constraint{{Target: "deploymentName", Name: validation.MaxLength, Rule: 64, Chain: nil}, - {Target: "deploymentName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "deploymentName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - errChan <- validation.NewErrorWithValidationError(err, "resources.DeploymentsClient", "Delete") - close(errChan) - close(resultChan) - return resultChan, errChan + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.DeploymentsClient", "Delete", err.Error()) } - go func() { - var err error - var result autorest.Response - defer func() { - resultChan <- result - errChan <- err - close(resultChan) - close(errChan) - }() - req, err := client.DeletePreparer(resourceGroupName, deploymentName, cancel) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "Delete", nil, "Failure preparing request") - return - } + req, err := client.DeletePreparer(ctx, resourceGroupName, deploymentName) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "Delete", nil, "Failure preparing request") + return + } - resp, err := client.DeleteSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "Delete", resp, "Failure sending request") - return - } + result, err = client.DeleteSender(req) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "Delete", result.Response(), "Failure sending request") + return + } - result, err = client.DeleteResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "Delete", resp, "Failure responding to request") - } - }() - return resultChan, errChan + return } // DeletePreparer prepares the Delete request. -func (client DeploymentsClient) DeletePreparer(resourceGroupName string, deploymentName string, cancel <-chan struct{}) (*http.Request, error) { +func (client DeploymentsClient) DeletePreparer(ctx context.Context, resourceGroupName string, deploymentName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "deploymentName": autorest.Encode("path", deploymentName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -391,15 +319,20 @@ func (client DeploymentsClient) DeletePreparer(resourceGroupName string, deploym autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}", pathParameters), autorest.WithQueryParameters(queryParameters)) - 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 DeploymentsClient) DeleteSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, - req, - azure.DoPollForAsynchronous(client.PollingDelay)) +func (client DeploymentsClient) DeleteSender(req *http.Request) (future DeploymentsDeleteFuture, err error) { + var resp *http.Response + resp, err = autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) + if err != nil { + return + } + future.Future, err = azure.NewFutureFromResponse(resp) + return } // DeleteResponder handles the response to the Delete request. The method always @@ -414,25 +347,20 @@ func (client DeploymentsClient) DeleteResponder(resp *http.Response) (result aut return } -// ExportTemplate exports the template used for specified deployment. -// -// resourceGroupName is the name of the resource group. The name is case -// insensitive. deploymentName is the name of the deployment from which to get -// the template. -func (client DeploymentsClient) ExportTemplate(resourceGroupName string, deploymentName string) (result DeploymentExportResult, err error) { +// ExportTemplate exports a deployment template. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// deploymentName - the name of the deployment. +func (client DeploymentsClient) ExportTemplate(ctx context.Context, resourceGroupName string, deploymentName string) (result DeploymentExportResult, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: deploymentName, - Constraints: []validation.Constraint{{Target: "deploymentName", Name: validation.MaxLength, Rule: 64, Chain: nil}, - {Target: "deploymentName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "deploymentName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.DeploymentsClient", "ExportTemplate") + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.DeploymentsClient", "ExportTemplate", err.Error()) } - req, err := client.ExportTemplatePreparer(resourceGroupName, deploymentName) + req, err := client.ExportTemplatePreparer(ctx, resourceGroupName, deploymentName) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "ExportTemplate", nil, "Failure preparing request") return @@ -454,14 +382,14 @@ func (client DeploymentsClient) ExportTemplate(resourceGroupName string, deploym } // ExportTemplatePreparer prepares the ExportTemplate request. -func (client DeploymentsClient) ExportTemplatePreparer(resourceGroupName string, deploymentName string) (*http.Request, error) { +func (client DeploymentsClient) ExportTemplatePreparer(ctx context.Context, resourceGroupName string, deploymentName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "deploymentName": autorest.Encode("path", deploymentName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -471,13 +399,14 @@ func (client DeploymentsClient) ExportTemplatePreparer(resourceGroupName string, autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}/exportTemplate", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // ExportTemplateSender sends the ExportTemplate request. The method will close the // http.Response Body if it receives an error. func (client DeploymentsClient) ExportTemplateSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // ExportTemplateResponder handles the response to the ExportTemplate request. The method always @@ -493,24 +422,20 @@ func (client DeploymentsClient) ExportTemplateResponder(resp *http.Response) (re return } -// Get gets a deployment. -// -// resourceGroupName is the name of the resource group. The name is case -// insensitive. deploymentName is the name of the deployment to get. -func (client DeploymentsClient) Get(resourceGroupName string, deploymentName string) (result DeploymentExtended, err error) { +// Get get a deployment. +// Parameters: +// resourceGroupName - the name of the resource group to get. The name is case insensitive. +// deploymentName - the name of the deployment. +func (client DeploymentsClient) Get(ctx context.Context, resourceGroupName string, deploymentName string) (result DeploymentExtended, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: deploymentName, - Constraints: []validation.Constraint{{Target: "deploymentName", Name: validation.MaxLength, Rule: 64, Chain: nil}, - {Target: "deploymentName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "deploymentName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.DeploymentsClient", "Get") + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.DeploymentsClient", "Get", err.Error()) } - req, err := client.GetPreparer(resourceGroupName, deploymentName) + req, err := client.GetPreparer(ctx, resourceGroupName, deploymentName) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "Get", nil, "Failure preparing request") return @@ -532,14 +457,14 @@ func (client DeploymentsClient) Get(resourceGroupName string, deploymentName str } // GetPreparer prepares the Get request. -func (client DeploymentsClient) GetPreparer(resourceGroupName string, deploymentName string) (*http.Request, error) { +func (client DeploymentsClient) GetPreparer(ctx context.Context, resourceGroupName string, deploymentName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "deploymentName": autorest.Encode("path", deploymentName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -549,13 +474,14 @@ func (client DeploymentsClient) GetPreparer(resourceGroupName string, deployment autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}", 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 DeploymentsClient) 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 @@ -571,23 +497,22 @@ func (client DeploymentsClient) GetResponder(resp *http.Response) (result Deploy return } -// List get all the deployments for a resource group. -// -// resourceGroupName is the name of the resource group with the deployments to -// get. The name is case insensitive. filter is the filter to apply on the -// operation. For example, you can use $filter=provisioningState eq '{state}'. -// top is the number of results to get. If null is passed, returns all -// deployments. -func (client DeploymentsClient) List(resourceGroupName string, filter string, top *int32) (result DeploymentListResult, err error) { +// List get a list of deployments. +// Parameters: +// resourceGroupName - the name of the resource group to filter by. The name is case insensitive. +// filter - the filter to apply on the operation. +// top - query parameters. If null is passed returns all deployments. +func (client DeploymentsClient) List(ctx context.Context, resourceGroupName string, filter string, top *int32) (result DeploymentListResultPage, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.DeploymentsClient", "List") + return result, validation.NewError("resources.DeploymentsClient", "List", err.Error()) } - req, err := client.ListPreparer(resourceGroupName, filter, top) + result.fn = client.listNextResults + req, err := client.ListPreparer(ctx, resourceGroupName, filter, top) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "List", nil, "Failure preparing request") return @@ -595,12 +520,12 @@ func (client DeploymentsClient) List(resourceGroupName string, filter string, to resp, err := client.ListSender(req) if err != nil { - result.Response = autorest.Response{Response: resp} + result.dlr.Response = autorest.Response{Response: resp} err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "List", resp, "Failure sending request") return } - result, err = client.ListResponder(resp) + result.dlr, err = client.ListResponder(resp) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "List", resp, "Failure responding to request") } @@ -609,13 +534,13 @@ func (client DeploymentsClient) List(resourceGroupName string, filter string, to } // ListPreparer prepares the List request. -func (client DeploymentsClient) ListPreparer(resourceGroupName string, filter string, top *int32) (*http.Request, error) { +func (client DeploymentsClient) ListPreparer(ctx context.Context, resourceGroupName string, filter string, top *int32) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -631,13 +556,14 @@ func (client DeploymentsClient) ListPreparer(resourceGroupName string, filter st autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/", 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 DeploymentsClient) 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 @@ -653,57 +579,55 @@ func (client DeploymentsClient) ListResponder(resp *http.Response) (result Deplo return } -// ListNextResults retrieves the next set of results, if any. -func (client DeploymentsClient) ListNextResults(lastResults DeploymentListResult) (result DeploymentListResult, err error) { - req, err := lastResults.DeploymentListResultPreparer() +// listNextResults retrieves the next set of results, if any. +func (client DeploymentsClient) listNextResults(lastResults DeploymentListResult) (result DeploymentListResult, err error) { + req, err := lastResults.deploymentListResultPreparer() if err != nil { - return result, autorest.NewErrorWithError(err, "resources.DeploymentsClient", "List", nil, "Failure preparing next results request") + return result, autorest.NewErrorWithError(err, "resources.DeploymentsClient", "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, "resources.DeploymentsClient", "List", resp, "Failure sending next results request") + return result, autorest.NewErrorWithError(err, "resources.DeploymentsClient", "listNextResults", resp, "Failure sending next results request") } - result, err = client.ListResponder(resp) if err != nil { - err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "List", resp, "Failure responding to next results request") + err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "listNextResults", resp, "Failure responding to next results request") } - return } -// Validate validates whether the specified template is syntactically correct -// and will be accepted by Azure Resource Manager.. -// -// resourceGroupName is the name of the resource group the template will be -// deployed to. The name is case insensitive. deploymentName is the name of the -// deployment. parameters is parameters to validate. -func (client DeploymentsClient) Validate(resourceGroupName string, deploymentName string, parameters Deployment) (result DeploymentValidateResult, err error) { +// ListComplete enumerates all values, automatically crossing page boundaries as required. +func (client DeploymentsClient) ListComplete(ctx context.Context, resourceGroupName string, filter string, top *int32) (result DeploymentListResultIterator, err error) { + result.page, err = client.List(ctx, resourceGroupName, filter, top) + return +} + +// Validate validate a deployment template. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// deploymentName - the name of the deployment. +// parameters - deployment to validate. +func (client DeploymentsClient) Validate(ctx context.Context, resourceGroupName string, deploymentName string, parameters Deployment) (result DeploymentValidateResult, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: deploymentName, - Constraints: []validation.Constraint{{Target: "deploymentName", Name: validation.MaxLength, Rule: 64, Chain: nil}, - {Target: "deploymentName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "deploymentName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, {TargetValue: parameters, - Constraints: []validation.Constraint{{Target: "parameters.Properties", Name: validation.Null, Rule: true, + Constraints: []validation.Constraint{{Target: "parameters.Properties", Name: validation.Null, Rule: false, Chain: []validation.Constraint{{Target: "parameters.Properties.TemplateLink", Name: validation.Null, Rule: false, Chain: []validation.Constraint{{Target: "parameters.Properties.TemplateLink.URI", Name: validation.Null, Rule: true, Chain: nil}}}, {Target: "parameters.Properties.ParametersLink", Name: validation.Null, Rule: false, Chain: []validation.Constraint{{Target: "parameters.Properties.ParametersLink.URI", Name: validation.Null, Rule: true, Chain: nil}}}, }}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.DeploymentsClient", "Validate") + return result, validation.NewError("resources.DeploymentsClient", "Validate", err.Error()) } - req, err := client.ValidatePreparer(resourceGroupName, deploymentName, parameters) + req, err := client.ValidatePreparer(ctx, resourceGroupName, deploymentName, parameters) if err != nil { err = autorest.NewErrorWithError(err, "resources.DeploymentsClient", "Validate", nil, "Failure preparing request") return @@ -725,32 +649,33 @@ func (client DeploymentsClient) Validate(resourceGroupName string, deploymentNam } // ValidatePreparer prepares the Validate request. -func (client DeploymentsClient) ValidatePreparer(resourceGroupName string, deploymentName string, parameters Deployment) (*http.Request, error) { +func (client DeploymentsClient) ValidatePreparer(ctx context.Context, resourceGroupName string, deploymentName string, parameters Deployment) (*http.Request, error) { pathParameters := map[string]interface{}{ "deploymentName": autorest.Encode("path", deploymentName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } preparer := autorest.CreatePreparer( - autorest.AsJSON(), + autorest.AsContentType("application/json; charset=utf-8"), autorest.AsPost(), autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/deployments/{deploymentName}/validate", pathParameters), autorest.WithJSON(parameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // ValidateSender sends the Validate request. The method will close the // http.Response Body if it receives an error. func (client DeploymentsClient) ValidateSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // ValidateResponder handles the response to the Validate request. The method always diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/groups.go b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/groups.go similarity index 67% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/groups.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/groups.go index 13244a9ea..f4d05a1b4 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/groups.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/groups.go @@ -14,21 +14,20 @@ package resources // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. import ( + "context" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/validation" "net/http" ) -// GroupsClient is the provides operations for working with resources and -// resource groups. +// GroupsClient is the client for the Groups methods of the Resources service. type GroupsClient struct { - ManagementClient + BaseClient } // NewGroupsClient creates an instance of the GroupsClient client. @@ -41,20 +40,19 @@ func NewGroupsClientWithBaseURI(baseURI string, subscriptionID string) GroupsCli return GroupsClient{NewWithBaseURI(baseURI, subscriptionID)} } -// CheckExistence checks whether a resource group exists. -// -// resourceGroupName is the name of the resource group to check. The name is -// case insensitive. -func (client GroupsClient) CheckExistence(resourceGroupName string) (result autorest.Response, err error) { +// CheckExistence checks whether resource group exists. +// Parameters: +// resourceGroupName - the name of the resource group to check. The name is case insensitive. +func (client GroupsClient) CheckExistence(ctx context.Context, resourceGroupName string) (result autorest.Response, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.GroupsClient", "CheckExistence") + return result, validation.NewError("resources.GroupsClient", "CheckExistence", err.Error()) } - req, err := client.CheckExistencePreparer(resourceGroupName) + req, err := client.CheckExistencePreparer(ctx, resourceGroupName) if err != nil { err = autorest.NewErrorWithError(err, "resources.GroupsClient", "CheckExistence", nil, "Failure preparing request") return @@ -76,13 +74,13 @@ func (client GroupsClient) CheckExistence(resourceGroupName string) (result auto } // CheckExistencePreparer prepares the CheckExistence request. -func (client GroupsClient) CheckExistencePreparer(resourceGroupName string) (*http.Request, error) { +func (client GroupsClient) CheckExistencePreparer(ctx context.Context, resourceGroupName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -92,13 +90,14 @@ func (client GroupsClient) CheckExistencePreparer(resourceGroupName string) (*ht autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // CheckExistenceSender sends the CheckExistence request. The method will close the // http.Response Body if it receives an error. func (client GroupsClient) CheckExistenceSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // CheckExistenceResponder handles the response to the CheckExistence request. The method always @@ -113,11 +112,11 @@ func (client GroupsClient) CheckExistenceResponder(resp *http.Response) (result return } -// CreateOrUpdate creates a resource group. -// -// resourceGroupName is the name of the resource group to create or update. -// parameters is parameters supplied to the create or update a resource group. -func (client GroupsClient) CreateOrUpdate(resourceGroupName string, parameters Group) (result Group, err error) { +// CreateOrUpdate create a resource group. +// Parameters: +// resourceGroupName - the name of the resource group to be created or updated. +// parameters - parameters supplied to the create or update resource group service operation. +func (client GroupsClient) CreateOrUpdate(ctx context.Context, resourceGroupName string, parameters Group) (result Group, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, @@ -125,10 +124,10 @@ func (client GroupsClient) CreateOrUpdate(resourceGroupName string, parameters G {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, {TargetValue: parameters, Constraints: []validation.Constraint{{Target: "parameters.Location", Name: validation.Null, Rule: true, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.GroupsClient", "CreateOrUpdate") + return result, validation.NewError("resources.GroupsClient", "CreateOrUpdate", err.Error()) } - req, err := client.CreateOrUpdatePreparer(resourceGroupName, parameters) + req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, parameters) if err != nil { err = autorest.NewErrorWithError(err, "resources.GroupsClient", "CreateOrUpdate", nil, "Failure preparing request") return @@ -150,31 +149,32 @@ func (client GroupsClient) CreateOrUpdate(resourceGroupName string, parameters G } // CreateOrUpdatePreparer prepares the CreateOrUpdate request. -func (client GroupsClient) CreateOrUpdatePreparer(resourceGroupName string, parameters Group) (*http.Request, error) { +func (client GroupsClient) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, parameters Group) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-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}", pathParameters), autorest.WithJSON(parameters), autorest.WithQueryParameters(queryParameters)) - 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 GroupsClient) 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 @@ -183,73 +183,48 @@ func (client GroupsClient) CreateOrUpdateResponder(resp *http.Response) (result err = autorest.Respond( resp, client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusCreated, http.StatusOK), + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated), autorest.ByUnmarshallingJSON(&result), autorest.ByClosing()) result.Response = autorest.Response{Response: resp} return } -// Delete when you delete a resource group, all of its resources are also -// deleted. Deleting a resource group deletes all of its template deployments -// and currently stored operations. This method may poll for completion. -// Polling can be canceled by passing the cancel channel argument. The channel -// will be used to cancel polling and any outstanding HTTP requests. -// -// resourceGroupName is the name of the resource group to delete. The name is -// case insensitive. -func (client GroupsClient) Delete(resourceGroupName string, cancel <-chan struct{}) (<-chan autorest.Response, <-chan error) { - resultChan := make(chan autorest.Response, 1) - errChan := make(chan error, 1) +// Delete delete resource group. +// Parameters: +// resourceGroupName - the name of the resource group to be deleted. The name is case insensitive. +func (client GroupsClient) Delete(ctx context.Context, resourceGroupName string) (result GroupsDeleteFuture, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - errChan <- validation.NewErrorWithValidationError(err, "resources.GroupsClient", "Delete") - close(errChan) - close(resultChan) - return resultChan, errChan + return result, validation.NewError("resources.GroupsClient", "Delete", err.Error()) } - go func() { - var err error - var result autorest.Response - defer func() { - resultChan <- result - errChan <- err - close(resultChan) - close(errChan) - }() - req, err := client.DeletePreparer(resourceGroupName, cancel) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupsClient", "Delete", nil, "Failure preparing request") - return - } + req, err := client.DeletePreparer(ctx, resourceGroupName) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.GroupsClient", "Delete", nil, "Failure preparing request") + return + } - resp, err := client.DeleteSender(req) - if err != nil { - result.Response = resp - err = autorest.NewErrorWithError(err, "resources.GroupsClient", "Delete", resp, "Failure sending request") - return - } + result, err = client.DeleteSender(req) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.GroupsClient", "Delete", result.Response(), "Failure sending request") + return + } - result, err = client.DeleteResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupsClient", "Delete", resp, "Failure responding to request") - } - }() - return resultChan, errChan + return } // DeletePreparer prepares the Delete request. -func (client GroupsClient) DeletePreparer(resourceGroupName string, cancel <-chan struct{}) (*http.Request, error) { +func (client GroupsClient) DeletePreparer(ctx context.Context, resourceGroupName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -259,15 +234,20 @@ func (client GroupsClient) DeletePreparer(resourceGroupName string, cancel <-cha autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}", pathParameters), autorest.WithQueryParameters(queryParameters)) - 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 GroupsClient) DeleteSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, - req, - azure.DoPollForAsynchronous(client.PollingDelay)) +func (client GroupsClient) DeleteSender(req *http.Request) (future GroupsDeleteFuture, err error) { + var resp *http.Response + resp, err = autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) + if err != nil { + return + } + future.Future, err = azure.NewFutureFromResponse(resp) + return } // DeleteResponder handles the response to the Delete request. The method always @@ -276,26 +256,26 @@ func (client GroupsClient) DeleteResponder(resp *http.Response) (result autorest err = autorest.Respond( resp, client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusAccepted, http.StatusOK), + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), autorest.ByClosing()) result.Response = resp return } // ExportTemplate captures the specified resource group as a template. -// -// resourceGroupName is the name of the resource group to export as a template. -// parameters is parameters for exporting the template. -func (client GroupsClient) ExportTemplate(resourceGroupName string, parameters ExportTemplateRequest) (result GroupExportResult, err error) { +// Parameters: +// resourceGroupName - the name of the resource group to be created or updated. +// parameters - parameters supplied to the export template resource group operation. +func (client GroupsClient) ExportTemplate(ctx context.Context, resourceGroupName string, parameters ExportTemplateRequest) (result GroupExportResult, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.GroupsClient", "ExportTemplate") + return result, validation.NewError("resources.GroupsClient", "ExportTemplate", err.Error()) } - req, err := client.ExportTemplatePreparer(resourceGroupName, parameters) + req, err := client.ExportTemplatePreparer(ctx, resourceGroupName, parameters) if err != nil { err = autorest.NewErrorWithError(err, "resources.GroupsClient", "ExportTemplate", nil, "Failure preparing request") return @@ -317,31 +297,32 @@ func (client GroupsClient) ExportTemplate(resourceGroupName string, parameters E } // ExportTemplatePreparer prepares the ExportTemplate request. -func (client GroupsClient) ExportTemplatePreparer(resourceGroupName string, parameters ExportTemplateRequest) (*http.Request, error) { +func (client GroupsClient) ExportTemplatePreparer(ctx context.Context, resourceGroupName string, parameters ExportTemplateRequest) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } preparer := autorest.CreatePreparer( - autorest.AsJSON(), + autorest.AsContentType("application/json; charset=utf-8"), autorest.AsPost(), autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/exportTemplate", pathParameters), autorest.WithJSON(parameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // ExportTemplateSender sends the ExportTemplate request. The method will close the // http.Response Body if it receives an error. func (client GroupsClient) ExportTemplateSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // ExportTemplateResponder handles the response to the ExportTemplate request. The method always @@ -357,20 +338,19 @@ func (client GroupsClient) ExportTemplateResponder(resp *http.Response) (result return } -// Get gets a resource group. -// -// resourceGroupName is the name of the resource group to get. The name is case -// insensitive. -func (client GroupsClient) Get(resourceGroupName string) (result Group, err error) { +// Get get a resource group. +// Parameters: +// resourceGroupName - the name of the resource group to get. The name is case insensitive. +func (client GroupsClient) Get(ctx context.Context, resourceGroupName string) (result Group, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.GroupsClient", "Get") + return result, validation.NewError("resources.GroupsClient", "Get", err.Error()) } - req, err := client.GetPreparer(resourceGroupName) + req, err := client.GetPreparer(ctx, resourceGroupName) if err != nil { err = autorest.NewErrorWithError(err, "resources.GroupsClient", "Get", nil, "Failure preparing request") return @@ -392,13 +372,13 @@ func (client GroupsClient) Get(resourceGroupName string) (result Group, err erro } // GetPreparer prepares the Get request. -func (client GroupsClient) GetPreparer(resourceGroupName string) (*http.Request, error) { +func (client GroupsClient) GetPreparer(ctx context.Context, resourceGroupName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -408,13 +388,14 @@ func (client GroupsClient) GetPreparer(resourceGroupName string) (*http.Request, autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}", 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 GroupsClient) 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 @@ -430,12 +411,13 @@ func (client GroupsClient) GetResponder(resp *http.Response) (result Group, err return } -// List gets all the resource groups for a subscription. -// -// filter is the filter to apply on the operation. top is the number of results -// to return. If null is passed, returns all resource groups. -func (client GroupsClient) List(filter string, top *int32) (result GroupListResult, err error) { - req, err := client.ListPreparer(filter, top) +// List gets a collection of resource groups. +// Parameters: +// filter - the filter to apply on the operation. +// top - query parameters. If null is passed returns all resource groups. +func (client GroupsClient) List(ctx context.Context, filter string, top *int32) (result GroupListResultPage, err error) { + result.fn = client.listNextResults + req, err := client.ListPreparer(ctx, filter, top) if err != nil { err = autorest.NewErrorWithError(err, "resources.GroupsClient", "List", nil, "Failure preparing request") return @@ -443,12 +425,12 @@ func (client GroupsClient) List(filter string, top *int32) (result GroupListResu resp, err := client.ListSender(req) if err != nil { - result.Response = autorest.Response{Response: resp} + result.glr.Response = autorest.Response{Response: resp} err = autorest.NewErrorWithError(err, "resources.GroupsClient", "List", resp, "Failure sending request") return } - result, err = client.ListResponder(resp) + result.glr, err = client.ListResponder(resp) if err != nil { err = autorest.NewErrorWithError(err, "resources.GroupsClient", "List", resp, "Failure responding to request") } @@ -457,12 +439,12 @@ func (client GroupsClient) List(filter string, top *int32) (result GroupListResu } // ListPreparer prepares the List request. -func (client GroupsClient) ListPreparer(filter string, top *int32) (*http.Request, error) { +func (client GroupsClient) ListPreparer(ctx context.Context, filter string, top *int32) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -478,13 +460,14 @@ func (client GroupsClient) ListPreparer(filter string, top *int32) (*http.Reques autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups", 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 GroupsClient) 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 @@ -500,46 +483,50 @@ func (client GroupsClient) ListResponder(resp *http.Response) (result GroupListR return } -// ListNextResults retrieves the next set of results, if any. -func (client GroupsClient) ListNextResults(lastResults GroupListResult) (result GroupListResult, err error) { - req, err := lastResults.GroupListResultPreparer() +// listNextResults retrieves the next set of results, if any. +func (client GroupsClient) listNextResults(lastResults GroupListResult) (result GroupListResult, err error) { + req, err := lastResults.groupListResultPreparer() if err != nil { - return result, autorest.NewErrorWithError(err, "resources.GroupsClient", "List", nil, "Failure preparing next results request") + return result, autorest.NewErrorWithError(err, "resources.GroupsClient", "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, "resources.GroupsClient", "List", resp, "Failure sending next results request") + return result, autorest.NewErrorWithError(err, "resources.GroupsClient", "listNextResults", resp, "Failure sending next results request") } - result, err = client.ListResponder(resp) if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupsClient", "List", resp, "Failure responding to next results request") + err = autorest.NewErrorWithError(err, "resources.GroupsClient", "listNextResults", resp, "Failure responding to next results request") } - return } -// ListResources get all the resources for a resource group. -// -// resourceGroupName is the resource group with the resources to get. filter is -// the filter to apply on the operation. expand is the $expand query parameter -// top is the number of results to return. If null is passed, returns all -// resources. -func (client GroupsClient) ListResources(resourceGroupName string, filter string, expand string, top *int32) (result ListResult, err error) { +// ListComplete enumerates all values, automatically crossing page boundaries as required. +func (client GroupsClient) ListComplete(ctx context.Context, filter string, top *int32) (result GroupListResultIterator, err error) { + result.page, err = client.List(ctx, filter, top) + return +} + +// ListResources get all of the resources under a subscription. +// Parameters: +// resourceGroupName - query parameters. If null is passed returns all resource groups. +// filter - the filter to apply on the operation. +// expand - the $expand query parameter +// top - query parameters. If null is passed returns all resource groups. +func (client GroupsClient) ListResources(ctx context.Context, resourceGroupName string, filter string, expand string, top *int32) (result ListResultPage, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.GroupsClient", "ListResources") + return result, validation.NewError("resources.GroupsClient", "ListResources", err.Error()) } - req, err := client.ListResourcesPreparer(resourceGroupName, filter, expand, top) + result.fn = client.listResourcesNextResults + req, err := client.ListResourcesPreparer(ctx, resourceGroupName, filter, expand, top) if err != nil { err = autorest.NewErrorWithError(err, "resources.GroupsClient", "ListResources", nil, "Failure preparing request") return @@ -547,12 +534,12 @@ func (client GroupsClient) ListResources(resourceGroupName string, filter string resp, err := client.ListResourcesSender(req) if err != nil { - result.Response = autorest.Response{Response: resp} + result.lr.Response = autorest.Response{Response: resp} err = autorest.NewErrorWithError(err, "resources.GroupsClient", "ListResources", resp, "Failure sending request") return } - result, err = client.ListResourcesResponder(resp) + result.lr, err = client.ListResourcesResponder(resp) if err != nil { err = autorest.NewErrorWithError(err, "resources.GroupsClient", "ListResources", resp, "Failure responding to request") } @@ -561,13 +548,13 @@ func (client GroupsClient) ListResources(resourceGroupName string, filter string } // ListResourcesPreparer prepares the ListResources request. -func (client GroupsClient) ListResourcesPreparer(resourceGroupName string, filter string, expand string, top *int32) (*http.Request, error) { +func (client GroupsClient) ListResourcesPreparer(ctx context.Context, resourceGroupName string, filter string, expand string, top *int32) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -586,13 +573,14 @@ func (client GroupsClient) ListResourcesPreparer(resourceGroupName string, filte autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/resources", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // ListResourcesSender sends the ListResources request. The method will close the // http.Response Body if it receives an error. func (client GroupsClient) ListResourcesSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // ListResourcesResponder handles the response to the ListResources request. The method always @@ -608,47 +596,49 @@ func (client GroupsClient) ListResourcesResponder(resp *http.Response) (result L return } -// ListResourcesNextResults retrieves the next set of results, if any. -func (client GroupsClient) ListResourcesNextResults(lastResults ListResult) (result ListResult, err error) { - req, err := lastResults.ListResultPreparer() +// listResourcesNextResults retrieves the next set of results, if any. +func (client GroupsClient) listResourcesNextResults(lastResults ListResult) (result ListResult, err error) { + req, err := lastResults.listResultPreparer() if err != nil { - return result, autorest.NewErrorWithError(err, "resources.GroupsClient", "ListResources", nil, "Failure preparing next results request") + return result, autorest.NewErrorWithError(err, "resources.GroupsClient", "listResourcesNextResults", nil, "Failure preparing next results request") } if req == nil { return } - resp, err := client.ListResourcesSender(req) if err != nil { result.Response = autorest.Response{Response: resp} - return result, autorest.NewErrorWithError(err, "resources.GroupsClient", "ListResources", resp, "Failure sending next results request") + return result, autorest.NewErrorWithError(err, "resources.GroupsClient", "listResourcesNextResults", resp, "Failure sending next results request") } - result, err = client.ListResourcesResponder(resp) if err != nil { - err = autorest.NewErrorWithError(err, "resources.GroupsClient", "ListResources", resp, "Failure responding to next results request") + err = autorest.NewErrorWithError(err, "resources.GroupsClient", "listResourcesNextResults", resp, "Failure responding to next results request") } - return } -// Patch resource groups can be updated through a simple PATCH operation to a -// group address. The format of the request is the same as that for creating a -// resource group. If a field is unspecified, the current value is retained. -// -// resourceGroupName is the name of the resource group to update. The name is -// case insensitive. parameters is parameters supplied to update a resource -// group. -func (client GroupsClient) Patch(resourceGroupName string, parameters Group) (result Group, err error) { +// ListResourcesComplete enumerates all values, automatically crossing page boundaries as required. +func (client GroupsClient) ListResourcesComplete(ctx context.Context, resourceGroupName string, filter string, expand string, top *int32) (result ListResultIterator, err error) { + result.page, err = client.ListResources(ctx, resourceGroupName, filter, expand, top) + return +} + +// Patch resource groups can be updated through a simple PATCH operation to a group address. The format of the request +// is the same as that for creating a resource groups, though if a field is unspecified current value will be carried +// over. +// Parameters: +// resourceGroupName - the name of the resource group to be created or updated. The name is case insensitive. +// parameters - parameters supplied to the update state resource group service operation. +func (client GroupsClient) Patch(ctx context.Context, resourceGroupName string, parameters Group) (result Group, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: resourceGroupName, Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "resources.GroupsClient", "Patch") + return result, validation.NewError("resources.GroupsClient", "Patch", err.Error()) } - req, err := client.PatchPreparer(resourceGroupName, parameters) + req, err := client.PatchPreparer(ctx, resourceGroupName, parameters) if err != nil { err = autorest.NewErrorWithError(err, "resources.GroupsClient", "Patch", nil, "Failure preparing request") return @@ -670,31 +660,32 @@ func (client GroupsClient) Patch(resourceGroupName string, parameters Group) (re } // PatchPreparer prepares the Patch request. -func (client GroupsClient) PatchPreparer(resourceGroupName string, parameters Group) (*http.Request, error) { +func (client GroupsClient) PatchPreparer(ctx context.Context, resourceGroupName string, parameters Group) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-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}", pathParameters), autorest.WithJSON(parameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // PatchSender sends the Patch request. The method will close the // http.Response Body if it receives an error. func (client GroupsClient) PatchSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // PatchResponder handles the response to the Patch request. The method always diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/models.go b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/models.go new file mode 100644 index 000000000..bf84a5d4c --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/models.go @@ -0,0 +1,1313 @@ +package resources + +// 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/date" + "github.com/Azure/go-autorest/autorest/to" + "net/http" +) + +// DeploymentMode enumerates the values for deployment mode. +type DeploymentMode string + +const ( + // Complete ... + Complete DeploymentMode = "Complete" + // Incremental ... + Incremental DeploymentMode = "Incremental" +) + +// PossibleDeploymentModeValues returns an array of possible values for the DeploymentMode const type. +func PossibleDeploymentModeValues() []DeploymentMode { + return []DeploymentMode{Complete, Incremental} +} + +// ResourceIdentityType enumerates the values for resource identity type. +type ResourceIdentityType string + +const ( + // SystemAssigned ... + SystemAssigned ResourceIdentityType = "SystemAssigned" +) + +// PossibleResourceIdentityTypeValues returns an array of possible values for the ResourceIdentityType const type. +func PossibleResourceIdentityTypeValues() []ResourceIdentityType { + return []ResourceIdentityType{SystemAssigned} +} + +// AliasPathType ... +type AliasPathType struct { + // Path - The path of an alias. + Path *string `json:"path,omitempty"` + // APIVersions - The api versions. + APIVersions *[]string `json:"apiVersions,omitempty"` +} + +// AliasType ... +type AliasType struct { + // Name - The alias name. + Name *string `json:"name,omitempty"` + // Paths - The paths for an alias. + Paths *[]AliasPathType `json:"paths,omitempty"` +} + +// BasicDependency deployment dependency information. +type BasicDependency struct { + // ID - The ID of the dependency. + ID *string `json:"id,omitempty"` + // ResourceType - The dependency resource type. + ResourceType *string `json:"resourceType,omitempty"` + // ResourceName - The dependency resource name. + ResourceName *string `json:"resourceName,omitempty"` +} + +// DebugSetting ... +type DebugSetting struct { + // DetailLevel - The debug detail level. + DetailLevel *string `json:"detailLevel,omitempty"` +} + +// Dependency deployment dependency information. +type Dependency struct { + // DependsOn - The list of dependencies. + DependsOn *[]BasicDependency `json:"dependsOn,omitempty"` + // ID - The ID of the dependency. + ID *string `json:"id,omitempty"` + // ResourceType - The dependency resource type. + ResourceType *string `json:"resourceType,omitempty"` + // ResourceName - The dependency resource name. + ResourceName *string `json:"resourceName,omitempty"` +} + +// Deployment deployment operation parameters. +type Deployment struct { + // Properties - The deployment properties. + Properties *DeploymentProperties `json:"properties,omitempty"` +} + +// DeploymentExportResult ... +type DeploymentExportResult struct { + autorest.Response `json:"-"` + // Template - The template content. + Template interface{} `json:"template,omitempty"` +} + +// DeploymentExtended deployment information. +type DeploymentExtended struct { + autorest.Response `json:"-"` + // ID - The ID of the deployment. + ID *string `json:"id,omitempty"` + // Name - The name of the deployment. + Name *string `json:"name,omitempty"` + // Properties - Deployment properties. + Properties *DeploymentPropertiesExtended `json:"properties,omitempty"` +} + +// DeploymentExtendedFilter deployment filter. +type DeploymentExtendedFilter struct { + // ProvisioningState - The provisioning state. + ProvisioningState *string `json:"provisioningState,omitempty"` +} + +// DeploymentListResult list of deployments. +type DeploymentListResult struct { + autorest.Response `json:"-"` + // Value - The list of deployments. + Value *[]DeploymentExtended `json:"value,omitempty"` + // NextLink - The URL to get the next set of results. + NextLink *string `json:"nextLink,omitempty"` +} + +// DeploymentListResultIterator provides access to a complete listing of DeploymentExtended values. +type DeploymentListResultIterator struct { + i int + page DeploymentListResultPage +} + +// 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 *DeploymentListResultIterator) 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 DeploymentListResultIterator) 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 DeploymentListResultIterator) Response() DeploymentListResult { + 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 DeploymentListResultIterator) Value() DeploymentExtended { + if !iter.page.NotDone() { + return DeploymentExtended{} + } + return iter.page.Values()[iter.i] +} + +// IsEmpty returns true if the ListResult contains no values. +func (dlr DeploymentListResult) IsEmpty() bool { + return dlr.Value == nil || len(*dlr.Value) == 0 +} + +// deploymentListResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (dlr DeploymentListResult) deploymentListResultPreparer() (*http.Request, error) { + if dlr.NextLink == nil || len(to.String(dlr.NextLink)) < 1 { + return nil, nil + } + return autorest.Prepare(&http.Request{}, + autorest.AsJSON(), + autorest.AsGet(), + autorest.WithBaseURL(to.String(dlr.NextLink))) +} + +// DeploymentListResultPage contains a page of DeploymentExtended values. +type DeploymentListResultPage struct { + fn func(DeploymentListResult) (DeploymentListResult, error) + dlr DeploymentListResult +} + +// 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 *DeploymentListResultPage) Next() error { + next, err := page.fn(page.dlr) + if err != nil { + return err + } + page.dlr = next + return nil +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page DeploymentListResultPage) NotDone() bool { + return !page.dlr.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page DeploymentListResultPage) Response() DeploymentListResult { + return page.dlr +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page DeploymentListResultPage) Values() []DeploymentExtended { + if page.dlr.IsEmpty() { + return nil + } + return *page.dlr.Value +} + +// DeploymentOperation deployment operation information. +type DeploymentOperation struct { + autorest.Response `json:"-"` + // ID - Full deployment operation id. + ID *string `json:"id,omitempty"` + // OperationID - Deployment operation id. + OperationID *string `json:"operationId,omitempty"` + // Properties - Deployment properties. + Properties *DeploymentOperationProperties `json:"properties,omitempty"` +} + +// DeploymentOperationProperties deployment operation properties. +type DeploymentOperationProperties struct { + // ProvisioningState - The state of the provisioning. + ProvisioningState *string `json:"provisioningState,omitempty"` + // Timestamp - The date and time of the operation. + Timestamp *date.Time `json:"timestamp,omitempty"` + // ServiceRequestID - Deployment operation service request id. + ServiceRequestID *string `json:"serviceRequestId,omitempty"` + // StatusCode - Operation status code. + StatusCode *string `json:"statusCode,omitempty"` + // StatusMessage - Operation status message. + StatusMessage interface{} `json:"statusMessage,omitempty"` + // TargetResource - The target resource. + TargetResource *TargetResource `json:"targetResource,omitempty"` + // Request - The HTTP request message. + Request *HTTPMessage `json:"request,omitempty"` + // Response - The HTTP response message. + Response *HTTPMessage `json:"response,omitempty"` +} + +// DeploymentOperationsListResult list of deployment operations. +type DeploymentOperationsListResult struct { + autorest.Response `json:"-"` + // Value - The list of deployments. + Value *[]DeploymentOperation `json:"value,omitempty"` + // NextLink - The URL to get the next set of results. + NextLink *string `json:"nextLink,omitempty"` +} + +// DeploymentOperationsListResultIterator provides access to a complete listing of DeploymentOperation values. +type DeploymentOperationsListResultIterator struct { + i int + page DeploymentOperationsListResultPage +} + +// 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 *DeploymentOperationsListResultIterator) 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 DeploymentOperationsListResultIterator) 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 DeploymentOperationsListResultIterator) Response() DeploymentOperationsListResult { + 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 DeploymentOperationsListResultIterator) Value() DeploymentOperation { + if !iter.page.NotDone() { + return DeploymentOperation{} + } + return iter.page.Values()[iter.i] +} + +// IsEmpty returns true if the ListResult contains no values. +func (dolr DeploymentOperationsListResult) IsEmpty() bool { + return dolr.Value == nil || len(*dolr.Value) == 0 +} + +// deploymentOperationsListResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (dolr DeploymentOperationsListResult) deploymentOperationsListResultPreparer() (*http.Request, error) { + if dolr.NextLink == nil || len(to.String(dolr.NextLink)) < 1 { + return nil, nil + } + return autorest.Prepare(&http.Request{}, + autorest.AsJSON(), + autorest.AsGet(), + autorest.WithBaseURL(to.String(dolr.NextLink))) +} + +// DeploymentOperationsListResultPage contains a page of DeploymentOperation values. +type DeploymentOperationsListResultPage struct { + fn func(DeploymentOperationsListResult) (DeploymentOperationsListResult, error) + dolr DeploymentOperationsListResult +} + +// 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 *DeploymentOperationsListResultPage) Next() error { + next, err := page.fn(page.dolr) + if err != nil { + return err + } + page.dolr = next + return nil +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page DeploymentOperationsListResultPage) NotDone() bool { + return !page.dolr.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page DeploymentOperationsListResultPage) Response() DeploymentOperationsListResult { + return page.dolr +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page DeploymentOperationsListResultPage) Values() []DeploymentOperation { + if page.dolr.IsEmpty() { + return nil + } + return *page.dolr.Value +} + +// DeploymentProperties deployment properties. +type DeploymentProperties struct { + // Template - The template content. It can be a JObject or a well formed JSON string. Use only one of Template or TemplateLink. + Template interface{} `json:"template,omitempty"` + // TemplateLink - The template URI. Use only one of Template or TemplateLink. + TemplateLink *TemplateLink `json:"templateLink,omitempty"` + // Parameters - Deployment parameters. It can be a JObject or a well formed JSON string. Use only one of Parameters or ParametersLink. + Parameters interface{} `json:"parameters,omitempty"` + // ParametersLink - The parameters URI. Use only one of Parameters or ParametersLink. + ParametersLink *ParametersLink `json:"parametersLink,omitempty"` + // Mode - The deployment mode. Possible values include: 'Incremental', 'Complete' + Mode DeploymentMode `json:"mode,omitempty"` + // DebugSetting - The debug setting of the deployment. + DebugSetting *DebugSetting `json:"debugSetting,omitempty"` +} + +// DeploymentPropertiesExtended deployment properties with additional details. +type DeploymentPropertiesExtended struct { + // ProvisioningState - The state of the provisioning. + ProvisioningState *string `json:"provisioningState,omitempty"` + // CorrelationID - The correlation ID of the deployment. + CorrelationID *string `json:"correlationId,omitempty"` + // Timestamp - The timestamp of the template deployment. + Timestamp *date.Time `json:"timestamp,omitempty"` + // Outputs - Key/value pairs that represent deploymentoutput. + Outputs interface{} `json:"outputs,omitempty"` + // Providers - The list of resource providers needed for the deployment. + Providers *[]Provider `json:"providers,omitempty"` + // Dependencies - The list of deployment dependencies. + Dependencies *[]Dependency `json:"dependencies,omitempty"` + // Template - The template content. Use only one of Template or TemplateLink. + Template interface{} `json:"template,omitempty"` + // TemplateLink - The URI referencing the template. Use only one of Template or TemplateLink. + TemplateLink *TemplateLink `json:"templateLink,omitempty"` + // Parameters - Deployment parameters. Use only one of Parameters or ParametersLink. + Parameters interface{} `json:"parameters,omitempty"` + // ParametersLink - The URI referencing the parameters. Use only one of Parameters or ParametersLink. + ParametersLink *ParametersLink `json:"parametersLink,omitempty"` + // Mode - The deployment mode. Possible values include: 'Incremental', 'Complete' + Mode DeploymentMode `json:"mode,omitempty"` + // DebugSetting - The debug setting of the deployment. + DebugSetting *DebugSetting `json:"debugSetting,omitempty"` +} + +// DeploymentsCreateOrUpdateFuture an abstraction for monitoring and retrieving the results of a long-running +// operation. +type DeploymentsCreateOrUpdateFuture struct { + azure.Future +} + +// Result returns the result of the asynchronous operation. +// If the operation has not completed it will return an error. +func (future *DeploymentsCreateOrUpdateFuture) Result(client DeploymentsClient) (de DeploymentExtended, err error) { + var done bool + done, err = future.Done(client) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.DeploymentsCreateOrUpdateFuture", "Result", future.Response(), "Polling failure") + return + } + if !done { + err = azure.NewAsyncOpIncompleteError("resources.DeploymentsCreateOrUpdateFuture") + return + } + sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) + if de.Response.Response, err = future.GetResult(sender); err == nil && de.Response.Response.StatusCode != http.StatusNoContent { + de, err = client.CreateOrUpdateResponder(de.Response.Response) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.DeploymentsCreateOrUpdateFuture", "Result", de.Response.Response, "Failure responding to request") + } + } + return +} + +// DeploymentsDeleteFuture an abstraction for monitoring and retrieving the results of a long-running operation. +type DeploymentsDeleteFuture struct { + azure.Future +} + +// Result returns the result of the asynchronous operation. +// If the operation has not completed it will return an error. +func (future *DeploymentsDeleteFuture) Result(client DeploymentsClient) (ar autorest.Response, err error) { + var done bool + done, err = future.Done(client) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.DeploymentsDeleteFuture", "Result", future.Response(), "Polling failure") + return + } + if !done { + err = azure.NewAsyncOpIncompleteError("resources.DeploymentsDeleteFuture") + return + } + ar.Response = future.Response() + return +} + +// DeploymentValidateResult information from validate template deployment response. +type DeploymentValidateResult struct { + autorest.Response `json:"-"` + // Error - Validation error. + Error *ManagementErrorWithDetails `json:"error,omitempty"` + // Properties - The template deployment properties. + Properties *DeploymentPropertiesExtended `json:"properties,omitempty"` +} + +// ExportTemplateRequest export resource group template request parameters. +type ExportTemplateRequest struct { + // ResourcesProperty - The ids of the resources. The only supported string currently is '*' (all resources). Future api updates will support exporting specific resources. + ResourcesProperty *[]string `json:"resources,omitempty"` + // Options - The export template options. Supported values include 'IncludeParameterDefaultValue', 'IncludeComments' or 'IncludeParameterDefaultValue, IncludeComments + Options *string `json:"options,omitempty"` +} + +// GenericResource resource information. +type GenericResource struct { + autorest.Response `json:"-"` + // Plan - The plan of the resource. + Plan *Plan `json:"plan,omitempty"` + // Properties - The resource properties. + Properties interface{} `json:"properties,omitempty"` + // Kind - The kind of the resource. + Kind *string `json:"kind,omitempty"` + // ManagedBy - Id of the resource that manages this resource. + ManagedBy *string `json:"managedBy,omitempty"` + // Sku - The sku of the resource. + Sku *Sku `json:"sku,omitempty"` + // Identity - The identity of the resource. + Identity *Identity `json:"identity,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 GenericResource. +func (gr GenericResource) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]interface{}) + if gr.Plan != nil { + objectMap["plan"] = gr.Plan + } + objectMap["properties"] = gr.Properties + if gr.Kind != nil { + objectMap["kind"] = gr.Kind + } + if gr.ManagedBy != nil { + objectMap["managedBy"] = gr.ManagedBy + } + if gr.Sku != nil { + objectMap["sku"] = gr.Sku + } + if gr.Identity != nil { + objectMap["identity"] = gr.Identity + } + if gr.ID != nil { + objectMap["id"] = gr.ID + } + if gr.Name != nil { + objectMap["name"] = gr.Name + } + if gr.Type != nil { + objectMap["type"] = gr.Type + } + if gr.Location != nil { + objectMap["location"] = gr.Location + } + if gr.Tags != nil { + objectMap["tags"] = gr.Tags + } + return json.Marshal(objectMap) +} + +// GenericResourceFilter resource filter. +type GenericResourceFilter struct { + // ResourceType - The resource type. + ResourceType *string `json:"resourceType,omitempty"` + // Tagname - The tag name. + Tagname *string `json:"tagname,omitempty"` + // Tagvalue - The tag value. + Tagvalue *string `json:"tagvalue,omitempty"` +} + +// Group resource group information. +type Group struct { + autorest.Response `json:"-"` + // ID - The ID of the resource group. + ID *string `json:"id,omitempty"` + // Name - The Name of the resource group. + Name *string `json:"name,omitempty"` + Properties *GroupProperties `json:"properties,omitempty"` + // Location - The location of the resource group. It cannot be changed after the resource group has been created. Has to be one of the supported Azure Locations, such as West US, East US, West Europe, East Asia, etc. + Location *string `json:"location,omitempty"` + // Tags - The tags attached to the resource group. + Tags map[string]*string `json:"tags"` +} + +// MarshalJSON is the custom marshaler for Group. +func (g Group) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]interface{}) + if g.ID != nil { + objectMap["id"] = g.ID + } + if g.Name != nil { + objectMap["name"] = g.Name + } + if g.Properties != nil { + objectMap["properties"] = g.Properties + } + if g.Location != nil { + objectMap["location"] = g.Location + } + if g.Tags != nil { + objectMap["tags"] = g.Tags + } + return json.Marshal(objectMap) +} + +// GroupExportResult ... +type GroupExportResult struct { + autorest.Response `json:"-"` + // Template - The template content. + Template interface{} `json:"template,omitempty"` + // Error - The error. + Error *ManagementErrorWithDetails `json:"error,omitempty"` +} + +// GroupFilter resource group filter. +type GroupFilter struct { + // TagName - The tag name. + TagName *string `json:"tagName,omitempty"` + // TagValue - The tag value. + TagValue *string `json:"tagValue,omitempty"` +} + +// GroupListResult list of resource groups. +type GroupListResult struct { + autorest.Response `json:"-"` + // Value - The list of resource groups. + Value *[]Group `json:"value,omitempty"` + // NextLink - The URL to get the next set of results. + NextLink *string `json:"nextLink,omitempty"` +} + +// GroupListResultIterator provides access to a complete listing of Group values. +type GroupListResultIterator struct { + i int + page GroupListResultPage +} + +// 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 *GroupListResultIterator) 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 GroupListResultIterator) 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 GroupListResultIterator) Response() GroupListResult { + 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 GroupListResultIterator) Value() Group { + if !iter.page.NotDone() { + return Group{} + } + return iter.page.Values()[iter.i] +} + +// IsEmpty returns true if the ListResult contains no values. +func (glr GroupListResult) IsEmpty() bool { + return glr.Value == nil || len(*glr.Value) == 0 +} + +// groupListResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (glr GroupListResult) groupListResultPreparer() (*http.Request, error) { + if glr.NextLink == nil || len(to.String(glr.NextLink)) < 1 { + return nil, nil + } + return autorest.Prepare(&http.Request{}, + autorest.AsJSON(), + autorest.AsGet(), + autorest.WithBaseURL(to.String(glr.NextLink))) +} + +// GroupListResultPage contains a page of Group values. +type GroupListResultPage struct { + fn func(GroupListResult) (GroupListResult, error) + glr GroupListResult +} + +// 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 *GroupListResultPage) Next() error { + next, err := page.fn(page.glr) + if err != nil { + return err + } + page.glr = next + return nil +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page GroupListResultPage) NotDone() bool { + return !page.glr.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page GroupListResultPage) Response() GroupListResult { + return page.glr +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page GroupListResultPage) Values() []Group { + if page.glr.IsEmpty() { + return nil + } + return *page.glr.Value +} + +// GroupProperties the resource group properties. +type GroupProperties struct { + // ProvisioningState - The provisioning state. + ProvisioningState *string `json:"provisioningState,omitempty"` +} + +// GroupsDeleteFuture an abstraction for monitoring and retrieving the results of a long-running operation. +type GroupsDeleteFuture struct { + azure.Future +} + +// Result returns the result of the asynchronous operation. +// If the operation has not completed it will return an error. +func (future *GroupsDeleteFuture) Result(client GroupsClient) (ar autorest.Response, err error) { + var done bool + done, err = future.Done(client) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.GroupsDeleteFuture", "Result", future.Response(), "Polling failure") + return + } + if !done { + err = azure.NewAsyncOpIncompleteError("resources.GroupsDeleteFuture") + return + } + ar.Response = future.Response() + return +} + +// HTTPMessage ... +type HTTPMessage struct { + // Content - HTTP message content. + Content interface{} `json:"content,omitempty"` +} + +// Identity identity for the resource. +type Identity struct { + // PrincipalID - The principal id of resource identity. + PrincipalID *string `json:"principalId,omitempty"` + // TenantID - The tenant id of resource. + TenantID *string `json:"tenantId,omitempty"` + // Type - The identity type. Possible values include: 'SystemAssigned' + Type ResourceIdentityType `json:"type,omitempty"` +} + +// ListResult list of resource groups. +type ListResult struct { + autorest.Response `json:"-"` + // Value - The list of resources. + Value *[]GenericResource `json:"value,omitempty"` + // NextLink - The URL to get the next set of results. + NextLink *string `json:"nextLink,omitempty"` +} + +// ListResultIterator provides access to a complete listing of GenericResource values. +type ListResultIterator struct { + i int + page ListResultPage +} + +// 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 *ListResultIterator) 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 ListResultIterator) 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 ListResultIterator) Response() ListResult { + 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 ListResultIterator) Value() GenericResource { + if !iter.page.NotDone() { + return GenericResource{} + } + return iter.page.Values()[iter.i] +} + +// IsEmpty returns true if the ListResult contains no values. +func (lr ListResult) IsEmpty() bool { + return lr.Value == nil || len(*lr.Value) == 0 +} + +// listResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (lr ListResult) listResultPreparer() (*http.Request, error) { + if lr.NextLink == nil || len(to.String(lr.NextLink)) < 1 { + return nil, nil + } + return autorest.Prepare(&http.Request{}, + autorest.AsJSON(), + autorest.AsGet(), + autorest.WithBaseURL(to.String(lr.NextLink))) +} + +// ListResultPage contains a page of GenericResource values. +type ListResultPage struct { + fn func(ListResult) (ListResult, error) + lr ListResult +} + +// 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 *ListResultPage) Next() error { + next, err := page.fn(page.lr) + if err != nil { + return err + } + page.lr = next + return nil +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page ListResultPage) NotDone() bool { + return !page.lr.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page ListResultPage) Response() ListResult { + return page.lr +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page ListResultPage) Values() []GenericResource { + if page.lr.IsEmpty() { + return nil + } + return *page.lr.Value +} + +// ManagementErrorWithDetails ... +type ManagementErrorWithDetails struct { + // Code - The error code returned from the server. + Code *string `json:"code,omitempty"` + // Message - The error message returned from the server. + Message *string `json:"message,omitempty"` + // Target - The target of the error. + Target *string `json:"target,omitempty"` + // Details - Validation error. + Details *[]ManagementErrorWithDetails `json:"details,omitempty"` +} + +// MoveInfo parameters of move resources. +type MoveInfo struct { + // ResourcesProperty - The ids of the resources. + ResourcesProperty *[]string `json:"resources,omitempty"` + // TargetResourceGroup - The target resource group. + TargetResourceGroup *string `json:"targetResourceGroup,omitempty"` +} + +// MoveResourcesFuture an abstraction for monitoring and retrieving the results of a long-running operation. +type MoveResourcesFuture struct { + azure.Future +} + +// Result returns the result of the asynchronous operation. +// If the operation has not completed it will return an error. +func (future *MoveResourcesFuture) Result(client Client) (ar autorest.Response, err error) { + var done bool + done, err = future.Done(client) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.MoveResourcesFuture", "Result", future.Response(), "Polling failure") + return + } + if !done { + err = azure.NewAsyncOpIncompleteError("resources.MoveResourcesFuture") + return + } + ar.Response = future.Response() + return +} + +// ParametersLink entity representing the reference to the deployment paramaters. +type ParametersLink struct { + // URI - URI referencing the template. + URI *string `json:"uri,omitempty"` + // ContentVersion - If included it must match the ContentVersion in the template. + ContentVersion *string `json:"contentVersion,omitempty"` +} + +// Plan plan for the resource. +type Plan struct { + // Name - The plan ID. + Name *string `json:"name,omitempty"` + // Publisher - The publisher ID. + Publisher *string `json:"publisher,omitempty"` + // Product - The offer ID. + Product *string `json:"product,omitempty"` + // PromotionCode - The promotion code. + PromotionCode *string `json:"promotionCode,omitempty"` +} + +// Provider resource provider information. +type Provider struct { + autorest.Response `json:"-"` + // ID - The provider id. + ID *string `json:"id,omitempty"` + // Namespace - The namespace of the provider. + Namespace *string `json:"namespace,omitempty"` + // RegistrationState - The registration state of the provider. + RegistrationState *string `json:"registrationState,omitempty"` + // ResourceTypes - The collection of provider resource types. + ResourceTypes *[]ProviderResourceType `json:"resourceTypes,omitempty"` +} + +// ProviderListResult list of resource providers. +type ProviderListResult struct { + autorest.Response `json:"-"` + // Value - The list of resource providers. + Value *[]Provider `json:"value,omitempty"` + // NextLink - The URL to get the next set of results. + NextLink *string `json:"nextLink,omitempty"` +} + +// ProviderListResultIterator provides access to a complete listing of Provider values. +type ProviderListResultIterator struct { + i int + page ProviderListResultPage +} + +// 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 *ProviderListResultIterator) 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 ProviderListResultIterator) 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 ProviderListResultIterator) Response() ProviderListResult { + 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 ProviderListResultIterator) Value() Provider { + if !iter.page.NotDone() { + return Provider{} + } + return iter.page.Values()[iter.i] +} + +// IsEmpty returns true if the ListResult contains no values. +func (plr ProviderListResult) IsEmpty() bool { + return plr.Value == nil || len(*plr.Value) == 0 +} + +// providerListResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (plr ProviderListResult) providerListResultPreparer() (*http.Request, error) { + if plr.NextLink == nil || len(to.String(plr.NextLink)) < 1 { + return nil, nil + } + return autorest.Prepare(&http.Request{}, + autorest.AsJSON(), + autorest.AsGet(), + autorest.WithBaseURL(to.String(plr.NextLink))) +} + +// ProviderListResultPage contains a page of Provider values. +type ProviderListResultPage struct { + fn func(ProviderListResult) (ProviderListResult, error) + plr ProviderListResult +} + +// 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 *ProviderListResultPage) Next() error { + next, err := page.fn(page.plr) + if err != nil { + return err + } + page.plr = next + return nil +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page ProviderListResultPage) NotDone() bool { + return !page.plr.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page ProviderListResultPage) Response() ProviderListResult { + return page.plr +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page ProviderListResultPage) Values() []Provider { + if page.plr.IsEmpty() { + return nil + } + return *page.plr.Value +} + +// ProviderOperationDisplayProperties resource provider operation's display properties. +type ProviderOperationDisplayProperties struct { + // Publisher - Operation description. + Publisher *string `json:"publisher,omitempty"` + // Provider - Operation provider. + Provider *string `json:"provider,omitempty"` + // Resource - Operation resource. + Resource *string `json:"resource,omitempty"` + // Operation - Operation. + Operation *string `json:"operation,omitempty"` + // Description - Operation description. + Description *string `json:"description,omitempty"` +} + +// ProviderResourceType resource type managed by the resource provider. +type ProviderResourceType struct { + // ResourceType - The resource type. + ResourceType *string `json:"resourceType,omitempty"` + // Locations - The collection of locations where this resource type can be created in. + Locations *[]string `json:"locations,omitempty"` + // Aliases - The aliases that are supported by this resource type. + Aliases *[]AliasType `json:"aliases,omitempty"` + // APIVersions - The api version. + APIVersions *[]string `json:"apiVersions,omitempty"` + // Properties - The properties. + Properties map[string]*string `json:"properties"` +} + +// MarshalJSON is the custom marshaler for ProviderResourceType. +func (prt ProviderResourceType) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]interface{}) + if prt.ResourceType != nil { + objectMap["resourceType"] = prt.ResourceType + } + if prt.Locations != nil { + objectMap["locations"] = prt.Locations + } + if prt.Aliases != nil { + objectMap["aliases"] = prt.Aliases + } + if prt.APIVersions != nil { + objectMap["apiVersions"] = prt.APIVersions + } + if prt.Properties != nil { + objectMap["properties"] = prt.Properties + } + return json.Marshal(objectMap) +} + +// 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) +} + +// Sku sku for the resource. +type Sku struct { + // Name - The sku name. + Name *string `json:"name,omitempty"` + // Tier - The sku tier. + Tier *string `json:"tier,omitempty"` + // Size - The sku size. + Size *string `json:"size,omitempty"` + // Family - The sku family. + Family *string `json:"family,omitempty"` + // Model - The sku model. + Model *string `json:"model,omitempty"` + // Capacity - The sku capacity. + Capacity *int32 `json:"capacity,omitempty"` +} + +// SubResource ... +type SubResource struct { + // ID - Resource Id + ID *string `json:"id,omitempty"` +} + +// TagCount tag count. +type TagCount struct { + // Type - Type of count. + Type *string `json:"type,omitempty"` + // Value - Value of count. + Value *string `json:"value,omitempty"` +} + +// TagDetails tag details. +type TagDetails struct { + autorest.Response `json:"-"` + // ID - The tag ID. + ID *string `json:"id,omitempty"` + // TagName - The tag name. + TagName *string `json:"tagName,omitempty"` + // Count - The tag count. + Count *TagCount `json:"count,omitempty"` + // Values - The list of tag values. + Values *[]TagValue `json:"values,omitempty"` +} + +// TagsListResult list of subscription tags. +type TagsListResult struct { + autorest.Response `json:"-"` + // Value - The list of tags. + Value *[]TagDetails `json:"value,omitempty"` + // NextLink - The URL to get the next set of results. + NextLink *string `json:"nextLink,omitempty"` +} + +// TagsListResultIterator provides access to a complete listing of TagDetails values. +type TagsListResultIterator struct { + i int + page TagsListResultPage +} + +// 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 *TagsListResultIterator) 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 TagsListResultIterator) 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 TagsListResultIterator) Response() TagsListResult { + 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 TagsListResultIterator) Value() TagDetails { + if !iter.page.NotDone() { + return TagDetails{} + } + return iter.page.Values()[iter.i] +} + +// IsEmpty returns true if the ListResult contains no values. +func (tlr TagsListResult) IsEmpty() bool { + return tlr.Value == nil || len(*tlr.Value) == 0 +} + +// tagsListResultPreparer prepares a request to retrieve the next set of results. +// It returns nil if no more results exist. +func (tlr TagsListResult) tagsListResultPreparer() (*http.Request, error) { + if tlr.NextLink == nil || len(to.String(tlr.NextLink)) < 1 { + return nil, nil + } + return autorest.Prepare(&http.Request{}, + autorest.AsJSON(), + autorest.AsGet(), + autorest.WithBaseURL(to.String(tlr.NextLink))) +} + +// TagsListResultPage contains a page of TagDetails values. +type TagsListResultPage struct { + fn func(TagsListResult) (TagsListResult, error) + tlr TagsListResult +} + +// 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 *TagsListResultPage) Next() error { + next, err := page.fn(page.tlr) + if err != nil { + return err + } + page.tlr = next + return nil +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page TagsListResultPage) NotDone() bool { + return !page.tlr.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page TagsListResultPage) Response() TagsListResult { + return page.tlr +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page TagsListResultPage) Values() []TagDetails { + if page.tlr.IsEmpty() { + return nil + } + return *page.tlr.Value +} + +// TagValue tag information. +type TagValue struct { + autorest.Response `json:"-"` + // ID - The tag ID. + ID *string `json:"id,omitempty"` + // TagValue - The tag value. + TagValue *string `json:"tagValue,omitempty"` + // Count - The tag value count. + Count *TagCount `json:"count,omitempty"` +} + +// TargetResource target resource. +type TargetResource struct { + // ID - The ID of the resource. + ID *string `json:"id,omitempty"` + // ResourceName - The name of the resource. + ResourceName *string `json:"resourceName,omitempty"` + // ResourceType - The type of the resource. + ResourceType *string `json:"resourceType,omitempty"` +} + +// TemplateLink entity representing the reference to the template. +type TemplateLink struct { + // URI - URI referencing the template. + URI *string `json:"uri,omitempty"` + // ContentVersion - If included it must match the ContentVersion in the template. + ContentVersion *string `json:"contentVersion,omitempty"` +} + +// UpdateFuture an abstraction for monitoring and retrieving the results of a long-running operation. +type UpdateFuture struct { + azure.Future +} + +// Result returns the result of the asynchronous operation. +// If the operation has not completed it will return an error. +func (future *UpdateFuture) Result(client Client) (gr GenericResource, err error) { + var done bool + done, err = future.Done(client) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.UpdateFuture", "Result", future.Response(), "Polling failure") + return + } + if !done { + err = azure.NewAsyncOpIncompleteError("resources.UpdateFuture") + return + } + sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) + if gr.Response.Response, err = future.GetResult(sender); err == nil && gr.Response.Response.StatusCode != http.StatusNoContent { + gr, err = client.UpdateResponder(gr.Response.Response) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.UpdateFuture", "Result", gr.Response.Response, "Failure responding to request") + } + } + return +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/providers.go b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/providers.go similarity index 70% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/providers.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/providers.go index 7fd6dc158..4993b1f43 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/providers.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/providers.go @@ -14,20 +14,19 @@ package resources // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. import ( + "context" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" "net/http" ) -// ProvidersClient is the provides operations for working with resources and -// resource groups. +// ProvidersClient is the client for the Providers methods of the Resources service. type ProvidersClient struct { - ManagementClient + BaseClient } // NewProvidersClient creates an instance of the ProvidersClient client. @@ -35,19 +34,18 @@ func NewProvidersClient(subscriptionID string) ProvidersClient { return NewProvidersClientWithBaseURI(DefaultBaseURI, subscriptionID) } -// NewProvidersClientWithBaseURI creates an instance of the ProvidersClient -// client. +// NewProvidersClientWithBaseURI creates an instance of the ProvidersClient client. func NewProvidersClientWithBaseURI(baseURI string, subscriptionID string) ProvidersClient { return ProvidersClient{NewWithBaseURI(baseURI, subscriptionID)} } -// Get gets the specified resource provider. -// -// resourceProviderNamespace is the namespace of the resource provider. expand -// is the $expand query parameter. For example, to include property aliases in -// response, use $expand=resourceTypes/aliases. -func (client ProvidersClient) Get(resourceProviderNamespace string, expand string) (result Provider, err error) { - req, err := client.GetPreparer(resourceProviderNamespace, expand) +// Get gets a resource provider. +// Parameters: +// resourceProviderNamespace - namespace of the resource provider. +// expand - the $expand query parameter. e.g. To include property aliases in response, use +// $expand=resourceTypes/aliases. +func (client ProvidersClient) Get(ctx context.Context, resourceProviderNamespace string, expand string) (result Provider, err error) { + req, err := client.GetPreparer(ctx, resourceProviderNamespace, expand) if err != nil { err = autorest.NewErrorWithError(err, "resources.ProvidersClient", "Get", nil, "Failure preparing request") return @@ -69,13 +67,13 @@ func (client ProvidersClient) Get(resourceProviderNamespace string, expand strin } // GetPreparer prepares the Get request. -func (client ProvidersClient) GetPreparer(resourceProviderNamespace string, expand string) (*http.Request, error) { +func (client ProvidersClient) GetPreparer(ctx context.Context, resourceProviderNamespace string, expand string) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -88,13 +86,14 @@ func (client ProvidersClient) GetPreparer(resourceProviderNamespace string, expa autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}", 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 ProvidersClient) 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 @@ -110,15 +109,14 @@ func (client ProvidersClient) GetResponder(resp *http.Response) (result Provider return } -// List gets all resource providers for a subscription. -// -// top is the number of results to return. If null is passed returns all -// deployments. expand is the properties to include in the results. For -// example, use &$expand=metadata in the query string to retrieve resource -// provider metadata. To include property aliases in response, use +// List gets a list of resource providers. +// Parameters: +// top - query parameters. If null is passed returns all deployments. +// expand - the $expand query parameter. e.g. To include property aliases in response, use // $expand=resourceTypes/aliases. -func (client ProvidersClient) List(top *int32, expand string) (result ProviderListResult, err error) { - req, err := client.ListPreparer(top, expand) +func (client ProvidersClient) List(ctx context.Context, top *int32, expand string) (result ProviderListResultPage, err error) { + result.fn = client.listNextResults + req, err := client.ListPreparer(ctx, top, expand) if err != nil { err = autorest.NewErrorWithError(err, "resources.ProvidersClient", "List", nil, "Failure preparing request") return @@ -126,12 +124,12 @@ func (client ProvidersClient) List(top *int32, expand string) (result ProviderLi resp, err := client.ListSender(req) if err != nil { - result.Response = autorest.Response{Response: resp} + result.plr.Response = autorest.Response{Response: resp} err = autorest.NewErrorWithError(err, "resources.ProvidersClient", "List", resp, "Failure sending request") return } - result, err = client.ListResponder(resp) + result.plr, err = client.ListResponder(resp) if err != nil { err = autorest.NewErrorWithError(err, "resources.ProvidersClient", "List", resp, "Failure responding to request") } @@ -140,12 +138,12 @@ func (client ProvidersClient) List(top *int32, expand string) (result ProviderLi } // ListPreparer prepares the List request. -func (client ProvidersClient) ListPreparer(top *int32, expand string) (*http.Request, error) { +func (client ProvidersClient) ListPreparer(ctx context.Context, top *int32, expand string) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -161,13 +159,14 @@ func (client ProvidersClient) ListPreparer(top *int32, expand string) (*http.Req autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers", 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 ProvidersClient) 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 @@ -183,36 +182,38 @@ func (client ProvidersClient) ListResponder(resp *http.Response) (result Provide return } -// ListNextResults retrieves the next set of results, if any. -func (client ProvidersClient) ListNextResults(lastResults ProviderListResult) (result ProviderListResult, err error) { - req, err := lastResults.ProviderListResultPreparer() +// listNextResults retrieves the next set of results, if any. +func (client ProvidersClient) listNextResults(lastResults ProviderListResult) (result ProviderListResult, err error) { + req, err := lastResults.providerListResultPreparer() if err != nil { - return result, autorest.NewErrorWithError(err, "resources.ProvidersClient", "List", nil, "Failure preparing next results request") + return result, autorest.NewErrorWithError(err, "resources.ProvidersClient", "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, "resources.ProvidersClient", "List", resp, "Failure sending next results request") + return result, autorest.NewErrorWithError(err, "resources.ProvidersClient", "listNextResults", resp, "Failure sending next results request") } - result, err = client.ListResponder(resp) if err != nil { - err = autorest.NewErrorWithError(err, "resources.ProvidersClient", "List", resp, "Failure responding to next results request") + err = autorest.NewErrorWithError(err, "resources.ProvidersClient", "listNextResults", resp, "Failure responding to next results request") } - return } -// Register registers a subscription with a resource provider. -// -// resourceProviderNamespace is the namespace of the resource provider to -// register. -func (client ProvidersClient) Register(resourceProviderNamespace string) (result Provider, err error) { - req, err := client.RegisterPreparer(resourceProviderNamespace) +// ListComplete enumerates all values, automatically crossing page boundaries as required. +func (client ProvidersClient) ListComplete(ctx context.Context, top *int32, expand string) (result ProviderListResultIterator, err error) { + result.page, err = client.List(ctx, top, expand) + return +} + +// Register registers provider to be used with a subscription. +// Parameters: +// resourceProviderNamespace - namespace of the resource provider. +func (client ProvidersClient) Register(ctx context.Context, resourceProviderNamespace string) (result Provider, err error) { + req, err := client.RegisterPreparer(ctx, resourceProviderNamespace) if err != nil { err = autorest.NewErrorWithError(err, "resources.ProvidersClient", "Register", nil, "Failure preparing request") return @@ -234,13 +235,13 @@ func (client ProvidersClient) Register(resourceProviderNamespace string) (result } // RegisterPreparer prepares the Register request. -func (client ProvidersClient) RegisterPreparer(resourceProviderNamespace string) (*http.Request, error) { +func (client ProvidersClient) RegisterPreparer(ctx context.Context, resourceProviderNamespace string) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -250,13 +251,14 @@ func (client ProvidersClient) RegisterPreparer(resourceProviderNamespace string) autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}/register", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // RegisterSender sends the Register request. The method will close the // http.Response Body if it receives an error. func (client ProvidersClient) RegisterSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // RegisterResponder handles the response to the Register request. The method always @@ -272,12 +274,11 @@ func (client ProvidersClient) RegisterResponder(resp *http.Response) (result Pro return } -// Unregister unregisters a subscription from a resource provider. -// -// resourceProviderNamespace is the namespace of the resource provider to -// unregister. -func (client ProvidersClient) Unregister(resourceProviderNamespace string) (result Provider, err error) { - req, err := client.UnregisterPreparer(resourceProviderNamespace) +// Unregister unregisters provider from a subscription. +// Parameters: +// resourceProviderNamespace - namespace of the resource provider. +func (client ProvidersClient) Unregister(ctx context.Context, resourceProviderNamespace string) (result Provider, err error) { + req, err := client.UnregisterPreparer(ctx, resourceProviderNamespace) if err != nil { err = autorest.NewErrorWithError(err, "resources.ProvidersClient", "Unregister", nil, "Failure preparing request") return @@ -299,13 +300,13 @@ func (client ProvidersClient) Unregister(resourceProviderNamespace string) (resu } // UnregisterPreparer prepares the Unregister request. -func (client ProvidersClient) UnregisterPreparer(resourceProviderNamespace string) (*http.Request, error) { +func (client ProvidersClient) UnregisterPreparer(ctx context.Context, resourceProviderNamespace string) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -315,13 +316,14 @@ func (client ProvidersClient) UnregisterPreparer(resourceProviderNamespace strin autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/{resourceProviderNamespace}/unregister", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // UnregisterSender sends the Unregister request. The method will close the // http.Response Body if it receives an error. func (client ProvidersClient) UnregisterSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // UnregisterResponder handles the response to the Unregister request. The method always diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/resources.go b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/resources.go new file mode 100644 index 000000000..301b9934e --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/resources.go @@ -0,0 +1,629 @@ +package resources + +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +import ( + "context" + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "net/http" +) + +// Client is the client for the Resources methods of the Resources service. +type Client struct { + BaseClient +} + +// NewClient creates an instance of the Client client. +func NewClient(subscriptionID string) Client { + return NewClientWithBaseURI(DefaultBaseURI, subscriptionID) +} + +// NewClientWithBaseURI creates an instance of the Client client. +func NewClientWithBaseURI(baseURI string, subscriptionID string) Client { + return Client{NewWithBaseURI(baseURI, subscriptionID)} +} + +// CheckExistence checks whether resource exists. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// resourceProviderNamespace - resource identity. +// parentResourcePath - resource identity. +// resourceType - resource identity. +// resourceName - resource identity. +func (client Client) CheckExistence(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (result autorest.Response, err error) { + if err := validation.Validate([]validation.Validation{ + {TargetValue: resourceGroupName, + Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, + {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.Client", "CheckExistence", err.Error()) + } + + req, err := client.CheckExistencePreparer(ctx, resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "CheckExistence", nil, "Failure preparing request") + return + } + + resp, err := client.CheckExistenceSender(req) + if err != nil { + result.Response = resp + err = autorest.NewErrorWithError(err, "resources.Client", "CheckExistence", resp, "Failure sending request") + return + } + + result, err = client.CheckExistenceResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "CheckExistence", resp, "Failure responding to request") + } + + return +} + +// CheckExistencePreparer prepares the CheckExistence request. +func (client Client) CheckExistencePreparer(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "parentResourcePath": parentResourcePath, + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "resourceName": autorest.Encode("path", resourceName), + "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), + "resourceType": resourceType, + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2016-02-01" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsHead(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}", pathParameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// CheckExistenceSender sends the CheckExistence request. The method will close the +// http.Response Body if it receives an error. +func (client Client) CheckExistenceSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// CheckExistenceResponder handles the response to the CheckExistence request. The method always +// closes the http.Response Body. +func (client Client) CheckExistenceResponder(resp *http.Response) (result autorest.Response, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusNoContent, http.StatusNotFound), + autorest.ByClosing()) + result.Response = resp + return +} + +// CreateOrUpdate create a resource. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// resourceProviderNamespace - resource identity. +// parentResourcePath - resource identity. +// resourceType - resource identity. +// resourceName - resource identity. +// parameters - create or update resource parameters. +func (client Client) CreateOrUpdate(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string, parameters GenericResource) (result GenericResource, err error) { + if err := validation.Validate([]validation.Validation{ + {TargetValue: resourceGroupName, + Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, + {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.Client", "CreateOrUpdate", err.Error()) + } + + req, err := client.CreateOrUpdatePreparer(ctx, resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName, parameters) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "CreateOrUpdate", nil, "Failure preparing request") + return + } + + resp, err := client.CreateOrUpdateSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "resources.Client", "CreateOrUpdate", resp, "Failure sending request") + return + } + + result, err = client.CreateOrUpdateResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "CreateOrUpdate", resp, "Failure responding to request") + } + + return +} + +// CreateOrUpdatePreparer prepares the CreateOrUpdate request. +func (client Client) CreateOrUpdatePreparer(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string, parameters GenericResource) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "parentResourcePath": parentResourcePath, + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "resourceName": autorest.Encode("path", resourceName), + "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), + "resourceType": resourceType, + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2016-02-01" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/json; charset=utf-8"), + autorest.AsPut(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}", pathParameters), + autorest.WithJSON(parameters), + autorest.WithQueryParameters(queryParameters)) + 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 Client) CreateOrUpdateSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// CreateOrUpdateResponder handles the response to the CreateOrUpdate request. The method always +// closes the http.Response Body. +func (client Client) CreateOrUpdateResponder(resp *http.Response) (result GenericResource, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} + +// Delete delete resource and all of its resources. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// resourceProviderNamespace - resource identity. +// parentResourcePath - resource identity. +// resourceType - resource identity. +// resourceName - resource identity. +func (client Client) Delete(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (result autorest.Response, err error) { + if err := validation.Validate([]validation.Validation{ + {TargetValue: resourceGroupName, + Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, + {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.Client", "Delete", err.Error()) + } + + req, err := client.DeletePreparer(ctx, resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "Delete", nil, "Failure preparing request") + return + } + + resp, err := client.DeleteSender(req) + if err != nil { + result.Response = resp + err = autorest.NewErrorWithError(err, "resources.Client", "Delete", resp, "Failure sending request") + return + } + + result, err = client.DeleteResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "Delete", resp, "Failure responding to request") + } + + return +} + +// DeletePreparer prepares the Delete request. +func (client Client) DeletePreparer(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "parentResourcePath": parentResourcePath, + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "resourceName": autorest.Encode("path", resourceName), + "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), + "resourceType": resourceType, + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2016-02-01" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsDelete(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}", pathParameters), + autorest.WithQueryParameters(queryParameters)) + 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 Client) DeleteSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// DeleteResponder handles the response to the Delete request. The method always +// closes the http.Response Body. +func (client Client) DeleteResponder(resp *http.Response) (result autorest.Response, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent), + autorest.ByClosing()) + result.Response = resp + return +} + +// Get returns a resource belonging to a resource group. +// Parameters: +// resourceGroupName - the name of the resource group. The name is case insensitive. +// resourceProviderNamespace - resource identity. +// parentResourcePath - resource identity. +// resourceType - resource identity. +// resourceName - resource identity. +func (client Client) Get(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (result GenericResource, err error) { + if err := validation.Validate([]validation.Validation{ + {TargetValue: resourceGroupName, + Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, + {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.Client", "Get", err.Error()) + } + + req, err := client.GetPreparer(ctx, resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "Get", nil, "Failure preparing request") + return + } + + resp, err := client.GetSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "resources.Client", "Get", resp, "Failure sending request") + return + } + + result, err = client.GetResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "Get", resp, "Failure responding to request") + } + + return +} + +// GetPreparer prepares the Get request. +func (client Client) GetPreparer(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "parentResourcePath": parentResourcePath, + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "resourceName": autorest.Encode("path", resourceName), + "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), + "resourceType": resourceType, + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2016-02-01" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsGet(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}", pathParameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// GetSender sends the Get request. The method will close the +// http.Response Body if it receives an error. +func (client Client) GetSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// GetResponder handles the response to the Get request. The method always +// closes the http.Response Body. +func (client Client) GetResponder(resp *http.Response) (result GenericResource, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} + +// List get all of the resources under a subscription. +// Parameters: +// filter - the filter to apply on the operation. +// expand - the $expand query parameter. +// top - query parameters. If null is passed returns all resource groups. +func (client Client) List(ctx context.Context, filter string, expand string, top *int32) (result ListResultPage, err error) { + result.fn = client.listNextResults + req, err := client.ListPreparer(ctx, filter, expand, top) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "List", nil, "Failure preparing request") + return + } + + resp, err := client.ListSender(req) + if err != nil { + result.lr.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "resources.Client", "List", resp, "Failure sending request") + return + } + + result.lr, err = client.ListResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "List", resp, "Failure responding to request") + } + + return +} + +// ListPreparer prepares the List request. +func (client Client) ListPreparer(ctx context.Context, filter string, expand string, top *int32) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2016-02-01" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + if len(filter) > 0 { + queryParameters["$filter"] = autorest.Encode("query", filter) + } + if len(expand) > 0 { + queryParameters["$expand"] = autorest.Encode("query", expand) + } + if top != nil { + queryParameters["$top"] = autorest.Encode("query", *top) + } + + preparer := autorest.CreatePreparer( + autorest.AsGet(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resources", pathParameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// ListSender sends the List request. The method will close the +// http.Response Body if it receives an error. +func (client Client) ListSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// ListResponder handles the response to the List request. The method always +// closes the http.Response Body. +func (client Client) ListResponder(resp *http.Response) (result ListResult, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} + +// listNextResults retrieves the next set of results, if any. +func (client Client) listNextResults(lastResults ListResult) (result ListResult, err error) { + req, err := lastResults.listResultPreparer() + if err != nil { + return result, autorest.NewErrorWithError(err, "resources.Client", "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, "resources.Client", "listNextResults", resp, "Failure sending next results request") + } + result, err = client.ListResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "listNextResults", resp, "Failure responding to next results request") + } + return +} + +// ListComplete enumerates all values, automatically crossing page boundaries as required. +func (client Client) ListComplete(ctx context.Context, filter string, expand string, top *int32) (result ListResultIterator, err error) { + result.page, err = client.List(ctx, filter, expand, top) + return +} + +// MoveResources move resources from one resource group to another. The resources being moved should all be in the same +// resource group. +// Parameters: +// sourceResourceGroupName - source resource group name. +// parameters - move resources' parameters. +func (client Client) MoveResources(ctx context.Context, sourceResourceGroupName string, parameters MoveInfo) (result MoveResourcesFuture, err error) { + if err := validation.Validate([]validation.Validation{ + {TargetValue: sourceResourceGroupName, + Constraints: []validation.Constraint{{Target: "sourceResourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, + {Target: "sourceResourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, + {Target: "sourceResourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.Client", "MoveResources", err.Error()) + } + + req, err := client.MoveResourcesPreparer(ctx, sourceResourceGroupName, parameters) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "MoveResources", nil, "Failure preparing request") + return + } + + result, err = client.MoveResourcesSender(req) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "MoveResources", result.Response(), "Failure sending request") + return + } + + return +} + +// MoveResourcesPreparer prepares the MoveResources request. +func (client Client) MoveResourcesPreparer(ctx context.Context, sourceResourceGroupName string, parameters MoveInfo) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "sourceResourceGroupName": autorest.Encode("path", sourceResourceGroupName), + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2016-02-01" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/json; charset=utf-8"), + autorest.AsPost(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{sourceResourceGroupName}/moveResources", pathParameters), + autorest.WithJSON(parameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// MoveResourcesSender sends the MoveResources request. The method will close the +// http.Response Body if it receives an error. +func (client Client) MoveResourcesSender(req *http.Request) (future MoveResourcesFuture, err error) { + var resp *http.Response + resp, err = autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) + if err != nil { + return + } + future.Future, err = azure.NewFutureFromResponse(resp) + return +} + +// MoveResourcesResponder handles the response to the MoveResources request. The method always +// closes the http.Response Body. +func (client Client) MoveResourcesResponder(resp *http.Response) (result autorest.Response, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted, http.StatusNoContent), + autorest.ByClosing()) + result.Response = resp + return +} + +// Update updates a resource. +// Parameters: +// resourceGroupName - the name of the resource group for the resource. The name is case insensitive. +// resourceProviderNamespace - the namespace of the resource provider. +// parentResourcePath - the parent resource identity. +// resourceType - the resource type of the resource to update. +// resourceName - the name of the resource to update. +// parameters - parameters for updating the resource. +func (client Client) Update(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string, parameters GenericResource) (result UpdateFuture, err error) { + if err := validation.Validate([]validation.Validation{ + {TargetValue: resourceGroupName, + Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, + {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, + {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { + return result, validation.NewError("resources.Client", "Update", err.Error()) + } + + req, err := client.UpdatePreparer(ctx, resourceGroupName, resourceProviderNamespace, parentResourcePath, resourceType, resourceName, parameters) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "Update", nil, "Failure preparing request") + return + } + + result, err = client.UpdateSender(req) + if err != nil { + err = autorest.NewErrorWithError(err, "resources.Client", "Update", result.Response(), "Failure sending request") + return + } + + return +} + +// UpdatePreparer prepares the Update request. +func (client Client) UpdatePreparer(ctx context.Context, resourceGroupName string, resourceProviderNamespace string, parentResourcePath string, resourceType string, resourceName string, parameters GenericResource) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "parentResourcePath": parentResourcePath, + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "resourceName": autorest.Encode("path", resourceName), + "resourceProviderNamespace": autorest.Encode("path", resourceProviderNamespace), + "resourceType": resourceType, + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2016-02-01" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/json; charset=utf-8"), + autorest.AsPatch(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}", pathParameters), + autorest.WithJSON(parameters), + autorest.WithQueryParameters(queryParameters)) + 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 Client) UpdateSender(req *http.Request) (future UpdateFuture, err error) { + var resp *http.Response + resp, err = autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) + if err != nil { + return + } + future.Future, err = azure.NewFutureFromResponse(resp) + return +} + +// UpdateResponder handles the response to the Update request. The method always +// closes the http.Response Body. +func (client Client) UpdateResponder(resp *http.Response) (result GenericResource, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/tags.go b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/tags.go similarity index 73% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/tags.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/tags.go index 445fccf62..c38a38188 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/tags.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/tags.go @@ -14,20 +14,19 @@ package resources // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. import ( + "context" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" "net/http" ) -// TagsClient is the provides operations for working with resources and -// resource groups. +// TagsClient is the client for the Tags methods of the Resources service. type TagsClient struct { - ManagementClient + BaseClient } // NewTagsClient creates an instance of the TagsClient client. @@ -40,13 +39,11 @@ func NewTagsClientWithBaseURI(baseURI string, subscriptionID string) TagsClient return TagsClient{NewWithBaseURI(baseURI, subscriptionID)} } -// CreateOrUpdate the tag name can have a maximum of 512 characters and is case -// insensitive. Tag names created by Azure have prefixes of microsoft, azure, -// or windows. You cannot create tags with one of these prefixes. -// -// tagName is the name of the tag to create. -func (client TagsClient) CreateOrUpdate(tagName string) (result TagDetails, err error) { - req, err := client.CreateOrUpdatePreparer(tagName) +// CreateOrUpdate create a subscription resource tag. +// Parameters: +// tagName - the name of the tag. +func (client TagsClient) CreateOrUpdate(ctx context.Context, tagName string) (result TagDetails, err error) { + req, err := client.CreateOrUpdatePreparer(ctx, tagName) if err != nil { err = autorest.NewErrorWithError(err, "resources.TagsClient", "CreateOrUpdate", nil, "Failure preparing request") return @@ -68,13 +65,13 @@ func (client TagsClient) CreateOrUpdate(tagName string) (result TagDetails, err } // CreateOrUpdatePreparer prepares the CreateOrUpdate request. -func (client TagsClient) CreateOrUpdatePreparer(tagName string) (*http.Request, error) { +func (client TagsClient) CreateOrUpdatePreparer(ctx context.Context, tagName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), "tagName": autorest.Encode("path", tagName), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -84,13 +81,14 @@ func (client TagsClient) CreateOrUpdatePreparer(tagName string) (*http.Request, autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/tagNames/{tagName}", pathParameters), autorest.WithQueryParameters(queryParameters)) - 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 TagsClient) 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 @@ -106,12 +104,12 @@ func (client TagsClient) CreateOrUpdateResponder(resp *http.Response) (result Ta return } -// CreateOrUpdateValue creates a tag value. The name of the tag must already -// exist. -// -// tagName is the name of the tag. tagValue is the value of the tag to create. -func (client TagsClient) CreateOrUpdateValue(tagName string, tagValue string) (result TagValue, err error) { - req, err := client.CreateOrUpdateValuePreparer(tagName, tagValue) +// CreateOrUpdateValue create a subscription resource tag value. +// Parameters: +// tagName - the name of the tag. +// tagValue - the value of the tag. +func (client TagsClient) CreateOrUpdateValue(ctx context.Context, tagName string, tagValue string) (result TagValue, err error) { + req, err := client.CreateOrUpdateValuePreparer(ctx, tagName, tagValue) if err != nil { err = autorest.NewErrorWithError(err, "resources.TagsClient", "CreateOrUpdateValue", nil, "Failure preparing request") return @@ -133,14 +131,14 @@ func (client TagsClient) CreateOrUpdateValue(tagName string, tagValue string) (r } // CreateOrUpdateValuePreparer prepares the CreateOrUpdateValue request. -func (client TagsClient) CreateOrUpdateValuePreparer(tagName string, tagValue string) (*http.Request, error) { +func (client TagsClient) CreateOrUpdateValuePreparer(ctx context.Context, tagName string, tagValue string) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), "tagName": autorest.Encode("path", tagName), "tagValue": autorest.Encode("path", tagValue), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -150,13 +148,14 @@ func (client TagsClient) CreateOrUpdateValuePreparer(tagName string, tagValue st autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/tagNames/{tagName}/tagValues/{tagValue}", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // CreateOrUpdateValueSender sends the CreateOrUpdateValue request. The method will close the // http.Response Body if it receives an error. func (client TagsClient) CreateOrUpdateValueSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // CreateOrUpdateValueResponder handles the response to the CreateOrUpdateValue request. The method always @@ -172,12 +171,11 @@ func (client TagsClient) CreateOrUpdateValueResponder(resp *http.Response) (resu return } -// Delete you must remove all values from a resource tag before you can delete -// it. -// -// tagName is the name of the tag. -func (client TagsClient) Delete(tagName string) (result autorest.Response, err error) { - req, err := client.DeletePreparer(tagName) +// Delete delete a subscription resource tag. +// Parameters: +// tagName - the name of the tag. +func (client TagsClient) Delete(ctx context.Context, tagName string) (result autorest.Response, err error) { + req, err := client.DeletePreparer(ctx, tagName) if err != nil { err = autorest.NewErrorWithError(err, "resources.TagsClient", "Delete", nil, "Failure preparing request") return @@ -199,13 +197,13 @@ func (client TagsClient) Delete(tagName string) (result autorest.Response, err e } // DeletePreparer prepares the Delete request. -func (client TagsClient) DeletePreparer(tagName string) (*http.Request, error) { +func (client TagsClient) DeletePreparer(ctx context.Context, tagName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), "tagName": autorest.Encode("path", tagName), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -215,13 +213,14 @@ func (client TagsClient) DeletePreparer(tagName string) (*http.Request, error) { autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/tagNames/{tagName}", pathParameters), autorest.WithQueryParameters(queryParameters)) - 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 TagsClient) 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 @@ -236,11 +235,12 @@ func (client TagsClient) DeleteResponder(resp *http.Response) (result autorest.R return } -// DeleteValue deletes a tag value. -// -// tagName is the name of the tag. tagValue is the value of the tag to delete. -func (client TagsClient) DeleteValue(tagName string, tagValue string) (result autorest.Response, err error) { - req, err := client.DeleteValuePreparer(tagName, tagValue) +// DeleteValue delete a subscription resource tag value. +// Parameters: +// tagName - the name of the tag. +// tagValue - the value of the tag. +func (client TagsClient) DeleteValue(ctx context.Context, tagName string, tagValue string) (result autorest.Response, err error) { + req, err := client.DeleteValuePreparer(ctx, tagName, tagValue) if err != nil { err = autorest.NewErrorWithError(err, "resources.TagsClient", "DeleteValue", nil, "Failure preparing request") return @@ -262,14 +262,14 @@ func (client TagsClient) DeleteValue(tagName string, tagValue string) (result au } // DeleteValuePreparer prepares the DeleteValue request. -func (client TagsClient) DeleteValuePreparer(tagName string, tagValue string) (*http.Request, error) { +func (client TagsClient) DeleteValuePreparer(ctx context.Context, tagName string, tagValue string) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), "tagName": autorest.Encode("path", tagName), "tagValue": autorest.Encode("path", tagValue), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -279,13 +279,14 @@ func (client TagsClient) DeleteValuePreparer(tagName string, tagValue string) (* autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/tagNames/{tagName}/tagValues/{tagValue}", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // DeleteValueSender sends the DeleteValue request. The method will close the // http.Response Body if it receives an error. func (client TagsClient) DeleteValueSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // DeleteValueResponder handles the response to the DeleteValue request. The method always @@ -300,10 +301,10 @@ func (client TagsClient) DeleteValueResponder(resp *http.Response) (result autor return } -// List gets the names and values of all resource tags that are defined in a -// subscription. -func (client TagsClient) List() (result TagsListResult, err error) { - req, err := client.ListPreparer() +// List get a list of subscription resource tags. +func (client TagsClient) List(ctx context.Context) (result TagsListResultPage, err error) { + result.fn = client.listNextResults + req, err := client.ListPreparer(ctx) if err != nil { err = autorest.NewErrorWithError(err, "resources.TagsClient", "List", nil, "Failure preparing request") return @@ -311,12 +312,12 @@ func (client TagsClient) List() (result TagsListResult, err error) { resp, err := client.ListSender(req) if err != nil { - result.Response = autorest.Response{Response: resp} + result.tlr.Response = autorest.Response{Response: resp} err = autorest.NewErrorWithError(err, "resources.TagsClient", "List", resp, "Failure sending request") return } - result, err = client.ListResponder(resp) + result.tlr, err = client.ListResponder(resp) if err != nil { err = autorest.NewErrorWithError(err, "resources.TagsClient", "List", resp, "Failure responding to request") } @@ -325,12 +326,12 @@ func (client TagsClient) List() (result TagsListResult, err error) { } // ListPreparer prepares the List request. -func (client TagsClient) ListPreparer() (*http.Request, error) { +func (client TagsClient) ListPreparer(ctx context.Context) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-09-01" + const APIVersion = "2016-02-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -340,13 +341,14 @@ func (client TagsClient) ListPreparer() (*http.Request, error) { autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/tagNames", 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 TagsClient) 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 @@ -362,26 +364,29 @@ func (client TagsClient) ListResponder(resp *http.Response) (result TagsListResu return } -// ListNextResults retrieves the next set of results, if any. -func (client TagsClient) ListNextResults(lastResults TagsListResult) (result TagsListResult, err error) { - req, err := lastResults.TagsListResultPreparer() +// listNextResults retrieves the next set of results, if any. +func (client TagsClient) listNextResults(lastResults TagsListResult) (result TagsListResult, err error) { + req, err := lastResults.tagsListResultPreparer() if err != nil { - return result, autorest.NewErrorWithError(err, "resources.TagsClient", "List", nil, "Failure preparing next results request") + return result, autorest.NewErrorWithError(err, "resources.TagsClient", "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, "resources.TagsClient", "List", resp, "Failure sending next results request") + return result, autorest.NewErrorWithError(err, "resources.TagsClient", "listNextResults", resp, "Failure sending next results request") } - result, err = client.ListResponder(resp) if err != nil { - err = autorest.NewErrorWithError(err, "resources.TagsClient", "List", resp, "Failure responding to next results request") + err = autorest.NewErrorWithError(err, "resources.TagsClient", "listNextResults", resp, "Failure responding to next results request") } - + return +} + +// ListComplete enumerates all values, automatically crossing page boundaries as required. +func (client TagsClient) ListComplete(ctx context.Context) (result TagsListResultIterator, err error) { + result.page, err = client.List(ctx) return } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/version.go b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/version.go similarity index 82% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/version.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/version.go index ab4005676..b7b502887 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/resources/resources/version.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources/version.go @@ -1,5 +1,7 @@ package resources +import "github.com/Azure/azure-sdk-for-go/version" + // Copyright (c) Microsoft and contributors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,15 +16,15 @@ package resources // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.2.2.0 +// Code generated by Microsoft (R) AutoRest Code Generator. // Changes may cause incorrect behavior and will be lost if the code is regenerated. // UserAgent returns the UserAgent string to use when sending http.Requests. func UserAgent() string { - return "Azure-SDK-For-Go/v10.3.0-beta arm-resources/2017-05-10" + return "Azure-SDK-For-Go/" + version.Number + " resources/2016-02-01" } // Version returns the semantic version (see http://semver.org) of the client. func Version() string { - return "v10.3.0-beta" + return version.Number } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/accounts.go b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/accounts.go similarity index 52% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/storage/accounts.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/accounts.go index f0606ac13..b9d2cbd99 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/accounts.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/accounts.go @@ -14,20 +14,20 @@ package storage // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. import ( + "context" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" "github.com/Azure/go-autorest/autorest/validation" "net/http" ) -// AccountsClient is the the Azure Storage Management API. +// AccountsClient is the the Storage Management Client. type AccountsClient struct { - ManagementClient + BaseClient } // NewAccountsClient creates an instance of the AccountsClient client. @@ -35,27 +35,24 @@ func NewAccountsClient(subscriptionID string) AccountsClient { return NewAccountsClientWithBaseURI(DefaultBaseURI, subscriptionID) } -// NewAccountsClientWithBaseURI creates an instance of the AccountsClient -// client. +// NewAccountsClientWithBaseURI creates an instance of the AccountsClient client. func NewAccountsClientWithBaseURI(baseURI string, subscriptionID string) AccountsClient { return AccountsClient{NewWithBaseURI(baseURI, subscriptionID)} } -// CheckNameAvailability checks that the storage account name is valid and is -// not already in use. -// -// accountName is the name of the storage account within the specified resource -// group. Storage account names must be between 3 and 24 characters in length -// and use numbers and lower-case letters only. -func (client AccountsClient) CheckNameAvailability(accountName AccountCheckNameAvailabilityParameters) (result CheckNameAvailabilityResult, err error) { +// CheckNameAvailability checks that the storage account name is valid and is not already in use. +// Parameters: +// accountName - the name of the storage account within the specified resource group. Storage account names +// must be between 3 and 24 characters in length and use numbers and lower-case letters only. +func (client AccountsClient) CheckNameAvailability(ctx context.Context, accountName AccountCheckNameAvailabilityParameters) (result CheckNameAvailabilityResult, err error) { if err := validation.Validate([]validation.Validation{ {TargetValue: accountName, Constraints: []validation.Constraint{{Target: "accountName.Name", Name: validation.Null, Rule: true, Chain: nil}, {Target: "accountName.Type", Name: validation.Null, Rule: true, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "storage.AccountsClient", "CheckNameAvailability") + return result, validation.NewError("storage.AccountsClient", "CheckNameAvailability", err.Error()) } - req, err := client.CheckNameAvailabilityPreparer(accountName) + req, err := client.CheckNameAvailabilityPreparer(ctx, accountName) if err != nil { err = autorest.NewErrorWithError(err, "storage.AccountsClient", "CheckNameAvailability", nil, "Failure preparing request") return @@ -77,30 +74,31 @@ func (client AccountsClient) CheckNameAvailability(accountName AccountCheckNameA } // CheckNameAvailabilityPreparer prepares the CheckNameAvailability request. -func (client AccountsClient) CheckNameAvailabilityPreparer(accountName AccountCheckNameAvailabilityParameters) (*http.Request, error) { +func (client AccountsClient) CheckNameAvailabilityPreparer(ctx context.Context, accountName AccountCheckNameAvailabilityParameters) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } preparer := autorest.CreatePreparer( - autorest.AsJSON(), + autorest.AsContentType("application/json; charset=utf-8"), autorest.AsPost(), autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.Storage/checkNameAvailability", pathParameters), autorest.WithJSON(accountName), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // CheckNameAvailabilitySender sends the CheckNameAvailability request. The method will close the // http.Response Body if it receives an error. func (client AccountsClient) CheckNameAvailabilitySender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // CheckNameAvailabilityResponder handles the response to the CheckNameAvailability request. The method always @@ -116,29 +114,17 @@ func (client AccountsClient) CheckNameAvailabilityResponder(resp *http.Response) return } -// Create asynchronously creates a new storage account with the specified -// parameters. If an account is already created and a subsequent create request -// is issued with different properties, the account properties will be updated. -// If an account is already created and a subsequent create or update request -// is issued with the exact same set of properties, the request will succeed. -// This method may poll for completion. Polling can be canceled by passing the -// cancel channel argument. The channel will be used to cancel polling and any -// outstanding HTTP requests. -// -// resourceGroupName is the name of the resource group within the user's -// subscription. The name is case insensitive. accountName is the name of the -// storage account within the specified resource group. Storage account names -// must be between 3 and 24 characters in length and use numbers and lower-case -// letters only. parameters is the parameters to provide for the created -// account. -func (client AccountsClient) Create(resourceGroupName string, accountName string, parameters AccountCreateParameters, cancel <-chan struct{}) (<-chan Account, <-chan error) { - resultChan := make(chan Account, 1) - errChan := make(chan error, 1) +// Create asynchronously creates a new storage account with the specified parameters. If an account is already created +// and a subsequent create request is issued with different properties, the account properties will be updated. If an +// account is already created and a subsequent create or update request is issued with the exact same set of +// properties, the request will succeed. +// Parameters: +// resourceGroupName - the name of the resource group within the user's subscription. +// accountName - the name of the storage account within the specified resource group. Storage account names +// must be between 3 and 24 characters in length and use numbers and lower-case letters only. +// parameters - the parameters to provide for the created account. +func (client AccountsClient) Create(ctx context.Context, resourceGroupName string, accountName string, parameters AccountCreateParameters) (result AccountsCreateFuture, err error) { if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, {TargetValue: accountName, Constraints: []validation.Constraint{{Target: "accountName", Name: validation.MaxLength, Rule: 24, Chain: nil}, {Target: "accountName", Name: validation.MinLength, Rule: 3, Chain: nil}}}, @@ -151,71 +137,62 @@ func (client AccountsClient) Create(resourceGroupName string, accountName string {Target: "parameters.AccountPropertiesCreateParameters.Encryption", Name: validation.Null, Rule: false, Chain: []validation.Constraint{{Target: "parameters.AccountPropertiesCreateParameters.Encryption.KeySource", Name: validation.Null, Rule: true, Chain: nil}}}, }}}}}); err != nil { - errChan <- validation.NewErrorWithValidationError(err, "storage.AccountsClient", "Create") - close(errChan) - close(resultChan) - return resultChan, errChan + return result, validation.NewError("storage.AccountsClient", "Create", err.Error()) } - go func() { - var err error - var result Account - defer func() { - resultChan <- result - errChan <- err - close(resultChan) - close(errChan) - }() - req, err := client.CreatePreparer(resourceGroupName, accountName, parameters, cancel) - if err != nil { - err = autorest.NewErrorWithError(err, "storage.AccountsClient", "Create", nil, "Failure preparing request") - return - } + req, err := client.CreatePreparer(ctx, resourceGroupName, accountName, parameters) + if err != nil { + err = autorest.NewErrorWithError(err, "storage.AccountsClient", "Create", nil, "Failure preparing request") + return + } - resp, err := client.CreateSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "storage.AccountsClient", "Create", resp, "Failure sending request") - return - } + result, err = client.CreateSender(req) + if err != nil { + err = autorest.NewErrorWithError(err, "storage.AccountsClient", "Create", result.Response(), "Failure sending request") + return + } - result, err = client.CreateResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "storage.AccountsClient", "Create", resp, "Failure responding to request") - } - }() - return resultChan, errChan + return } // CreatePreparer prepares the Create request. -func (client AccountsClient) CreatePreparer(resourceGroupName string, accountName string, parameters AccountCreateParameters, cancel <-chan struct{}) (*http.Request, error) { +func (client AccountsClient) CreatePreparer(ctx context.Context, resourceGroupName string, accountName string, parameters AccountCreateParameters) (*http.Request, error) { pathParameters := map[string]interface{}{ "accountName": autorest.Encode("path", accountName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-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.Storage/storageAccounts/{accountName}", pathParameters), autorest.WithJSON(parameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{Cancel: cancel}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // CreateSender sends the Create request. The method will close the // http.Response Body if it receives an error. -func (client AccountsClient) CreateSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, - req, - azure.DoPollForAsynchronous(client.PollingDelay)) +func (client AccountsClient) CreateSender(req *http.Request) (future AccountsCreateFuture, err error) { + var resp *http.Response + resp, err = autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) + if err != nil { + return + } + err = autorest.Respond(resp, azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusAccepted)) + if err != nil { + return + } + future.Future, err = azure.NewFutureFromResponse(resp) + return } // CreateResponder handles the response to the Create request. The method always @@ -232,25 +209,19 @@ func (client AccountsClient) CreateResponder(resp *http.Response) (result Accoun } // Delete deletes a storage account in Microsoft Azure. -// -// resourceGroupName is the name of the resource group within the user's -// subscription. The name is case insensitive. accountName is the name of the -// storage account within the specified resource group. Storage account names -// must be between 3 and 24 characters in length and use numbers and lower-case -// letters only. -func (client AccountsClient) Delete(resourceGroupName string, accountName string) (result autorest.Response, err error) { +// Parameters: +// resourceGroupName - the name of the resource group within the user's subscription. +// accountName - the name of the storage account within the specified resource group. Storage account names +// must be between 3 and 24 characters in length and use numbers and lower-case letters only. +func (client AccountsClient) Delete(ctx context.Context, resourceGroupName string, accountName string) (result autorest.Response, err error) { if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, {TargetValue: accountName, Constraints: []validation.Constraint{{Target: "accountName", Name: validation.MaxLength, Rule: 24, Chain: nil}, {Target: "accountName", Name: validation.MinLength, Rule: 3, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "storage.AccountsClient", "Delete") + return result, validation.NewError("storage.AccountsClient", "Delete", err.Error()) } - req, err := client.DeletePreparer(resourceGroupName, accountName) + req, err := client.DeletePreparer(ctx, resourceGroupName, accountName) if err != nil { err = autorest.NewErrorWithError(err, "storage.AccountsClient", "Delete", nil, "Failure preparing request") return @@ -272,14 +243,14 @@ func (client AccountsClient) Delete(resourceGroupName string, accountName string } // DeletePreparer prepares the Delete request. -func (client AccountsClient) DeletePreparer(resourceGroupName string, accountName string) (*http.Request, error) { +func (client AccountsClient) DeletePreparer(ctx context.Context, resourceGroupName string, accountName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "accountName": autorest.Encode("path", accountName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -289,13 +260,14 @@ func (client AccountsClient) DeletePreparer(resourceGroupName string, accountNam autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}", pathParameters), autorest.WithQueryParameters(queryParameters)) - 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 AccountsClient) 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 @@ -310,28 +282,21 @@ func (client AccountsClient) DeleteResponder(resp *http.Response) (result autore return } -// GetProperties returns the properties for the specified storage account -// including but not limited to name, SKU name, location, and account status. -// The ListKeys operation should be used to retrieve storage keys. -// -// resourceGroupName is the name of the resource group within the user's -// subscription. The name is case insensitive. accountName is the name of the -// storage account within the specified resource group. Storage account names -// must be between 3 and 24 characters in length and use numbers and lower-case -// letters only. -func (client AccountsClient) GetProperties(resourceGroupName string, accountName string) (result Account, err error) { +// GetProperties returns the properties for the specified storage account including but not limited to name, SKU name, +// location, and account status. The ListKeys operation should be used to retrieve storage keys. +// Parameters: +// resourceGroupName - the name of the resource group within the user's subscription. +// accountName - the name of the storage account within the specified resource group. Storage account names +// must be between 3 and 24 characters in length and use numbers and lower-case letters only. +func (client AccountsClient) GetProperties(ctx context.Context, resourceGroupName string, accountName string) (result Account, err error) { if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, {TargetValue: accountName, Constraints: []validation.Constraint{{Target: "accountName", Name: validation.MaxLength, Rule: 24, Chain: nil}, {Target: "accountName", Name: validation.MinLength, Rule: 3, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "storage.AccountsClient", "GetProperties") + return result, validation.NewError("storage.AccountsClient", "GetProperties", err.Error()) } - req, err := client.GetPropertiesPreparer(resourceGroupName, accountName) + req, err := client.GetPropertiesPreparer(ctx, resourceGroupName, accountName) if err != nil { err = autorest.NewErrorWithError(err, "storage.AccountsClient", "GetProperties", nil, "Failure preparing request") return @@ -353,14 +318,14 @@ func (client AccountsClient) GetProperties(resourceGroupName string, accountName } // GetPropertiesPreparer prepares the GetProperties request. -func (client AccountsClient) GetPropertiesPreparer(resourceGroupName string, accountName string) (*http.Request, error) { +func (client AccountsClient) GetPropertiesPreparer(ctx context.Context, resourceGroupName string, accountName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "accountName": autorest.Encode("path", accountName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -370,13 +335,14 @@ func (client AccountsClient) GetPropertiesPreparer(resourceGroupName string, acc autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // GetPropertiesSender sends the GetProperties request. The method will close the // http.Response Body if it receives an error. func (client AccountsClient) GetPropertiesSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // GetPropertiesResponder handles the response to the GetProperties request. The method always @@ -392,10 +358,10 @@ func (client AccountsClient) GetPropertiesResponder(resp *http.Response) (result return } -// List lists all the storage accounts available under the subscription. Note -// that storage keys are not returned; use the ListKeys operation for this. -func (client AccountsClient) List() (result AccountListResult, err error) { - req, err := client.ListPreparer() +// List lists all the storage accounts available under the subscription. Note that storage keys are not returned; use +// the ListKeys operation for this. +func (client AccountsClient) List(ctx context.Context) (result AccountListResult, err error) { + req, err := client.ListPreparer(ctx) if err != nil { err = autorest.NewErrorWithError(err, "storage.AccountsClient", "List", nil, "Failure preparing request") return @@ -417,12 +383,12 @@ func (client AccountsClient) List() (result AccountListResult, err error) { } // ListPreparer prepares the List request. -func (client AccountsClient) ListPreparer() (*http.Request, error) { +func (client AccountsClient) ListPreparer(ctx context.Context) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -432,13 +398,14 @@ func (client AccountsClient) ListPreparer() (*http.Request, error) { autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.Storage/storageAccounts", 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 AccountsClient) 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 @@ -454,107 +421,12 @@ func (client AccountsClient) ListResponder(resp *http.Response) (result AccountL return } -// ListAccountSAS list SAS credentials of a storage account. -// -// resourceGroupName is the name of the resource group within the user's -// subscription. The name is case insensitive. accountName is the name of the -// storage account within the specified resource group. Storage account names -// must be between 3 and 24 characters in length and use numbers and lower-case -// letters only. parameters is the parameters to provide to list SAS -// credentials for the storage account. -func (client AccountsClient) ListAccountSAS(resourceGroupName string, accountName string, parameters AccountSasParameters) (result ListAccountSasResponse, err error) { - if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: accountName, - Constraints: []validation.Constraint{{Target: "accountName", Name: validation.MaxLength, Rule: 24, Chain: nil}, - {Target: "accountName", Name: validation.MinLength, Rule: 3, Chain: nil}}}, - {TargetValue: parameters, - Constraints: []validation.Constraint{{Target: "parameters.SharedAccessExpiryTime", Name: validation.Null, Rule: true, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "storage.AccountsClient", "ListAccountSAS") - } - - req, err := client.ListAccountSASPreparer(resourceGroupName, accountName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "storage.AccountsClient", "ListAccountSAS", nil, "Failure preparing request") - return - } - - resp, err := client.ListAccountSASSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "storage.AccountsClient", "ListAccountSAS", resp, "Failure sending request") - return - } - - result, err = client.ListAccountSASResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "storage.AccountsClient", "ListAccountSAS", resp, "Failure responding to request") - } - - return -} - -// ListAccountSASPreparer prepares the ListAccountSAS request. -func (client AccountsClient) ListAccountSASPreparer(resourceGroupName string, accountName string, parameters AccountSasParameters) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "accountName": autorest.Encode("path", accountName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2016-12-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsJSON(), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}/ListAccountSas", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) -} - -// ListAccountSASSender sends the ListAccountSAS request. The method will close the -// http.Response Body if it receives an error. -func (client AccountsClient) ListAccountSASSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) -} - -// ListAccountSASResponder handles the response to the ListAccountSAS request. The method always -// closes the http.Response Body. -func (client AccountsClient) ListAccountSASResponder(resp *http.Response) (result ListAccountSasResponse, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// ListByResourceGroup lists all the storage accounts available under the given -// resource group. Note that storage keys are not returned; use the ListKeys -// operation for this. -// -// resourceGroupName is the name of the resource group within the user's -// subscription. The name is case insensitive. -func (client AccountsClient) ListByResourceGroup(resourceGroupName string) (result AccountListResult, err error) { - if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "storage.AccountsClient", "ListByResourceGroup") - } - - req, err := client.ListByResourceGroupPreparer(resourceGroupName) +// ListByResourceGroup lists all the storage accounts available under the given resource group. Note that storage keys +// are not returned; use the ListKeys operation for this. +// Parameters: +// resourceGroupName - the name of the resource group within the user's subscription. +func (client AccountsClient) ListByResourceGroup(ctx context.Context, resourceGroupName string) (result AccountListResult, err error) { + req, err := client.ListByResourceGroupPreparer(ctx, resourceGroupName) if err != nil { err = autorest.NewErrorWithError(err, "storage.AccountsClient", "ListByResourceGroup", nil, "Failure preparing request") return @@ -576,13 +448,13 @@ func (client AccountsClient) ListByResourceGroup(resourceGroupName string) (resu } // ListByResourceGroupPreparer prepares the ListByResourceGroup request. -func (client AccountsClient) ListByResourceGroupPreparer(resourceGroupName string) (*http.Request, error) { +func (client AccountsClient) ListByResourceGroupPreparer(ctx context.Context, resourceGroupName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -592,13 +464,14 @@ func (client AccountsClient) ListByResourceGroupPreparer(resourceGroupName strin autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts", 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 AccountsClient) 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 @@ -615,25 +488,19 @@ func (client AccountsClient) ListByResourceGroupResponder(resp *http.Response) ( } // ListKeys lists the access keys for the specified storage account. -// -// resourceGroupName is the name of the resource group within the user's -// subscription. The name is case insensitive. accountName is the name of the -// storage account within the specified resource group. Storage account names -// must be between 3 and 24 characters in length and use numbers and lower-case -// letters only. -func (client AccountsClient) ListKeys(resourceGroupName string, accountName string) (result AccountListKeysResult, err error) { +// Parameters: +// resourceGroupName - the name of the resource group within the user's subscription. +// accountName - the name of the storage account within the specified resource group. Storage account names +// must be between 3 and 24 characters in length and use numbers and lower-case letters only. +func (client AccountsClient) ListKeys(ctx context.Context, resourceGroupName string, accountName string) (result AccountListKeysResult, err error) { if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, {TargetValue: accountName, Constraints: []validation.Constraint{{Target: "accountName", Name: validation.MaxLength, Rule: 24, Chain: nil}, {Target: "accountName", Name: validation.MinLength, Rule: 3, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "storage.AccountsClient", "ListKeys") + return result, validation.NewError("storage.AccountsClient", "ListKeys", err.Error()) } - req, err := client.ListKeysPreparer(resourceGroupName, accountName) + req, err := client.ListKeysPreparer(ctx, resourceGroupName, accountName) if err != nil { err = autorest.NewErrorWithError(err, "storage.AccountsClient", "ListKeys", nil, "Failure preparing request") return @@ -655,14 +522,14 @@ func (client AccountsClient) ListKeys(resourceGroupName string, accountName stri } // ListKeysPreparer prepares the ListKeys request. -func (client AccountsClient) ListKeysPreparer(resourceGroupName string, accountName string) (*http.Request, error) { +func (client AccountsClient) ListKeysPreparer(ctx context.Context, resourceGroupName string, accountName string) (*http.Request, error) { pathParameters := map[string]interface{}{ "accountName": autorest.Encode("path", accountName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -672,13 +539,14 @@ func (client AccountsClient) ListKeysPreparer(resourceGroupName string, accountN autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}/listKeys", pathParameters), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // ListKeysSender sends the ListKeys request. The method will close the // http.Response Body if it receives an error. func (client AccountsClient) ListKeysSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // ListKeysResponder handles the response to the ListKeys request. The method always @@ -694,117 +562,23 @@ func (client AccountsClient) ListKeysResponder(resp *http.Response) (result Acco return } -// ListServiceSAS list service SAS credentials of a specific resource. -// -// resourceGroupName is the name of the resource group within the user's -// subscription. The name is case insensitive. accountName is the name of the -// storage account within the specified resource group. Storage account names -// must be between 3 and 24 characters in length and use numbers and lower-case -// letters only. parameters is the parameters to provide to list service SAS -// credentials. -func (client AccountsClient) ListServiceSAS(resourceGroupName string, accountName string, parameters ServiceSasParameters) (result ListServiceSasResponse, err error) { +// RegenerateKey regenerates one of the access keys for the specified storage account. +// Parameters: +// resourceGroupName - the name of the resource group within the user's subscription. +// accountName - the name of the storage account within the specified resource group. Storage account names +// must be between 3 and 24 characters in length and use numbers and lower-case letters only. +// regenerateKey - specifies name of the key which should be regenerated -- key1 or key2. +func (client AccountsClient) RegenerateKey(ctx context.Context, resourceGroupName string, accountName string, regenerateKey AccountRegenerateKeyParameters) (result AccountListKeysResult, err error) { if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, - {TargetValue: accountName, - Constraints: []validation.Constraint{{Target: "accountName", Name: validation.MaxLength, Rule: 24, Chain: nil}, - {Target: "accountName", Name: validation.MinLength, Rule: 3, Chain: nil}}}, - {TargetValue: parameters, - Constraints: []validation.Constraint{{Target: "parameters.CanonicalizedResource", Name: validation.Null, Rule: true, Chain: nil}, - {Target: "parameters.Identifier", Name: validation.Null, Rule: false, - Chain: []validation.Constraint{{Target: "parameters.Identifier", Name: validation.MaxLength, Rule: 64, Chain: nil}}}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "storage.AccountsClient", "ListServiceSAS") - } - - req, err := client.ListServiceSASPreparer(resourceGroupName, accountName, parameters) - if err != nil { - err = autorest.NewErrorWithError(err, "storage.AccountsClient", "ListServiceSAS", nil, "Failure preparing request") - return - } - - resp, err := client.ListServiceSASSender(req) - if err != nil { - result.Response = autorest.Response{Response: resp} - err = autorest.NewErrorWithError(err, "storage.AccountsClient", "ListServiceSAS", resp, "Failure sending request") - return - } - - result, err = client.ListServiceSASResponder(resp) - if err != nil { - err = autorest.NewErrorWithError(err, "storage.AccountsClient", "ListServiceSAS", resp, "Failure responding to request") - } - - return -} - -// ListServiceSASPreparer prepares the ListServiceSAS request. -func (client AccountsClient) ListServiceSASPreparer(resourceGroupName string, accountName string, parameters ServiceSasParameters) (*http.Request, error) { - pathParameters := map[string]interface{}{ - "accountName": autorest.Encode("path", accountName), - "resourceGroupName": autorest.Encode("path", resourceGroupName), - "subscriptionId": autorest.Encode("path", client.SubscriptionID), - } - - const APIVersion = "2016-12-01" - queryParameters := map[string]interface{}{ - "api-version": APIVersion, - } - - preparer := autorest.CreatePreparer( - autorest.AsJSON(), - autorest.AsPost(), - autorest.WithBaseURL(client.BaseURI), - autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}/ListServiceSas", pathParameters), - autorest.WithJSON(parameters), - autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) -} - -// ListServiceSASSender sends the ListServiceSAS request. The method will close the -// http.Response Body if it receives an error. -func (client AccountsClient) ListServiceSASSender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) -} - -// ListServiceSASResponder handles the response to the ListServiceSAS request. The method always -// closes the http.Response Body. -func (client AccountsClient) ListServiceSASResponder(resp *http.Response) (result ListServiceSasResponse, err error) { - err = autorest.Respond( - resp, - client.ByInspecting(), - azure.WithErrorUnlessStatusCode(http.StatusOK), - autorest.ByUnmarshallingJSON(&result), - autorest.ByClosing()) - result.Response = autorest.Response{Response: resp} - return -} - -// RegenerateKey regenerates one of the access keys for the specified storage -// account. -// -// resourceGroupName is the name of the resource group within the user's -// subscription. The name is case insensitive. accountName is the name of the -// storage account within the specified resource group. Storage account names -// must be between 3 and 24 characters in length and use numbers and lower-case -// letters only. regenerateKey is specifies name of the key which should be -// regenerated -- key1 or key2. -func (client AccountsClient) RegenerateKey(resourceGroupName string, accountName string, regenerateKey AccountRegenerateKeyParameters) (result AccountListKeysResult, err error) { - if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, {TargetValue: accountName, Constraints: []validation.Constraint{{Target: "accountName", Name: validation.MaxLength, Rule: 24, Chain: nil}, {Target: "accountName", Name: validation.MinLength, Rule: 3, Chain: nil}}}, {TargetValue: regenerateKey, Constraints: []validation.Constraint{{Target: "regenerateKey.KeyName", Name: validation.Null, Rule: true, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "storage.AccountsClient", "RegenerateKey") + return result, validation.NewError("storage.AccountsClient", "RegenerateKey", err.Error()) } - req, err := client.RegenerateKeyPreparer(resourceGroupName, accountName, regenerateKey) + req, err := client.RegenerateKeyPreparer(ctx, resourceGroupName, accountName, regenerateKey) if err != nil { err = autorest.NewErrorWithError(err, "storage.AccountsClient", "RegenerateKey", nil, "Failure preparing request") return @@ -826,32 +600,33 @@ func (client AccountsClient) RegenerateKey(resourceGroupName string, accountName } // RegenerateKeyPreparer prepares the RegenerateKey request. -func (client AccountsClient) RegenerateKeyPreparer(resourceGroupName string, accountName string, regenerateKey AccountRegenerateKeyParameters) (*http.Request, error) { +func (client AccountsClient) RegenerateKeyPreparer(ctx context.Context, resourceGroupName string, accountName string, regenerateKey AccountRegenerateKeyParameters) (*http.Request, error) { pathParameters := map[string]interface{}{ "accountName": autorest.Encode("path", accountName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } preparer := autorest.CreatePreparer( - autorest.AsJSON(), + autorest.AsContentType("application/json; charset=utf-8"), autorest.AsPost(), autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}/regenerateKey", pathParameters), autorest.WithJSON(regenerateKey), autorest.WithQueryParameters(queryParameters)) - return preparer.Prepare(&http.Request{}) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) } // RegenerateKeySender sends the RegenerateKey request. The method will close the // http.Response Body if it receives an error. func (client AccountsClient) RegenerateKeySender(req *http.Request) (*http.Response, error) { - return autorest.SendWithSender(client, req) + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) } // RegenerateKeyResponder handles the response to the RegenerateKey request. The method always @@ -867,36 +642,26 @@ func (client AccountsClient) RegenerateKeyResponder(resp *http.Response) (result return } -// Update the update operation can be used to update the SKU, encryption, -// access tier, or tags for a storage account. It can also be used to map the -// account to a custom domain. Only one custom domain is supported per storage -// account; the replacement/change of custom domain is not supported. In order -// to replace an old custom domain, the old value must be cleared/unregistered -// before a new value can be set. The update of multiple properties is -// supported. This call does not change the storage keys for the account. If -// you want to change the storage account keys, use the regenerate keys -// operation. The location and name of the storage account cannot be changed -// after creation. -// -// resourceGroupName is the name of the resource group within the user's -// subscription. The name is case insensitive. accountName is the name of the -// storage account within the specified resource group. Storage account names -// must be between 3 and 24 characters in length and use numbers and lower-case -// letters only. parameters is the parameters to provide for the updated -// account. -func (client AccountsClient) Update(resourceGroupName string, accountName string, parameters AccountUpdateParameters) (result Account, err error) { +// Update the update operation can be used to update the SKU, encryption, access tier, or tags for a storage account. +// It can also be used to map the account to a custom domain. Only one custom domain is supported per storage account; +// the replacement/change of custom domain is not supported. In order to replace an old custom domain, the old value +// must be cleared/unregistered before a new value can be set. The update of multiple properties is supported. This +// call does not change the storage keys for the account. If you want to change the storage account keys, use the +// regenerate keys operation. The location and name of the storage account cannot be changed after creation. +// Parameters: +// resourceGroupName - the name of the resource group within the user's subscription. +// accountName - the name of the storage account within the specified resource group. Storage account names +// must be between 3 and 24 characters in length and use numbers and lower-case letters only. +// parameters - the parameters to provide for the updated account. +func (client AccountsClient) Update(ctx context.Context, resourceGroupName string, accountName string, parameters AccountUpdateParameters) (result Account, err error) { if err := validation.Validate([]validation.Validation{ - {TargetValue: resourceGroupName, - Constraints: []validation.Constraint{{Target: "resourceGroupName", Name: validation.MaxLength, Rule: 90, Chain: nil}, - {Target: "resourceGroupName", Name: validation.MinLength, Rule: 1, Chain: nil}, - {Target: "resourceGroupName", Name: validation.Pattern, Rule: `^[-\w\._\(\)]+$`, Chain: nil}}}, {TargetValue: accountName, Constraints: []validation.Constraint{{Target: "accountName", Name: validation.MaxLength, Rule: 24, Chain: nil}, {Target: "accountName", Name: validation.MinLength, Rule: 3, Chain: nil}}}}); err != nil { - return result, validation.NewErrorWithValidationError(err, "storage.AccountsClient", "Update") + return result, validation.NewError("storage.AccountsClient", "Update", err.Error()) } - req, err := client.UpdatePreparer(resourceGroupName, accountName, parameters) + req, err := client.UpdatePreparer(ctx, resourceGroupName, accountName, parameters) if err != nil { err = autorest.NewErrorWithError(err, "storage.AccountsClient", "Update", nil, "Failure preparing request") return @@ -918,32 +683,33 @@ func (client AccountsClient) Update(resourceGroupName string, accountName string } // UpdatePreparer prepares the Update request. -func (client AccountsClient) UpdatePreparer(resourceGroupName string, accountName string, parameters AccountUpdateParameters) (*http.Request, error) { +func (client AccountsClient) UpdatePreparer(ctx context.Context, resourceGroupName string, accountName string, parameters AccountUpdateParameters) (*http.Request, error) { pathParameters := map[string]interface{}{ "accountName": autorest.Encode("path", accountName), "resourceGroupName": autorest.Encode("path", resourceGroupName), "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-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.Storage/storageAccounts/{accountName}", pathParameters), autorest.WithJSON(parameters), autorest.WithQueryParameters(queryParameters)) - 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 AccountsClient) 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 diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/client.go b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/client.go similarity index 69% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/storage/client.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/client.go index a537bdd25..483dfc6d0 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/client.go @@ -1,7 +1,6 @@ -// Package storage implements the Azure ARM Storage service API version -// 2016-12-01. +// Package storage implements the Azure ARM Storage service API version 2016-01-01. // -// The Azure Storage Management API. +// The Storage Management Client. package storage // Copyright (c) Microsoft and contributors. All rights reserved. @@ -18,9 +17,8 @@ package storage // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. import ( "github.com/Azure/go-autorest/autorest" @@ -31,21 +29,21 @@ const ( DefaultBaseURI = "https://management.azure.com" ) -// ManagementClient is the base client for Storage. -type ManagementClient struct { +// BaseClient is the base client for Storage. +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, diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/models.go b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/models.go new file mode 100644 index 000000000..4fdf467fa --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/models.go @@ -0,0 +1,708 @@ +package storage + +// 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/date" + "net/http" +) + +// AccessTier enumerates the values for access tier. +type AccessTier string + +const ( + // Cool ... + Cool AccessTier = "Cool" + // Hot ... + Hot AccessTier = "Hot" +) + +// PossibleAccessTierValues returns an array of possible values for the AccessTier const type. +func PossibleAccessTierValues() []AccessTier { + return []AccessTier{Cool, Hot} +} + +// AccountStatus enumerates the values for account status. +type AccountStatus string + +const ( + // Available ... + Available AccountStatus = "Available" + // Unavailable ... + Unavailable AccountStatus = "Unavailable" +) + +// PossibleAccountStatusValues returns an array of possible values for the AccountStatus const type. +func PossibleAccountStatusValues() []AccountStatus { + return []AccountStatus{Available, Unavailable} +} + +// KeyPermission enumerates the values for key permission. +type KeyPermission string + +const ( + // FULL ... + FULL KeyPermission = "FULL" + // READ ... + READ KeyPermission = "READ" +) + +// PossibleKeyPermissionValues returns an array of possible values for the KeyPermission const type. +func PossibleKeyPermissionValues() []KeyPermission { + return []KeyPermission{FULL, READ} +} + +// Kind enumerates the values for kind. +type Kind string + +const ( + // BlobStorage ... + BlobStorage Kind = "BlobStorage" + // Storage ... + Storage Kind = "Storage" +) + +// PossibleKindValues returns an array of possible values for the Kind const type. +func PossibleKindValues() []Kind { + return []Kind{BlobStorage, Storage} +} + +// ProvisioningState enumerates the values for provisioning state. +type ProvisioningState string + +const ( + // Creating ... + Creating ProvisioningState = "Creating" + // ResolvingDNS ... + ResolvingDNS ProvisioningState = "ResolvingDNS" + // Succeeded ... + Succeeded ProvisioningState = "Succeeded" +) + +// PossibleProvisioningStateValues returns an array of possible values for the ProvisioningState const type. +func PossibleProvisioningStateValues() []ProvisioningState { + return []ProvisioningState{Creating, ResolvingDNS, Succeeded} +} + +// Reason enumerates the values for reason. +type Reason string + +const ( + // AccountNameInvalid ... + AccountNameInvalid Reason = "AccountNameInvalid" + // AlreadyExists ... + AlreadyExists Reason = "AlreadyExists" +) + +// PossibleReasonValues returns an array of possible values for the Reason const type. +func PossibleReasonValues() []Reason { + return []Reason{AccountNameInvalid, AlreadyExists} +} + +// SkuName enumerates the values for sku name. +type SkuName string + +const ( + // PremiumLRS ... + PremiumLRS SkuName = "Premium_LRS" + // StandardGRS ... + StandardGRS SkuName = "Standard_GRS" + // StandardLRS ... + StandardLRS SkuName = "Standard_LRS" + // StandardRAGRS ... + StandardRAGRS SkuName = "Standard_RAGRS" + // StandardZRS ... + StandardZRS SkuName = "Standard_ZRS" +) + +// PossibleSkuNameValues returns an array of possible values for the SkuName const type. +func PossibleSkuNameValues() []SkuName { + return []SkuName{PremiumLRS, StandardGRS, StandardLRS, StandardRAGRS, StandardZRS} +} + +// SkuTier enumerates the values for sku tier. +type SkuTier string + +const ( + // Premium ... + Premium SkuTier = "Premium" + // Standard ... + Standard SkuTier = "Standard" +) + +// PossibleSkuTierValues returns an array of possible values for the SkuTier const type. +func PossibleSkuTierValues() []SkuTier { + return []SkuTier{Premium, Standard} +} + +// UsageUnit enumerates the values for usage unit. +type UsageUnit string + +const ( + // Bytes ... + Bytes UsageUnit = "Bytes" + // BytesPerSecond ... + BytesPerSecond UsageUnit = "BytesPerSecond" + // Count ... + Count UsageUnit = "Count" + // CountsPerSecond ... + CountsPerSecond UsageUnit = "CountsPerSecond" + // Percent ... + Percent UsageUnit = "Percent" + // Seconds ... + Seconds UsageUnit = "Seconds" +) + +// PossibleUsageUnitValues returns an array of possible values for the UsageUnit const type. +func PossibleUsageUnitValues() []UsageUnit { + return []UsageUnit{Bytes, BytesPerSecond, Count, CountsPerSecond, Percent, Seconds} +} + +// Account the storage account. +type Account struct { + autorest.Response `json:"-"` + // Sku - Gets the SKU. + Sku *Sku `json:"sku,omitempty"` + // Kind - Gets the Kind. Possible values include: 'Storage', 'BlobStorage' + Kind Kind `json:"kind,omitempty"` + *AccountProperties `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 - Tags assigned to a resource; can be used for viewing and grouping a resource (across resource groups). + Tags map[string]*string `json:"tags"` +} + +// MarshalJSON is the custom marshaler for Account. +func (a Account) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]interface{}) + if a.Sku != nil { + objectMap["sku"] = a.Sku + } + if a.Kind != "" { + objectMap["kind"] = a.Kind + } + if a.AccountProperties != nil { + objectMap["properties"] = a.AccountProperties + } + if a.ID != nil { + objectMap["id"] = a.ID + } + if a.Name != nil { + objectMap["name"] = a.Name + } + if a.Type != nil { + objectMap["type"] = a.Type + } + if a.Location != nil { + objectMap["location"] = a.Location + } + if a.Tags != nil { + objectMap["tags"] = a.Tags + } + return json.Marshal(objectMap) +} + +// UnmarshalJSON is the custom unmarshaler for Account struct. +func (a *Account) 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 "sku": + if v != nil { + var sku Sku + err = json.Unmarshal(*v, &sku) + if err != nil { + return err + } + a.Sku = &sku + } + case "kind": + if v != nil { + var kind Kind + err = json.Unmarshal(*v, &kind) + if err != nil { + return err + } + a.Kind = kind + } + case "properties": + if v != nil { + var accountProperties AccountProperties + err = json.Unmarshal(*v, &accountProperties) + if err != nil { + return err + } + a.AccountProperties = &accountProperties + } + case "id": + if v != nil { + var ID string + err = json.Unmarshal(*v, &ID) + if err != nil { + return err + } + a.ID = &ID + } + case "name": + if v != nil { + var name string + err = json.Unmarshal(*v, &name) + if err != nil { + return err + } + a.Name = &name + } + case "type": + if v != nil { + var typeVar string + err = json.Unmarshal(*v, &typeVar) + if err != nil { + return err + } + a.Type = &typeVar + } + case "location": + if v != nil { + var location string + err = json.Unmarshal(*v, &location) + if err != nil { + return err + } + a.Location = &location + } + case "tags": + if v != nil { + var tags map[string]*string + err = json.Unmarshal(*v, &tags) + if err != nil { + return err + } + a.Tags = tags + } + } + } + + return nil +} + +// AccountCheckNameAvailabilityParameters ... +type AccountCheckNameAvailabilityParameters struct { + Name *string `json:"name,omitempty"` + Type *string `json:"type,omitempty"` +} + +// AccountCreateParameters the parameters used when creating a storage account. +type AccountCreateParameters struct { + // Sku - Required. Gets or sets the sku name. + Sku *Sku `json:"sku,omitempty"` + // Kind - Required. Indicates the type of storage account. Possible values include: 'Storage', 'BlobStorage' + Kind Kind `json:"kind,omitempty"` + // Location - Required. Gets or sets the location of the resource. This will be one of the supported and registered Azure Geo Regions (e.g. West US, East US, Southeast Asia, etc.). The geo region of a resource cannot be changed once it is created, but if an identical geo region is specified on update, the request will succeed. + Location *string `json:"location,omitempty"` + // Tags - Gets or sets a list of key value pairs that describe the resource. These tags can be used for viewing and grouping this resource (across resource groups). A maximum of 15 tags can be provided for a resource. Each tag must have a key with a length no greater than 128 characters and a value with a length no greater than 256 characters. + Tags map[string]*string `json:"tags"` + *AccountPropertiesCreateParameters `json:"properties,omitempty"` +} + +// MarshalJSON is the custom marshaler for AccountCreateParameters. +func (acp AccountCreateParameters) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]interface{}) + if acp.Sku != nil { + objectMap["sku"] = acp.Sku + } + if acp.Kind != "" { + objectMap["kind"] = acp.Kind + } + if acp.Location != nil { + objectMap["location"] = acp.Location + } + if acp.Tags != nil { + objectMap["tags"] = acp.Tags + } + if acp.AccountPropertiesCreateParameters != nil { + objectMap["properties"] = acp.AccountPropertiesCreateParameters + } + return json.Marshal(objectMap) +} + +// UnmarshalJSON is the custom unmarshaler for AccountCreateParameters struct. +func (acp *AccountCreateParameters) 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 "sku": + if v != nil { + var sku Sku + err = json.Unmarshal(*v, &sku) + if err != nil { + return err + } + acp.Sku = &sku + } + case "kind": + if v != nil { + var kind Kind + err = json.Unmarshal(*v, &kind) + if err != nil { + return err + } + acp.Kind = kind + } + case "location": + if v != nil { + var location string + err = json.Unmarshal(*v, &location) + if err != nil { + return err + } + acp.Location = &location + } + case "tags": + if v != nil { + var tags map[string]*string + err = json.Unmarshal(*v, &tags) + if err != nil { + return err + } + acp.Tags = tags + } + case "properties": + if v != nil { + var accountPropertiesCreateParameters AccountPropertiesCreateParameters + err = json.Unmarshal(*v, &accountPropertiesCreateParameters) + if err != nil { + return err + } + acp.AccountPropertiesCreateParameters = &accountPropertiesCreateParameters + } + } + } + + return nil +} + +// AccountKey an access key for the storage account. +type AccountKey struct { + // KeyName - Name of the key. + KeyName *string `json:"keyName,omitempty"` + // Value - Base 64-encoded value of the key. + Value *string `json:"value,omitempty"` + // Permissions - Permissions for the key -- read-only or full permissions. Possible values include: 'READ', 'FULL' + Permissions KeyPermission `json:"permissions,omitempty"` +} + +// AccountListKeysResult the response from the ListKeys operation. +type AccountListKeysResult struct { + autorest.Response `json:"-"` + // Keys - Gets the list of storage account keys and their properties for the specified storage account. + Keys *[]AccountKey `json:"keys,omitempty"` +} + +// AccountListResult the response from the List Storage Accounts operation. +type AccountListResult struct { + autorest.Response `json:"-"` + // Value - Gets the list of storage accounts and their properties. + Value *[]Account `json:"value,omitempty"` +} + +// AccountProperties ... +type AccountProperties struct { + // ProvisioningState - Gets the status of the storage account at the time the operation was called. Possible values include: 'Creating', 'ResolvingDNS', 'Succeeded' + ProvisioningState ProvisioningState `json:"provisioningState,omitempty"` + // PrimaryEndpoints - Gets the URLs that are used to perform a retrieval of a public blob, queue, or table object. Note that Standard_ZRS and Premium_LRS accounts only return the blob endpoint. + PrimaryEndpoints *Endpoints `json:"primaryEndpoints,omitempty"` + // PrimaryLocation - Gets the location of the primary data center for the storage account. + PrimaryLocation *string `json:"primaryLocation,omitempty"` + // StatusOfPrimary - Gets the status indicating whether the primary location of the storage account is available or unavailable. Possible values include: 'Available', 'Unavailable' + StatusOfPrimary AccountStatus `json:"statusOfPrimary,omitempty"` + // LastGeoFailoverTime - Gets the timestamp of the most recent instance of a failover to the secondary location. Only the most recent timestamp is retained. This element is not returned if there has never been a failover instance. Only available if the accountType is Standard_GRS or Standard_RAGRS. + LastGeoFailoverTime *date.Time `json:"lastGeoFailoverTime,omitempty"` + // SecondaryLocation - Gets the location of the geo-replicated secondary for the storage account. Only available if the accountType is Standard_GRS or Standard_RAGRS. + SecondaryLocation *string `json:"secondaryLocation,omitempty"` + // StatusOfSecondary - Gets the status indicating whether the secondary location of the storage account is available or unavailable. Only available if the SKU name is Standard_GRS or Standard_RAGRS. Possible values include: 'Available', 'Unavailable' + StatusOfSecondary AccountStatus `json:"statusOfSecondary,omitempty"` + // CreationTime - Gets the creation date and time of the storage account in UTC. + CreationTime *date.Time `json:"creationTime,omitempty"` + // CustomDomain - Gets the custom domain the user assigned to this storage account. + CustomDomain *CustomDomain `json:"customDomain,omitempty"` + // SecondaryEndpoints - Gets the URLs that are used to perform a retrieval of a public blob, queue, or table object from the secondary location of the storage account. Only available if the SKU name is Standard_RAGRS. + SecondaryEndpoints *Endpoints `json:"secondaryEndpoints,omitempty"` + // Encryption - Gets the encryption settings on the account. If unspecified, the account is unencrypted. + Encryption *Encryption `json:"encryption,omitempty"` + // AccessTier - Required for storage accounts where kind = BlobStorage. The access tier used for billing. Possible values include: 'Hot', 'Cool' + AccessTier AccessTier `json:"accessTier,omitempty"` +} + +// AccountPropertiesCreateParameters ... +type AccountPropertiesCreateParameters struct { + // CustomDomain - User domain assigned to the storage account. Name is the CNAME source. Only one custom domain is supported per storage account at this time. To clear the existing custom domain, use an empty string for the custom domain name property. + CustomDomain *CustomDomain `json:"customDomain,omitempty"` + // Encryption - Provides the encryption settings on the account. If left unspecified the account encryption settings will remain the same. The default setting is unencrypted. + Encryption *Encryption `json:"encryption,omitempty"` + // AccessTier - Required for storage accounts where kind = BlobStorage. The access tier used for billing. Possible values include: 'Hot', 'Cool' + AccessTier AccessTier `json:"accessTier,omitempty"` +} + +// AccountPropertiesUpdateParameters ... +type AccountPropertiesUpdateParameters struct { + // CustomDomain - Custom domain assigned to the storage account by the user. Name is the CNAME source. Only one custom domain is supported per storage account at this time. To clear the existing custom domain, use an empty string for the custom domain name property. + CustomDomain *CustomDomain `json:"customDomain,omitempty"` + // Encryption - Provides the encryption settings on the account. The default setting is unencrypted. + Encryption *Encryption `json:"encryption,omitempty"` + // AccessTier - Required for storage accounts where kind = BlobStorage. The access tier used for billing. Possible values include: 'Hot', 'Cool' + AccessTier AccessTier `json:"accessTier,omitempty"` +} + +// AccountRegenerateKeyParameters ... +type AccountRegenerateKeyParameters struct { + KeyName *string `json:"keyName,omitempty"` +} + +// AccountsCreateFuture an abstraction for monitoring and retrieving the results of a long-running operation. +type AccountsCreateFuture struct { + azure.Future +} + +// Result returns the result of the asynchronous operation. +// If the operation has not completed it will return an error. +func (future *AccountsCreateFuture) Result(client AccountsClient) (a Account, err error) { + var done bool + done, err = future.Done(client) + if err != nil { + err = autorest.NewErrorWithError(err, "storage.AccountsCreateFuture", "Result", future.Response(), "Polling failure") + return + } + if !done { + err = azure.NewAsyncOpIncompleteError("storage.AccountsCreateFuture") + return + } + sender := autorest.DecorateSender(client, autorest.DoRetryForStatusCodes(client.RetryAttempts, client.RetryDuration, autorest.StatusCodesForRetry...)) + if a.Response.Response, err = future.GetResult(sender); err == nil && a.Response.Response.StatusCode != http.StatusNoContent { + a, err = client.CreateResponder(a.Response.Response) + if err != nil { + err = autorest.NewErrorWithError(err, "storage.AccountsCreateFuture", "Result", a.Response.Response, "Failure responding to request") + } + } + return +} + +// AccountUpdateParameters the parameters that can be provided when updating the storage account properties. +type AccountUpdateParameters struct { + // Sku - Gets or sets the SKU name. Note that the SKU name cannot be updated to Standard_ZRS or Premium_LRS, nor can accounts of those sku names be updated to any other value. + Sku *Sku `json:"sku,omitempty"` + // Tags - Gets or sets a list of key value pairs that describe the resource. These tags can be used in viewing and grouping this resource (across resource groups). A maximum of 15 tags can be provided for a resource. Each tag must have a key no greater in length than 128 characters and a value no greater in length than 256 characters. + Tags map[string]*string `json:"tags"` + *AccountPropertiesUpdateParameters `json:"properties,omitempty"` +} + +// MarshalJSON is the custom marshaler for AccountUpdateParameters. +func (aup AccountUpdateParameters) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]interface{}) + if aup.Sku != nil { + objectMap["sku"] = aup.Sku + } + if aup.Tags != nil { + objectMap["tags"] = aup.Tags + } + if aup.AccountPropertiesUpdateParameters != nil { + objectMap["properties"] = aup.AccountPropertiesUpdateParameters + } + return json.Marshal(objectMap) +} + +// UnmarshalJSON is the custom unmarshaler for AccountUpdateParameters struct. +func (aup *AccountUpdateParameters) 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 "sku": + if v != nil { + var sku Sku + err = json.Unmarshal(*v, &sku) + if err != nil { + return err + } + aup.Sku = &sku + } + case "tags": + if v != nil { + var tags map[string]*string + err = json.Unmarshal(*v, &tags) + if err != nil { + return err + } + aup.Tags = tags + } + case "properties": + if v != nil { + var accountPropertiesUpdateParameters AccountPropertiesUpdateParameters + err = json.Unmarshal(*v, &accountPropertiesUpdateParameters) + if err != nil { + return err + } + aup.AccountPropertiesUpdateParameters = &accountPropertiesUpdateParameters + } + } + } + + return nil +} + +// CheckNameAvailabilityResult the CheckNameAvailability operation response. +type CheckNameAvailabilityResult struct { + autorest.Response `json:"-"` + // NameAvailable - Gets a boolean value that indicates whether the name is available for you to use. If true, the name is available. If false, the name has already been taken or is invalid and cannot be used. + NameAvailable *bool `json:"nameAvailable,omitempty"` + // Reason - Gets the reason that a storage account name could not be used. The Reason element is only returned if NameAvailable is false. Possible values include: 'AccountNameInvalid', 'AlreadyExists' + Reason Reason `json:"reason,omitempty"` + // Message - Gets an error message explaining the Reason value in more detail. + Message *string `json:"message,omitempty"` +} + +// CustomDomain the custom domain assigned to this storage account. This can be set via Update. +type CustomDomain struct { + // Name - Gets or sets the custom domain name assigned to the storage account. Name is the CNAME source. + Name *string `json:"name,omitempty"` + // UseSubDomain - Indicates whether indirect CName validation is enabled. Default value is false. This should only be set on updates. + UseSubDomain *bool `json:"useSubDomain,omitempty"` +} + +// Encryption the encryption settings on the storage account. +type Encryption struct { + // Services - List of services which support encryption. + Services *EncryptionServices `json:"services,omitempty"` + // KeySource - The encryption keySource (provider). Possible values (case-insensitive): Microsoft.Storage + KeySource *string `json:"keySource,omitempty"` +} + +// EncryptionService a service that allows server-side encryption to be used. +type EncryptionService struct { + // Enabled - A boolean indicating whether or not the service encrypts the data as it is stored. + Enabled *bool `json:"enabled,omitempty"` + // LastEnabledTime - Gets a rough estimate of the date/time when the encryption was last enabled by the user. Only returned when encryption is enabled. There might be some unencrypted blobs which were written after this time, as it is just a rough estimate. + LastEnabledTime *date.Time `json:"lastEnabledTime,omitempty"` +} + +// EncryptionServices a list of services that support encryption. +type EncryptionServices struct { + // Blob - The encryption function of the blob storage service. + Blob *EncryptionService `json:"blob,omitempty"` +} + +// Endpoints the URIs that are used to perform a retrieval of a public blob, queue, or table object. +type Endpoints struct { + // Blob - Gets the blob endpoint. + Blob *string `json:"blob,omitempty"` + // Queue - Gets the queue endpoint. + Queue *string `json:"queue,omitempty"` + // Table - Gets the table endpoint. + Table *string `json:"table,omitempty"` + // File - Gets the file endpoint. + File *string `json:"file,omitempty"` +} + +// 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 - Tags assigned to a resource; can be used for viewing and grouping a resource (across resource groups). + 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) +} + +// Sku the SKU of the storage account. +type Sku struct { + // Name - Gets or sets the sku name. Required for account creation; optional for update. Note that in older versions, sku name was called accountType. Possible values include: 'StandardLRS', 'StandardGRS', 'StandardRAGRS', 'StandardZRS', 'PremiumLRS' + Name SkuName `json:"name,omitempty"` + // Tier - Gets the sku tier. This is based on the SKU name. Possible values include: 'Standard', 'Premium' + Tier SkuTier `json:"tier,omitempty"` +} + +// Usage describes Storage Resource Usage. +type Usage struct { + // Unit - Gets the unit of measurement. Possible values include: 'Count', 'Bytes', 'Seconds', 'Percent', 'CountsPerSecond', 'BytesPerSecond' + Unit UsageUnit `json:"unit,omitempty"` + // CurrentValue - Gets the current count of the allocated resources in the subscription. + CurrentValue *int32 `json:"currentValue,omitempty"` + // Limit - Gets the maximum count of the resources that can be allocated in the subscription. + Limit *int32 `json:"limit,omitempty"` + // Name - Gets the name of the type of usage. + Name *UsageName `json:"name,omitempty"` +} + +// UsageListResult the response from the List Usages operation. +type UsageListResult struct { + autorest.Response `json:"-"` + // Value - Gets or sets the list of Storage Resource Usages. + Value *[]Usage `json:"value,omitempty"` +} + +// UsageName the usage names that can be used; currently limited to StorageAccount. +type UsageName struct { + // Value - Gets a string describing the resource name. + Value *string `json:"value,omitempty"` + // LocalizedValue - Gets a localized string describing the resource name. + LocalizedValue *string `json:"localizedValue,omitempty"` +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/usage.go b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/usage.go similarity index 83% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/storage/usage.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/usage.go index b12a6d315..1c136faf7 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/usage.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/usage.go @@ -14,19 +14,19 @@ package storage // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.0.1.0 -// Changes may cause incorrect behavior and will be lost if the code is -// regenerated. +// Code generated by Microsoft (R) AutoRest Code Generator. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. import ( + "context" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" "net/http" ) -// UsageClient is the the Azure Storage Management API. +// UsageClient is the the Storage Management Client. type UsageClient struct { - ManagementClient + BaseClient } // NewUsageClient creates an instance of the UsageClient client. @@ -39,10 +39,9 @@ func NewUsageClientWithBaseURI(baseURI string, subscriptionID string) UsageClien return UsageClient{NewWithBaseURI(baseURI, subscriptionID)} } -// List gets the current usage count and the limit for the resources under the -// subscription. -func (client UsageClient) List() (result UsageListResult, err error) { - req, err := client.ListPreparer() +// List gets the current usage count and the limit for the resources under the subscription. +func (client UsageClient) List(ctx context.Context) (result UsageListResult, err error) { + req, err := client.ListPreparer(ctx) if err != nil { err = autorest.NewErrorWithError(err, "storage.UsageClient", "List", nil, "Failure preparing request") return @@ -64,12 +63,12 @@ func (client UsageClient) List() (result UsageListResult, err error) { } // ListPreparer prepares the List request. -func (client UsageClient) ListPreparer() (*http.Request, error) { +func (client UsageClient) ListPreparer(ctx context.Context) (*http.Request, error) { pathParameters := map[string]interface{}{ "subscriptionId": autorest.Encode("path", client.SubscriptionID), } - const APIVersion = "2016-12-01" + const APIVersion = "2016-01-01" queryParameters := map[string]interface{}{ "api-version": APIVersion, } @@ -79,13 +78,14 @@ func (client UsageClient) ListPreparer() (*http.Request, error) { autorest.WithBaseURL(client.BaseURI), autorest.WithPathParameters("/subscriptions/{subscriptionId}/providers/Microsoft.Storage/usages", 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 UsageClient) 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 diff --git a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/version.go b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/version.go similarity index 82% rename from vendor/github.com/Azure/azure-sdk-for-go/arm/storage/version.go rename to vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/version.go index 8d944c739..b7c1881b3 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/arm/storage/version.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage/version.go @@ -1,5 +1,7 @@ package storage +import "github.com/Azure/azure-sdk-for-go/version" + // Copyright (c) Microsoft and contributors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,15 +16,15 @@ package storage // See the License for the specific language governing permissions and // limitations under the License. // -// Code generated by Microsoft (R) AutoRest Code Generator 1.2.2.0 +// Code generated by Microsoft (R) AutoRest Code Generator. // Changes may cause incorrect behavior and will be lost if the code is regenerated. // UserAgent returns the UserAgent string to use when sending http.Requests. func UserAgent() string { - return "Azure-SDK-For-Go/v10.3.0-beta arm-storage/2017-06-01" + return "Azure-SDK-For-Go/" + version.Number + " storage/2016-01-01" } // Version returns the semantic version (see http://semver.org) of the client. func Version() string { - return "v10.3.0-beta" + return version.Number } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/README.md b/vendor/github.com/Azure/azure-sdk-for-go/storage/README.md new file mode 100644 index 000000000..459b45831 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/README.md @@ -0,0 +1,22 @@ +# Azure Storage SDK for Go (Preview) + +:exclamation: IMPORTANT: This package is in maintenance only and will be deprecated in the +future. Please use one of the following packages instead. + +| Service | Import Path/Repo | +|---------|------------------| +| Storage - Blobs | [github.com/Azure/azure-storage-blob-go](https://github.com/Azure/azure-storage-blob-go) | +| Storage - Files | [github.com/Azure/azure-storage-file-go](https://github.com/Azure/azure-storage-file-go) | +| Storage - Queues | [github.com/Azure/azure-storage-queue-go](https://github.com/Azure/azure-storage-queue-go) | + +The `github.com/Azure/azure-sdk-for-go/storage` package is used to manage +[Azure Storage](https://docs.microsoft.com/en-us/azure/storage/) data plane +resources: containers, blobs, tables, and queues. + +To manage storage *accounts* use Azure Resource Manager (ARM) via the packages +at [github.com/Azure/azure-sdk-for-go/services/storage](https://github.com/Azure/azure-sdk-for-go/tree/master/services/storage). + +This package also supports the [Azure Storage +Emulator](https://azure.microsoft.com/documentation/articles/storage-use-emulator/) +(Windows only). + diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/appendblob.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/appendblob.go index c13d409b7..8b5b96d48 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/appendblob.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/appendblob.go @@ -1,7 +1,23 @@ package storage +// 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" + "crypto/md5" + "encoding/base64" "fmt" "net/http" "net/url" @@ -31,8 +47,7 @@ func (b *Blob) PutAppendBlob(options *PutBlobOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + return b.respondCreation(resp, BlobTypeAppend) } // AppendBlockOptions includes the options for an append block operation @@ -46,6 +61,7 @@ type AppendBlockOptions struct { IfMatch string `header:"If-Match"` IfNoneMatch string `header:"If-None-Match"` RequestID string `header:"x-ms-client-request-id"` + ContentMD5 bool } // AppendBlock appends a block to an append blob. @@ -60,6 +76,10 @@ func (b *Blob) AppendBlock(chunk []byte, options *AppendBlockOptions) error { if options != nil { params = addTimeout(params, options.Timeout) headers = mergeHeaders(headers, headersFromStruct(*options)) + if options.ContentMD5 { + md5sum := md5.Sum(chunk) + headers[headerContentMD5] = base64.StdEncoding.EncodeToString(md5sum[:]) + } } uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params) @@ -67,6 +87,5 @@ func (b *Blob) AppendBlock(chunk []byte, options *AppendBlockOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + return b.respondCreation(resp, BlobTypeAppend) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/authorization.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/authorization.go index 608bf3133..76794c305 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/authorization.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/authorization.go @@ -1,6 +1,20 @@ // Package storage provides clients for Microsoft Azure Storage Services. package storage +// 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" @@ -41,16 +55,18 @@ const ( ) func (c *Client) addAuthorizationHeader(verb, url string, headers map[string]string, auth authentication) (map[string]string, error) { - authHeader, err := c.getSharedKey(verb, url, headers, auth) - if err != nil { - return nil, err + if !c.sasClient { + authHeader, err := c.getSharedKey(verb, url, headers, auth) + if err != nil { + return nil, err + } + headers[headerAuthorization] = authHeader } - headers[headerAuthorization] = authHeader return headers, nil } func (c *Client) getSharedKey(verb, url string, headers map[string]string, auth authentication) (string, error) { - canRes, err := c.buildCanonicalizedResource(url, auth) + canRes, err := c.buildCanonicalizedResource(url, auth, false) if err != nil { return "", err } @@ -62,15 +78,18 @@ func (c *Client) getSharedKey(verb, url string, headers map[string]string, auth return c.createAuthorizationHeader(canString, auth), nil } -func (c *Client) buildCanonicalizedResource(uri string, auth authentication) (string, error) { +func (c *Client) buildCanonicalizedResource(uri string, auth authentication, sas bool) (string, error) { errMsg := "buildCanonicalizedResource error: %s" u, err := url.Parse(uri) if err != nil { return "", fmt.Errorf(errMsg, err.Error()) } - cr := bytes.NewBufferString("/") - cr.WriteString(c.getCanonicalizedAccountName()) + cr := bytes.NewBufferString("") + if c.accountName != StorageEmulatorAccountName || !sas { + cr.WriteString("/") + cr.WriteString(c.getCanonicalizedAccountName()) + } if len(u.Path) > 0 { // Any portion of the CanonicalizedResource string that is derived from diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/blob.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/blob.go index 12f61ac2a..1d2248625 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/blob.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/blob.go @@ -1,5 +1,19 @@ package storage +// 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/xml" "errors" @@ -90,7 +104,7 @@ type BlobProperties struct { CacheControl string `xml:"Cache-Control" header:"x-ms-blob-cache-control"` ContentLanguage string `xml:"Cache-Language" header:"x-ms-blob-content-language"` ContentDisposition string `xml:"Content-Disposition" header:"x-ms-blob-content-disposition"` - BlobType BlobType `xml:"x-ms-blob-blob-type"` + BlobType BlobType `xml:"BlobType"` SequenceNumber int64 `xml:"x-ms-blob-sequence-number"` CopyID string `xml:"CopyId"` CopyStatus string `xml:"CopyStatus"` @@ -126,17 +140,16 @@ func (b *Blob) Exists() (bool, error) { headers := b.Container.bsc.client.getStandardHeaders() resp, err := b.Container.bsc.client.exec(http.MethodHead, uri, headers, nil, b.Container.bsc.auth) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusOK, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotFound { + return resp.StatusCode == http.StatusOK, nil } } return false, err } // GetURL gets the canonical URL to the blob with the specified name in the -// specified container. If name is not specified, the canonical URL for the entire -// container is obtained. +// specified container. // This method does not create a publicly accessible URL if the blob or container // is private and this method does not check if the blob exists. func (b *Blob) GetURL() string { @@ -195,13 +208,13 @@ func (b *Blob) Get(options *GetBlobOptions) (io.ReadCloser, error) { return nil, err } - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err := checkRespCode(resp, []int{http.StatusOK}); err != nil { return nil, err } - if err := b.writeProperties(resp.headers, true); err != nil { - return resp.body, err + if err := b.writeProperties(resp.Header, true); err != nil { + return resp.Body, err } - return resp.body, nil + return resp.Body, nil } // GetRange reads the specified range of a blob to a stream. The bytesRange @@ -215,18 +228,18 @@ func (b *Blob) GetRange(options *GetBlobRangeOptions) (io.ReadCloser, error) { return nil, err } - if err := checkRespCode(resp.statusCode, []int{http.StatusPartialContent}); err != nil { + if err := checkRespCode(resp, []int{http.StatusPartialContent}); err != nil { return nil, err } // Content-Length header should not be updated, as the service returns the range length // (which is not alwys the full blob length) - if err := b.writeProperties(resp.headers, false); err != nil { - return resp.body, err + if err := b.writeProperties(resp.Header, false); err != nil { + return resp.Body, err } - return resp.body, nil + return resp.Body, nil } -func (b *Blob) getRange(options *GetBlobRangeOptions) (*storageResponse, error) { +func (b *Blob) getRange(options *GetBlobRangeOptions) (*http.Response, error) { params := url.Values{} headers := b.Container.bsc.client.getStandardHeaders() @@ -280,13 +293,13 @@ func (b *Blob) CreateSnapshot(options *SnapshotOptions) (snapshotTimestamp *time if err != nil || resp == nil { return nil, err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err := checkRespCode(resp.statusCode, []int{http.StatusCreated}); err != nil { + if err := checkRespCode(resp, []int{http.StatusCreated}); err != nil { return nil, err } - snapshotResponse := resp.headers.Get(http.CanonicalHeaderKey("x-ms-snapshot")) + snapshotResponse := resp.Header.Get(http.CanonicalHeaderKey("x-ms-snapshot")) if snapshotResponse != "" { snapshotTimestamp, err := time.Parse(time.RFC3339, snapshotResponse) if err != nil { @@ -327,12 +340,12 @@ func (b *Blob) GetProperties(options *GetBlobPropertiesOptions) error { if err != nil { return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err = checkRespCode(resp, []int{http.StatusOK}); err != nil { return err } - return b.writeProperties(resp.headers, true) + return b.writeProperties(resp.Header, true) } func (b *Blob) writeProperties(h http.Header, includeContentLen bool) error { @@ -437,8 +450,8 @@ func (b *Blob) SetProperties(options *SetBlobPropertiesOptions) error { uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params) if b.Properties.BlobType == BlobTypePage { - headers = addToHeaders(headers, "x-ms-blob-content-length", fmt.Sprintf("byte %v", b.Properties.ContentLength)) - if options != nil || options.SequenceNumberAction != nil { + headers = addToHeaders(headers, "x-ms-blob-content-length", fmt.Sprintf("%v", b.Properties.ContentLength)) + if options != nil && options.SequenceNumberAction != nil { headers = addToHeaders(headers, "x-ms-sequence-number-action", string(*options.SequenceNumberAction)) if *options.SequenceNumberAction != SequenceNumberActionIncrement { headers = addToHeaders(headers, "x-ms-blob-sequence-number", fmt.Sprintf("%v", b.Properties.SequenceNumber)) @@ -450,8 +463,8 @@ func (b *Blob) SetProperties(options *SetBlobPropertiesOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusOK}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusOK}) } // SetBlobMetadataOptions includes the options for a set blob metadata operation @@ -488,8 +501,8 @@ func (b *Blob) SetMetadata(options *SetBlobMetadataOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusOK}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusOK}) } // GetBlobMetadataOptions includes the options for a get blob metadata operation @@ -525,38 +538,18 @@ func (b *Blob) GetMetadata(options *GetBlobMetadataOptions) error { if err != nil { return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err := checkRespCode(resp, []int{http.StatusOK}); err != nil { return err } - b.writeMetadata(resp.headers) + b.writeMetadata(resp.Header) return nil } func (b *Blob) writeMetadata(h http.Header) { - metadata := make(map[string]string) - for k, v := range h { - // Can't trust CanonicalHeaderKey() to munge case - // reliably. "_" is allowed in identifiers: - // https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx - // https://msdn.microsoft.com/library/aa664670(VS.71).aspx - // http://tools.ietf.org/html/rfc7230#section-3.2 - // ...but "_" is considered invalid by - // CanonicalMIMEHeaderKey in - // https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542 - // so k can be "X-Ms-Meta-Lol" or "x-ms-meta-lol_rofl". - k = strings.ToLower(k) - if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) { - continue - } - // metadata["lol"] = content of the last X-Ms-Meta-Lol header - k = k[len(userDefinedMetadataHeaderPrefix):] - metadata[k] = v[len(v)-1] - } - - b.Metadata = BlobMetadata(metadata) + b.Metadata = BlobMetadata(writeMetadata(h)) } // DeleteBlobOptions includes the options for a delete blob operation @@ -581,8 +574,8 @@ func (b *Blob) Delete(options *DeleteBlobOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusAccepted}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusAccepted}) } // DeleteIfExists deletes the given blob from the specified container If the @@ -592,15 +585,15 @@ func (b *Blob) Delete(options *DeleteBlobOptions) error { func (b *Blob) DeleteIfExists(options *DeleteBlobOptions) (bool, error) { resp, err := b.delete(options) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound { + return resp.StatusCode == http.StatusAccepted, nil } } return false, err } -func (b *Blob) delete(options *DeleteBlobOptions) (*storageResponse, error) { +func (b *Blob) delete(options *DeleteBlobOptions) (*http.Response, error) { params := url.Values{} headers := b.Container.bsc.client.getStandardHeaders() @@ -627,3 +620,13 @@ func pathForResource(container, name string) string { } return fmt.Sprintf("/%s", container) } + +func (b *Blob) respondCreation(resp *http.Response, bt BlobType) error { + defer drainRespBody(resp) + err := checkRespCode(resp, []int{http.StatusCreated}) + if err != nil { + return err + } + b.Properties.BlobType = bt + return nil +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/blobsasuri.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/blobsasuri.go index 43173d3a4..31894dbfc 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/blobsasuri.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/blobsasuri.go @@ -1,5 +1,19 @@ package storage +// 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" "fmt" @@ -8,68 +22,126 @@ import ( "time" ) -// GetSASURIWithSignedIPAndProtocol creates an URL to the specified blob which contains the Shared -// Access Signature with specified permissions and expiration time. Also includes signedIPRange and allowed protocols. -// If old API version is used but no signedIP is passed (ie empty string) then this should still work. -// We only populate the signedIP when it non-empty. +// OverrideHeaders defines overridable response heaedrs in +// a request using a SAS URI. +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas +type OverrideHeaders struct { + CacheControl string + ContentDisposition string + ContentEncoding string + ContentLanguage string + ContentType string +} + +// BlobSASOptions are options to construct a blob SAS +// URI. +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas +type BlobSASOptions struct { + BlobServiceSASPermissions + OverrideHeaders + SASOptions +} + +// BlobServiceSASPermissions includes the available permissions for +// blob service SAS URI. +type BlobServiceSASPermissions struct { + Read bool + Add bool + Create bool + Write bool + Delete bool +} + +func (p BlobServiceSASPermissions) buildString() string { + permissions := "" + if p.Read { + permissions += "r" + } + if p.Add { + permissions += "a" + } + if p.Create { + permissions += "c" + } + if p.Write { + permissions += "w" + } + if p.Delete { + permissions += "d" + } + return permissions +} + +// GetSASURI creates an URL to the blob which contains the Shared +// Access Signature with the specified options. // -// See https://msdn.microsoft.com/en-us/library/azure/ee395415.aspx -func (b *Blob) GetSASURIWithSignedIPAndProtocol(expiry time.Time, permissions string, signedIPRange string, HTTPSOnly bool) (string, error) { - var ( - signedPermissions = permissions - blobURL = b.GetURL() - ) - canonicalizedResource, err := b.Container.bsc.client.buildCanonicalizedResource(blobURL, b.Container.bsc.auth) +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas +func (b *Blob) GetSASURI(options BlobSASOptions) (string, error) { + uri := b.GetURL() + signedResource := "b" + canonicalizedResource, err := b.Container.bsc.client.buildCanonicalizedResource(uri, b.Container.bsc.auth, true) if err != nil { return "", err } - // "The canonicalizedresouce portion of the string is a canonical path to the signed resource. - // It must include the service name (blob, table, queue or file) for version 2015-02-21 or - // later, the storage account name, and the resource name, and must be URL-decoded. - // -- https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx + permissions := options.BlobServiceSASPermissions.buildString() + return b.Container.bsc.client.blobAndFileSASURI(options.SASOptions, uri, permissions, canonicalizedResource, signedResource, options.OverrideHeaders) +} + +func (c *Client) blobAndFileSASURI(options SASOptions, uri, permissions, canonicalizedResource, signedResource string, headers OverrideHeaders) (string, error) { + start := "" + if options.Start != (time.Time{}) { + start = options.Start.UTC().Format(time.RFC3339) + } + + expiry := options.Expiry.UTC().Format(time.RFC3339) // We need to replace + with %2b first to avoid being treated as a space (which is correct for query strings, but not the path component). canonicalizedResource = strings.Replace(canonicalizedResource, "+", "%2b", -1) - canonicalizedResource, err = url.QueryUnescape(canonicalizedResource) + canonicalizedResource, err := url.QueryUnescape(canonicalizedResource) if err != nil { return "", err } - signedExpiry := expiry.UTC().Format(time.RFC3339) - - //If blob name is missing, resource is a container - signedResource := "c" - if len(b.Name) > 0 { - signedResource = "b" - } - - protocols := "https,http" - if HTTPSOnly { + protocols := "" + if options.UseHTTPS { protocols = "https" } - stringToSign, err := blobSASStringToSign(b.Container.bsc.client.apiVersion, canonicalizedResource, signedExpiry, signedPermissions, signedIPRange, protocols) + stringToSign, err := blobSASStringToSign(permissions, start, expiry, canonicalizedResource, options.Identifier, options.IP, protocols, c.apiVersion, headers) if err != nil { return "", err } - sig := b.Container.bsc.client.computeHmac256(stringToSign) + sig := c.computeHmac256(stringToSign) sasParams := url.Values{ - "sv": {b.Container.bsc.client.apiVersion}, - "se": {signedExpiry}, + "sv": {c.apiVersion}, + "se": {expiry}, "sr": {signedResource}, - "sp": {signedPermissions}, + "sp": {permissions}, "sig": {sig}, } - if b.Container.bsc.client.apiVersion >= "2015-04-05" { - sasParams.Add("spr", protocols) - if signedIPRange != "" { - sasParams.Add("sip", signedIPRange) + if start != "" { + sasParams.Add("st", start) + } + + if c.apiVersion >= "2015-04-05" { + if protocols != "" { + sasParams.Add("spr", protocols) + } + if options.IP != "" { + sasParams.Add("sip", options.IP) } } - sasURL, err := url.Parse(blobURL) + // Add override response hedaers + addQueryParameter(sasParams, "rscc", headers.CacheControl) + addQueryParameter(sasParams, "rscd", headers.ContentDisposition) + addQueryParameter(sasParams, "rsce", headers.ContentEncoding) + addQueryParameter(sasParams, "rscl", headers.ContentLanguage) + addQueryParameter(sasParams, "rsct", headers.ContentType) + + sasURL, err := url.Parse(uri) if err != nil { return "", err } @@ -77,16 +149,12 @@ func (b *Blob) GetSASURIWithSignedIPAndProtocol(expiry time.Time, permissions st return sasURL.String(), nil } -// GetSASURI creates an URL to the specified blob which contains the Shared -// Access Signature with specified permissions and expiration time. -// -// See https://msdn.microsoft.com/en-us/library/azure/ee395415.aspx -func (b *Blob) GetSASURI(expiry time.Time, permissions string) (string, error) { - return b.GetSASURIWithSignedIPAndProtocol(expiry, permissions, "", false) -} - -func blobSASStringToSign(signedVersion, canonicalizedResource, signedExpiry, signedPermissions string, signedIP string, protocols string) (string, error) { - var signedStart, signedIdentifier, rscc, rscd, rsce, rscl, rsct string +func blobSASStringToSign(signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedIP, protocols, signedVersion string, headers OverrideHeaders) (string, error) { + rscc := headers.CacheControl + rscd := headers.ContentDisposition + rsce := headers.ContentEncoding + rscl := headers.ContentLanguage + rsct := headers.ContentType if signedVersion >= "2015-02-21" { canonicalizedResource = "/blob" + canonicalizedResource diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/blobserviceclient.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/blobserviceclient.go index 450b20f96..02fa5929c 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/blobserviceclient.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/blobserviceclient.go @@ -1,9 +1,26 @@ package storage +// 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/xml" + "fmt" "net/http" "net/url" "strconv" + "strings" ) // BlobStorageClient contains operations for Microsoft Azure Blob Storage @@ -45,6 +62,25 @@ func (b *BlobStorageClient) GetContainerReference(name string) *Container { } } +// GetContainerReferenceFromSASURI returns a Container object for the specified +// container SASURI +func GetContainerReferenceFromSASURI(sasuri url.URL) (*Container, error) { + path := strings.Split(sasuri.Path, "/") + if len(path) <= 1 { + return nil, fmt.Errorf("could not find a container in URI: %s", sasuri.String()) + } + c, err := newSASClientFromURL(&sasuri) + if err != nil { + return nil, err + } + cli := c.GetBlobService() + return &Container{ + bsc: &cli, + Name: path[1], + sasuri: sasuri, + }, nil +} + // ListContainers returns the list of containers in a storage account along with // pagination token and other response details. // @@ -54,21 +90,53 @@ func (b BlobStorageClient) ListContainers(params ListContainersParameters) (*Con uri := b.client.getEndpoint(blobServiceName, "", q) headers := b.client.getStandardHeaders() - var out ContainerListResponse + type ContainerAlias struct { + bsc *BlobStorageClient + Name string `xml:"Name"` + Properties ContainerProperties `xml:"Properties"` + Metadata BlobMetadata + sasuri url.URL + } + type ContainerListResponseAlias struct { + XMLName xml.Name `xml:"EnumerationResults"` + Xmlns string `xml:"xmlns,attr"` + Prefix string `xml:"Prefix"` + Marker string `xml:"Marker"` + NextMarker string `xml:"NextMarker"` + MaxResults int64 `xml:"MaxResults"` + Containers []ContainerAlias `xml:"Containers>Container"` + } + + var outAlias ContainerListResponseAlias resp, err := b.client.exec(http.MethodGet, uri, headers, nil, b.auth) if err != nil { return nil, err } - defer resp.body.Close() - err = xmlUnmarshal(resp.body, &out) + defer resp.Body.Close() + err = xmlUnmarshal(resp.Body, &outAlias) if err != nil { return nil, err } - // assign our client to the newly created Container objects - for i := range out.Containers { - out.Containers[i].bsc = &b + out := ContainerListResponse{ + XMLName: outAlias.XMLName, + Xmlns: outAlias.Xmlns, + Prefix: outAlias.Prefix, + Marker: outAlias.Marker, + NextMarker: outAlias.NextMarker, + MaxResults: outAlias.MaxResults, + Containers: make([]Container, len(outAlias.Containers)), } + for i, cnt := range outAlias.Containers { + out.Containers[i] = Container{ + bsc: &b, + Name: cnt.Name, + Properties: cnt.Properties, + Metadata: map[string]string(cnt.Metadata), + sasuri: cnt.sasuri, + } + } + return &out, err } @@ -93,3 +161,26 @@ func (p ListContainersParameters) getParameters() url.Values { return out } + +func writeMetadata(h http.Header) map[string]string { + metadata := make(map[string]string) + for k, v := range h { + // Can't trust CanonicalHeaderKey() to munge case + // reliably. "_" is allowed in identifiers: + // https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx + // https://msdn.microsoft.com/library/aa664670(VS.71).aspx + // http://tools.ietf.org/html/rfc7230#section-3.2 + // ...but "_" is considered invalid by + // CanonicalMIMEHeaderKey in + // https://golang.org/src/net/textproto/reader.go?s=14615:14659#L542 + // so k can be "X-Ms-Meta-Lol" or "x-ms-meta-lol_rofl". + k = strings.ToLower(k) + if len(v) == 0 || !strings.HasPrefix(k, strings.ToLower(userDefinedMetadataHeaderPrefix)) { + continue + } + // metadata["lol"] = content of the last X-Ms-Meta-Lol header + k = k[len(userDefinedMetadataHeaderPrefix):] + metadata[k] = v[len(v)-1] + } + return metadata +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/blockblob.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/blockblob.go index 5258f24fd..c9c62d799 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/blockblob.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/blockblob.go @@ -1,5 +1,19 @@ package storage +// 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/xml" @@ -132,8 +146,7 @@ func (b *Blob) CreateBlockBlobFromReader(blob io.Reader, options *PutBlobOptions if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + return b.respondCreation(resp, BlobTypeBlock) } // PutBlockOptions includes the options for a put block operation @@ -181,8 +194,7 @@ func (b *Blob) PutBlockWithLength(blockID string, size uint64, blob io.Reader, o if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + return b.respondCreation(resp, BlobTypeBlock) } // PutBlockListOptions includes the options for a put block list operation @@ -217,8 +229,8 @@ func (b *Blob) PutBlockList(blocks []Block, options *PutBlockListOptions) error if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusCreated}) } // GetBlockListOptions includes the options for a get block list operation @@ -251,8 +263,8 @@ func (b *Blob) GetBlockList(blockType BlockListType, options *GetBlockListOption if err != nil { return out, err } - defer resp.body.Close() + defer resp.Body.Close() - err = xmlUnmarshal(resp.body, &out) + err = xmlUnmarshal(resp.Body, &out) return out, err } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/client.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/client.go index 42fa702f6..427558b5d 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/client.go @@ -1,9 +1,22 @@ // Package storage provides clients for Microsoft Azure Storage Services. package storage +// 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 ( "bufio" - "bytes" "encoding/base64" "encoding/json" "encoding/xml" @@ -17,9 +30,11 @@ import ( "net/url" "regexp" "runtime" + "strconv" "strings" "time" + "github.com/Azure/azure-sdk-for-go/version" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" ) @@ -33,7 +48,9 @@ const ( // basic client is created. DefaultAPIVersion = "2016-05-31" - defaultUseHTTPS = true + defaultUseHTTPS = true + defaultRetryAttempts = 5 + defaultRetryDuration = time.Second * 5 // StorageEmulatorAccountName is the fixed storage account used by Azure Storage Emulator StorageEmulatorAccountName = "devstoreaccount1" @@ -53,10 +70,28 @@ const ( userAgentHeader = "User-Agent" userDefinedMetadataHeaderPrefix = "x-ms-meta-" + + connectionStringAccountName = "accountname" + connectionStringAccountKey = "accountkey" + connectionStringEndpointSuffix = "endpointsuffix" + connectionStringEndpointProtocol = "defaultendpointsprotocol" + + connectionStringBlobEndpoint = "blobendpoint" + connectionStringFileEndpoint = "fileendpoint" + connectionStringQueueEndpoint = "queueendpoint" + connectionStringTableEndpoint = "tableendpoint" + connectionStringSAS = "sharedaccesssignature" ) var ( - validStorageAccount = regexp.MustCompile("^[0-9a-z]{3,24}$") + validStorageAccount = regexp.MustCompile("^[0-9a-z]{3,24}$") + defaultValidStatusCodes = []int{ + http.StatusRequestTimeout, // 408 + http.StatusInternalServerError, // 500 + http.StatusBadGateway, // 502 + http.StatusServiceUnavailable, // 503 + http.StatusGatewayTimeout, // 504 + } ) // Sender sends a request @@ -85,6 +120,7 @@ func (ds *DefaultSender) Send(c *Client, req *http.Request) (resp *http.Response if err != nil || !autorest.ResponseHasStatusCode(resp, ds.ValidStatusCodes...) { return resp, err } + drainRespBody(resp) autorest.DelayForBackoff(ds.RetryDuration, attempts, req.Cancel) ds.attempts = attempts } @@ -112,16 +148,12 @@ type Client struct { baseURL string apiVersion string userAgent string -} - -type storageResponse struct { - statusCode int - headers http.Header - body io.ReadCloser + sasClient bool + accountSASToken url.Values } type odataResponse struct { - storageResponse + resp *http.Response odata odataErrorWrapper } @@ -161,6 +193,7 @@ type odataErrorWrapper struct { type UnexpectedStatusCodeError struct { allowed []int got int + inner error } func (e UnexpectedStatusCodeError) Error() string { @@ -171,7 +204,7 @@ func (e UnexpectedStatusCodeError) Error() string { for _, v := range e.allowed { expected = append(expected, s(v)) } - return fmt.Sprintf("storage: status code from service response is %s; was expecting %s", got, strings.Join(expected, " or ")) + return fmt.Sprintf("storage: status code from service response is %s; was expecting %s. Inner error: %+v", got, strings.Join(expected, " or "), e.inner) } // Got is the actual status code returned by Azure. @@ -179,6 +212,60 @@ func (e UnexpectedStatusCodeError) Got() int { return e.got } +// Inner returns any inner error info. +func (e UnexpectedStatusCodeError) Inner() error { + return e.inner +} + +// NewClientFromConnectionString creates a Client from the connection string. +func NewClientFromConnectionString(input string) (Client, error) { + // build a map of connection string key/value pairs + parts := map[string]string{} + for _, pair := range strings.Split(input, ";") { + if pair == "" { + continue + } + + equalDex := strings.IndexByte(pair, '=') + if equalDex <= 0 { + return Client{}, fmt.Errorf("Invalid connection segment %q", pair) + } + + value := strings.TrimSpace(pair[equalDex+1:]) + key := strings.TrimSpace(strings.ToLower(pair[:equalDex])) + parts[key] = value + } + + // TODO: validate parameter sets? + + if parts[connectionStringAccountName] == StorageEmulatorAccountName { + return NewEmulatorClient() + } + + if parts[connectionStringSAS] != "" { + endpoint := "" + if parts[connectionStringBlobEndpoint] != "" { + endpoint = parts[connectionStringBlobEndpoint] + } else if parts[connectionStringFileEndpoint] != "" { + endpoint = parts[connectionStringFileEndpoint] + } else if parts[connectionStringQueueEndpoint] != "" { + endpoint = parts[connectionStringQueueEndpoint] + } else { + endpoint = parts[connectionStringTableEndpoint] + } + + return NewAccountSASClientFromEndpointToken(endpoint, parts[connectionStringSAS]) + } + + useHTTPS := defaultUseHTTPS + if parts[connectionStringEndpointProtocol] != "" { + useHTTPS = parts[connectionStringEndpointProtocol] == "https" + } + + return NewClient(parts[connectionStringAccountName], parts[connectionStringAccountKey], + parts[connectionStringEndpointSuffix], DefaultAPIVersion, useHTTPS) +} + // NewBasicClient constructs a Client with given storage service name and // key. func NewBasicClient(accountName, accountKey string) (Client, error) { @@ -206,13 +293,13 @@ func NewEmulatorClient() (Client, error) { // NewClient constructs a Client. This should be used if the caller wants // to specify whether to use HTTPS, a specific REST API version or a custom // storage endpoint than Azure Public Cloud. -func NewClient(accountName, accountKey, blobServiceBaseURL, apiVersion string, useHTTPS bool) (Client, error) { +func NewClient(accountName, accountKey, serviceBaseURL, apiVersion string, useHTTPS bool) (Client, error) { var c Client if !IsValidStorageAccount(accountName) { return c, fmt.Errorf("azure: account name is not valid: it must be between 3 and 24 characters, and only may contain numbers and lowercase letters: %v", accountName) } else if accountKey == "" { return c, fmt.Errorf("azure: account key required") - } else if blobServiceBaseURL == "" { + } else if serviceBaseURL == "" { return c, fmt.Errorf("azure: base storage service url required") } @@ -226,19 +313,14 @@ func NewClient(accountName, accountKey, blobServiceBaseURL, apiVersion string, u accountName: accountName, accountKey: key, useHTTPS: useHTTPS, - baseURL: blobServiceBaseURL, + baseURL: serviceBaseURL, apiVersion: apiVersion, + sasClient: false, UseSharedKeyLite: false, Sender: &DefaultSender{ - RetryAttempts: 5, - ValidStatusCodes: []int{ - http.StatusRequestTimeout, // 408 - http.StatusInternalServerError, // 500 - http.StatusBadGateway, // 502 - http.StatusServiceUnavailable, // 503 - http.StatusGatewayTimeout, // 504 - }, - RetryDuration: time.Second * 5, + RetryAttempts: defaultRetryAttempts, + ValidStatusCodes: defaultValidStatusCodes, + RetryDuration: defaultRetryDuration, }, } c.userAgent = c.getDefaultUserAgent() @@ -251,12 +333,89 @@ func IsValidStorageAccount(account string) bool { return validStorageAccount.MatchString(account) } +// NewAccountSASClient contructs a client that uses accountSAS authorization +// for its operations. +func NewAccountSASClient(account string, token url.Values, env azure.Environment) Client { + return newSASClient(account, env.StorageEndpointSuffix, token) +} + +// NewAccountSASClientFromEndpointToken constructs a client that uses accountSAS authorization +// for its operations using the specified endpoint and SAS token. +func NewAccountSASClientFromEndpointToken(endpoint string, sasToken string) (Client, error) { + u, err := url.Parse(endpoint) + if err != nil { + return Client{}, err + } + _, err = url.ParseQuery(sasToken) + if err != nil { + return Client{}, err + } + u.RawQuery = sasToken + return newSASClientFromURL(u) +} + +func newSASClient(accountName, baseURL string, sasToken url.Values) Client { + c := Client{ + HTTPClient: http.DefaultClient, + apiVersion: DefaultAPIVersion, + sasClient: true, + Sender: &DefaultSender{ + RetryAttempts: defaultRetryAttempts, + ValidStatusCodes: defaultValidStatusCodes, + RetryDuration: defaultRetryDuration, + }, + accountName: accountName, + baseURL: baseURL, + accountSASToken: sasToken, + } + c.userAgent = c.getDefaultUserAgent() + // Get API version and protocol from token + c.apiVersion = sasToken.Get("sv") + c.useHTTPS = sasToken.Get("spr") == "https" + return c +} + +func newSASClientFromURL(u *url.URL) (Client, error) { + // the host name will look something like this + // - foo.blob.core.windows.net + // "foo" is the account name + // "core.windows.net" is the baseURL + + // find the first dot to get account name + i1 := strings.IndexByte(u.Host, '.') + if i1 < 0 { + return Client{}, fmt.Errorf("failed to find '.' in %s", u.Host) + } + + // now find the second dot to get the base URL + i2 := strings.IndexByte(u.Host[i1+1:], '.') + if i2 < 0 { + return Client{}, fmt.Errorf("failed to find '.' in %s", u.Host[i1+1:]) + } + + sasToken := u.Query() + c := newSASClient(u.Host[:i1], u.Host[i1+i2+2:], sasToken) + if spr := sasToken.Get("spr"); spr == "" { + // infer from URL if not in the query params set + c.useHTTPS = u.Scheme == "https" + } + return c, nil +} + +func (c Client) isServiceSASClient() bool { + return c.sasClient && c.accountSASToken == nil +} + +func (c Client) isAccountSASClient() bool { + return c.sasClient && c.accountSASToken != nil +} + func (c Client) getDefaultUserAgent() string { return fmt.Sprintf("Go/%s (%s-%s) azure-storage-go/%s api-version/%s", runtime.Version(), runtime.GOARCH, runtime.GOOS, - sdkVersion, + version.Number, c.apiVersion, ) } @@ -323,6 +482,160 @@ func (c Client) getEndpoint(service, path string, params url.Values) string { return u.String() } +// AccountSASTokenOptions includes options for constructing +// an account SAS token. +// https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas +type AccountSASTokenOptions struct { + APIVersion string + Services Services + ResourceTypes ResourceTypes + Permissions Permissions + Start time.Time + Expiry time.Time + IP string + UseHTTPS bool +} + +// Services specify services accessible with an account SAS. +type Services struct { + Blob bool + Queue bool + Table bool + File bool +} + +// ResourceTypes specify the resources accesible with an +// account SAS. +type ResourceTypes struct { + Service bool + Container bool + Object bool +} + +// Permissions specifies permissions for an accountSAS. +type Permissions struct { + Read bool + Write bool + Delete bool + List bool + Add bool + Create bool + Update bool + Process bool +} + +// GetAccountSASToken creates an account SAS token +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas +func (c Client) GetAccountSASToken(options AccountSASTokenOptions) (url.Values, error) { + if options.APIVersion == "" { + options.APIVersion = c.apiVersion + } + + if options.APIVersion < "2015-04-05" { + return url.Values{}, fmt.Errorf("account SAS does not support API versions prior to 2015-04-05. API version : %s", options.APIVersion) + } + + // build services string + services := "" + if options.Services.Blob { + services += "b" + } + if options.Services.Queue { + services += "q" + } + if options.Services.Table { + services += "t" + } + if options.Services.File { + services += "f" + } + + // build resources string + resources := "" + if options.ResourceTypes.Service { + resources += "s" + } + if options.ResourceTypes.Container { + resources += "c" + } + if options.ResourceTypes.Object { + resources += "o" + } + + // build permissions string + permissions := "" + if options.Permissions.Read { + permissions += "r" + } + if options.Permissions.Write { + permissions += "w" + } + if options.Permissions.Delete { + permissions += "d" + } + if options.Permissions.List { + permissions += "l" + } + if options.Permissions.Add { + permissions += "a" + } + if options.Permissions.Create { + permissions += "c" + } + if options.Permissions.Update { + permissions += "u" + } + if options.Permissions.Process { + permissions += "p" + } + + // build start time, if exists + start := "" + if options.Start != (time.Time{}) { + start = options.Start.UTC().Format(time.RFC3339) + } + + // build expiry time + expiry := options.Expiry.UTC().Format(time.RFC3339) + + protocol := "https,http" + if options.UseHTTPS { + protocol = "https" + } + + stringToSign := strings.Join([]string{ + c.accountName, + permissions, + services, + resources, + start, + expiry, + options.IP, + protocol, + options.APIVersion, + "", + }, "\n") + signature := c.computeHmac256(stringToSign) + + sasParams := url.Values{ + "sv": {options.APIVersion}, + "ss": {services}, + "srt": {resources}, + "sp": {permissions}, + "se": {expiry}, + "spr": {protocol}, + "sig": {signature}, + } + if start != "" { + sasParams.Add("st", start) + } + if options.IP != "" { + sasParams.Add("sip", options.IP) + } + + return sasParams, nil +} + // GetBlobService returns a BlobStorageClient which can operate on the blob // service of the storage account. func (c Client) GetBlobService() BlobStorageClient { @@ -387,7 +700,7 @@ func (c Client) getStandardHeaders() map[string]string { } } -func (c Client) exec(verb, url string, headers map[string]string, body io.Reader, auth authentication) (*storageResponse, error) { +func (c Client) exec(verb, url string, headers map[string]string, body io.Reader, auth authentication) (*http.Response, error) { headers, err := c.addAuthorizationHeader(verb, url, headers, auth) if err != nil { return nil, err @@ -398,12 +711,13 @@ func (c Client) exec(verb, url string, headers map[string]string, body io.Reader return nil, errors.New("azure/storage: error creating request: " + err.Error()) } - // if a body was provided ensure that the content length was set. - // http.NewRequest() will automatically do this for a handful of types - // and for those that it doesn't we will handle here. - if body != nil && req.ContentLength < 1 { - if lr, ok := body.(*io.LimitedReader); ok { - setContentLengthFromLimitedReader(req, lr) + // http.NewRequest() will automatically set req.ContentLength for a handful of types + // otherwise we will handle here. + if req.ContentLength < 1 { + if clstr, ok := headers["Content-Length"]; ok { + if cl, err := strconv.ParseInt(clstr, 10, 64); err == nil { + req.ContentLength = cl + } } } @@ -411,54 +725,23 @@ func (c Client) exec(verb, url string, headers map[string]string, body io.Reader req.Header[k] = append(req.Header[k], v) // Must bypass case munging present in `Add` by using map functions directly. See https://github.com/Azure/azure-sdk-for-go/issues/645 } + if c.isAccountSASClient() { + // append the SAS token to the query params + v := req.URL.Query() + v = mergeParams(v, c.accountSASToken) + req.URL.RawQuery = v.Encode() + } + resp, err := c.Sender.Send(&c, req) if err != nil { return nil, err } if resp.StatusCode >= 400 && resp.StatusCode <= 505 { - var respBody []byte - respBody, err = readAndCloseBody(resp.Body) - if err != nil { - return nil, err - } - - requestID, date, version := getDebugHeaders(resp.Header) - if len(respBody) == 0 { - // no error in response body, might happen in HEAD requests - err = serviceErrFromStatusCode(resp.StatusCode, resp.Status, requestID, date, version) - } else { - storageErr := AzureStorageServiceError{ - StatusCode: resp.StatusCode, - RequestID: requestID, - Date: date, - APIVersion: version, - } - // response contains storage service error object, unmarshal - if resp.Header.Get("Content-Type") == "application/xml" { - errIn := serviceErrFromXML(respBody, &storageErr) - if err != nil { // error unmarshaling the error response - err = errIn - } - } else { - errIn := serviceErrFromJSON(respBody, &storageErr) - if err != nil { // error unmarshaling the error response - err = errIn - } - } - err = storageErr - } - return &storageResponse{ - statusCode: resp.StatusCode, - headers: resp.Header, - body: ioutil.NopCloser(bytes.NewReader(respBody)), /* restore the body */ - }, err + return resp, getErrorFromResponse(resp) } - return &storageResponse{ - statusCode: resp.StatusCode, - headers: resp.Header, - body: resp.Body}, nil + return resp, nil } func (c Client) execInternalJSONCommon(verb, url string, headers map[string]string, body io.Reader, auth authentication) (*odataResponse, *http.Request, *http.Response, error) { @@ -477,10 +760,7 @@ func (c Client) execInternalJSONCommon(verb, url string, headers map[string]stri return nil, nil, nil, err } - respToRet := &odataResponse{} - respToRet.body = resp.Body - respToRet.statusCode = resp.StatusCode - respToRet.headers = resp.Header + respToRet := &odataResponse{resp: resp} statusCode := resp.StatusCode if statusCode >= 400 && statusCode <= 505 { @@ -565,7 +845,7 @@ func genChangesetReader(req *http.Request, respToRet *odataResponse, batchPartBu if err != nil { return err } - respToRet.statusCode = changesetResp.StatusCode + respToRet.resp = changesetResp } return nil @@ -600,6 +880,12 @@ func readAndCloseBody(body io.ReadCloser) ([]byte, error) { return out, err } +// reads the response body then closes it +func drainRespBody(resp *http.Response) { + io.Copy(ioutil.Discard, resp.Body) + resp.Body.Close() +} + func serviceErrFromXML(body []byte, storageErr *AzureStorageServiceError) error { if err := xml.Unmarshal(body, storageErr); err != nil { storageErr.Message = fmt.Sprintf("Response body could no be unmarshaled: %v. Body: %v.", err, string(body)) @@ -638,13 +924,18 @@ func (e AzureStorageServiceError) Error() string { // checkRespCode returns UnexpectedStatusError if the given response code is not // one of the allowed status codes; otherwise nil. -func checkRespCode(respCode int, allowed []int) error { +func checkRespCode(resp *http.Response, allowed []int) error { for _, v := range allowed { - if respCode == v { + if resp.StatusCode == v { return nil } } - return UnexpectedStatusCodeError{allowed, respCode} + err := getErrorFromResponse(resp) + return UnexpectedStatusCodeError{ + allowed: allowed, + got: resp.StatusCode, + inner: err, + } } func (c Client) addMetadataToHeaders(h map[string]string, metadata map[string]string) map[string]string { @@ -661,3 +952,37 @@ func getDebugHeaders(h http.Header) (requestID, date, version string) { date = h.Get("Date") return } + +func getErrorFromResponse(resp *http.Response) error { + respBody, err := readAndCloseBody(resp.Body) + if err != nil { + return err + } + + requestID, date, version := getDebugHeaders(resp.Header) + if len(respBody) == 0 { + // no error in response body, might happen in HEAD requests + err = serviceErrFromStatusCode(resp.StatusCode, resp.Status, requestID, date, version) + } else { + storageErr := AzureStorageServiceError{ + StatusCode: resp.StatusCode, + RequestID: requestID, + Date: date, + APIVersion: version, + } + // response contains storage service error object, unmarshal + if resp.Header.Get("Content-Type") == "application/xml" { + errIn := serviceErrFromXML(respBody, &storageErr) + if err != nil { // error unmarshaling the error response + err = errIn + } + } else { + errIn := serviceErrFromJSON(respBody, &storageErr) + if err != nil { // error unmarshaling the error response + err = errIn + } + } + err = storageErr + } + return err +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/commonsasuri.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/commonsasuri.go new file mode 100644 index 000000000..e898e9bfa --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/commonsasuri.go @@ -0,0 +1,38 @@ +package storage + +// 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/url" + "time" +) + +// SASOptions includes options used by SAS URIs for different +// services and resources. +type SASOptions struct { + APIVersion string + Start time.Time + Expiry time.Time + IP string + UseHTTPS bool + Identifier string +} + +func addQueryParameter(query url.Values, key, value string) url.Values { + if value != "" { + query.Add(key, value) + } + return query +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/container.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/container.go index c2c9c055b..056473d49 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/container.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/container.go @@ -1,8 +1,21 @@ package storage +// 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/xml" - "errors" "fmt" "io" "net/http" @@ -18,20 +31,75 @@ type Container struct { Name string `xml:"Name"` Properties ContainerProperties `xml:"Properties"` Metadata map[string]string + sasuri url.URL +} + +// Client returns the HTTP client used by the Container reference. +func (c *Container) Client() *Client { + return &c.bsc.client } func (c *Container) buildPath() string { return fmt.Sprintf("/%s", c.Name) } +// GetURL gets the canonical URL to the container. +// This method does not create a publicly accessible URL if the container +// is private and this method does not check if the blob exists. +func (c *Container) GetURL() string { + container := c.Name + if container == "" { + container = "$root" + } + return c.bsc.client.getEndpoint(blobServiceName, pathForResource(container, ""), nil) +} + +// ContainerSASOptions are options to construct a container SAS +// URI. +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas +type ContainerSASOptions struct { + ContainerSASPermissions + OverrideHeaders + SASOptions +} + +// ContainerSASPermissions includes the available permissions for +// a container SAS URI. +type ContainerSASPermissions struct { + BlobServiceSASPermissions + List bool +} + +// GetSASURI creates an URL to the container which contains the Shared +// Access Signature with the specified options. +// +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas +func (c *Container) GetSASURI(options ContainerSASOptions) (string, error) { + uri := c.GetURL() + signedResource := "c" + canonicalizedResource, err := c.bsc.client.buildCanonicalizedResource(uri, c.bsc.auth, true) + if err != nil { + return "", err + } + + // build permissions string + permissions := options.BlobServiceSASPermissions.buildString() + if options.List { + permissions += "l" + } + + return c.bsc.client.blobAndFileSASURI(options.SASOptions, uri, permissions, canonicalizedResource, signedResource, options.OverrideHeaders) +} + // ContainerProperties contains various properties of a container returned from // various endpoints like ListContainers. type ContainerProperties struct { - LastModified string `xml:"Last-Modified"` - Etag string `xml:"Etag"` - LeaseStatus string `xml:"LeaseStatus"` - LeaseState string `xml:"LeaseState"` - LeaseDuration string `xml:"LeaseDuration"` + LastModified string `xml:"Last-Modified"` + Etag string `xml:"Etag"` + LeaseStatus string `xml:"LeaseStatus"` + LeaseState string `xml:"LeaseState"` + LeaseDuration string `xml:"LeaseDuration"` + PublicAccess ContainerAccessType `xml:"PublicAccess"` } // ContainerListResponse contains the response fields from @@ -190,8 +258,8 @@ func (c *Container) Create(options *CreateContainerOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusCreated}) } // CreateIfNotExists creates a blob container if it does not exist. Returns @@ -199,15 +267,15 @@ func (c *Container) Create(options *CreateContainerOptions) error { func (c *Container) CreateIfNotExists(options *CreateContainerOptions) (bool, error) { resp, err := c.create(options) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict { - return resp.statusCode == http.StatusCreated, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusConflict { + return resp.StatusCode == http.StatusCreated, nil } } return false, err } -func (c *Container) create(options *CreateContainerOptions) (*storageResponse, error) { +func (c *Container) create(options *CreateContainerOptions) (*http.Response, error) { query := url.Values{"restype": {"container"}} headers := c.bsc.client.getStandardHeaders() headers = c.bsc.client.addMetadataToHeaders(headers, c.Metadata) @@ -224,14 +292,24 @@ func (c *Container) create(options *CreateContainerOptions) (*storageResponse, e // Exists returns true if a container with given name exists // on the storage account, otherwise returns false. func (c *Container) Exists() (bool, error) { - uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), url.Values{"restype": {"container"}}) + q := url.Values{"restype": {"container"}} + var uri string + if c.bsc.client.isServiceSASClient() { + q = mergeParams(q, c.sasuri.Query()) + newURI := c.sasuri + newURI.RawQuery = q.Encode() + uri = newURI.String() + + } else { + uri = c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), q) + } headers := c.bsc.client.getStandardHeaders() resp, err := c.bsc.client.exec(http.MethodHead, uri, headers, nil, c.bsc.auth) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusOK, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotFound { + return resp.StatusCode == http.StatusOK, nil } } return false, err @@ -271,13 +349,8 @@ func (c *Container) SetPermissions(permissions ContainerPermissions, options *Se if err != nil { return err } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - return errors.New("Unable to set permissions") - } - - return nil + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusOK}) } // GetContainerPermissionOptions includes options for a get container permissions operation @@ -307,14 +380,14 @@ func (c *Container) GetPermissions(options *GetContainerPermissionOptions) (*Con if err != nil { return nil, err } - defer resp.body.Close() + defer resp.Body.Close() var ap AccessPolicy - err = xmlUnmarshal(resp.body, &ap.SignedIdentifiersList) + err = xmlUnmarshal(resp.Body, &ap.SignedIdentifiersList) if err != nil { return nil, err } - return buildAccessPolicy(ap, &resp.headers), nil + return buildAccessPolicy(ap, &resp.Header), nil } func buildAccessPolicy(ap AccessPolicy, headers *http.Header) *ContainerPermissions { @@ -358,8 +431,8 @@ func (c *Container) Delete(options *DeleteContainerOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusAccepted}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusAccepted}) } // DeleteIfExists deletes the container with given name on the storage @@ -371,15 +444,15 @@ func (c *Container) Delete(options *DeleteContainerOptions) error { func (c *Container) DeleteIfExists(options *DeleteContainerOptions) (bool, error) { resp, err := c.delete(options) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound { + return resp.StatusCode == http.StatusAccepted, nil } } return false, err } -func (c *Container) delete(options *DeleteContainerOptions) (*storageResponse, error) { +func (c *Container) delete(options *DeleteContainerOptions) (*http.Response, error) { query := url.Values{"restype": {"container"}} headers := c.bsc.client.getStandardHeaders() @@ -399,9 +472,17 @@ func (c *Container) delete(options *DeleteContainerOptions) (*storageResponse, e func (c *Container) ListBlobs(params ListBlobsParameters) (BlobListResponse, error) { q := mergeParams(params.getParameters(), url.Values{ "restype": {"container"}, - "comp": {"list"}}, - ) - uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), q) + "comp": {"list"}, + }) + var uri string + if c.bsc.client.isServiceSASClient() { + q = mergeParams(q, c.sasuri.Query()) + newURI := c.sasuri + newURI.RawQuery = q.Encode() + uri = newURI.String() + } else { + uri = c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), q) + } headers := c.bsc.client.getStandardHeaders() headers = addToHeaders(headers, "x-ms-client-request-id", params.RequestID) @@ -411,15 +492,90 @@ func (c *Container) ListBlobs(params ListBlobsParameters) (BlobListResponse, err if err != nil { return out, err } - defer resp.body.Close() + defer resp.Body.Close() - err = xmlUnmarshal(resp.body, &out) + err = xmlUnmarshal(resp.Body, &out) for i := range out.Blobs { out.Blobs[i].Container = c } return out, err } +// ContainerMetadataOptions includes options for container metadata operations +type ContainerMetadataOptions struct { + Timeout uint + LeaseID string `header:"x-ms-lease-id"` + RequestID string `header:"x-ms-client-request-id"` +} + +// SetMetadata replaces the metadata for the specified container. +// +// Some keys may be converted to Camel-Case before sending. All keys +// are returned in lower case by GetBlobMetadata. HTTP header names +// are case-insensitive so case munging should not matter to other +// applications either. +// +// See https://docs.microsoft.com/en-us/rest/api/storageservices/set-container-metadata +func (c *Container) SetMetadata(options *ContainerMetadataOptions) error { + params := url.Values{ + "comp": {"metadata"}, + "restype": {"container"}, + } + headers := c.bsc.client.getStandardHeaders() + headers = c.bsc.client.addMetadataToHeaders(headers, c.Metadata) + + if options != nil { + params = addTimeout(params, options.Timeout) + headers = mergeHeaders(headers, headersFromStruct(*options)) + } + + uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), params) + + resp, err := c.bsc.client.exec(http.MethodPut, uri, headers, nil, c.bsc.auth) + if err != nil { + return err + } + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusOK}) +} + +// GetMetadata returns all user-defined metadata for the specified container. +// +// All metadata keys will be returned in lower case. (HTTP header +// names are case-insensitive.) +// +// See https://docs.microsoft.com/en-us/rest/api/storageservices/get-container-metadata +func (c *Container) GetMetadata(options *ContainerMetadataOptions) error { + params := url.Values{ + "comp": {"metadata"}, + "restype": {"container"}, + } + headers := c.bsc.client.getStandardHeaders() + + if options != nil { + params = addTimeout(params, options.Timeout) + headers = mergeHeaders(headers, headersFromStruct(*options)) + } + + uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), params) + + resp, err := c.bsc.client.exec(http.MethodGet, uri, headers, nil, c.bsc.auth) + if err != nil { + return err + } + defer drainRespBody(resp) + if err := checkRespCode(resp, []int{http.StatusOK}); err != nil { + return err + } + + c.writeMetadata(resp.Header) + return nil +} + +func (c *Container) writeMetadata(h http.Header) { + c.Metadata = writeMetadata(h) +} + func generateContainerACLpayload(policies []ContainerAccessPolicy) (io.Reader, int, error) { sil := SignedIdentifiers{ SignedIdentifiers: []SignedIdentifier{}, @@ -451,3 +607,34 @@ func (capd *ContainerAccessPolicy) generateContainerPermissions() (permissions s return permissions } + +// GetProperties updated the properties of the container. +// +// See https://docs.microsoft.com/en-us/rest/api/storageservices/get-container-properties +func (c *Container) GetProperties() error { + params := url.Values{ + "restype": {"container"}, + } + headers := c.bsc.client.getStandardHeaders() + + uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), params) + + resp, err := c.bsc.client.exec(http.MethodGet, uri, headers, nil, c.bsc.auth) + if err != nil { + return err + } + defer resp.Body.Close() + if err := checkRespCode(resp, []int{http.StatusOK}); err != nil { + return err + } + + // update properties + c.Properties.Etag = resp.Header.Get(headerEtag) + c.Properties.LeaseStatus = resp.Header.Get("x-ms-lease-status") + c.Properties.LeaseState = resp.Header.Get("x-ms-lease-state") + c.Properties.LeaseDuration = resp.Header.Get("x-ms-lease-duration") + c.Properties.LastModified = resp.Header.Get("Last-Modified") + c.Properties.PublicAccess = ContainerAccessType(resp.Header.Get(ContainerAccessHeader)) + + return nil +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/copyblob.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/copyblob.go index f14342618..151e9a510 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/copyblob.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/copyblob.go @@ -1,5 +1,19 @@ package storage +// 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" "fmt" @@ -96,13 +110,13 @@ func (b *Blob) StartCopy(sourceBlob string, options *CopyOptions) (string, error if err != nil { return "", err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err := checkRespCode(resp.statusCode, []int{http.StatusAccepted, http.StatusCreated}); err != nil { + if err := checkRespCode(resp, []int{http.StatusAccepted, http.StatusCreated}); err != nil { return "", err } - copyID := resp.headers.Get("x-ms-copy-id") + copyID := resp.Header.Get("x-ms-copy-id") if copyID == "" { return "", errors.New("Got empty copy id header") } @@ -138,8 +152,8 @@ func (b *Blob) AbortCopy(copyID string, options *AbortCopyOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusNoContent}) } // WaitForCopy loops until a BlobCopy operation is completed (or fails with error) @@ -209,13 +223,13 @@ func (b *Blob) IncrementalCopyBlob(sourceBlobURL string, snapshotTime time.Time, if err != nil { return "", err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err := checkRespCode(resp.statusCode, []int{http.StatusAccepted}); err != nil { + if err := checkRespCode(resp, []int{http.StatusAccepted}); err != nil { return "", err } - copyID := resp.headers.Get("x-ms-copy-id") + copyID := resp.Header.Get("x-ms-copy-id") if copyID == "" { return "", errors.New("Got empty copy id header") } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/directory.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/directory.go index 57053efd1..2e805e7df 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/directory.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/directory.go @@ -1,5 +1,19 @@ package storage +// 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/xml" "net/http" @@ -93,10 +107,10 @@ func (d *Directory) CreateIfNotExists(options *FileRequestOptions) (bool, error) params := prepareOptions(options) resp, err := d.fsc.createResourceNoClose(d.buildPath(), resourceDirectory, params, nil) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict { - if resp.statusCode == http.StatusCreated { - d.updateEtagAndLastModified(resp.headers) + defer drainRespBody(resp) + if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusConflict { + if resp.StatusCode == http.StatusCreated { + d.updateEtagAndLastModified(resp.Header) return true, nil } @@ -121,9 +135,9 @@ func (d *Directory) Delete(options *FileRequestOptions) error { func (d *Directory) DeleteIfExists(options *FileRequestOptions) (bool, error) { resp, err := d.fsc.deleteResourceNoClose(d.buildPath(), resourceDirectory, options) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound { + return resp.StatusCode == http.StatusAccepted, nil } } return false, err @@ -186,9 +200,9 @@ func (d *Directory) ListDirsAndFiles(params ListDirsAndFilesParameters) (*DirsAn return nil, err } - defer resp.body.Close() + defer resp.Body.Close() var out DirsAndFilesListResponse - err = xmlUnmarshal(resp.body, &out) + err = xmlUnmarshal(resp.Body, &out) return &out, err } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/entity.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/entity.go index 13e947507..fbbcb93ba 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/entity.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/entity.go @@ -1,7 +1,22 @@ package storage +// 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/base64" "encoding/json" "errors" "fmt" @@ -12,7 +27,7 @@ import ( "strings" "time" - "github.com/satori/uuid" + "github.com/satori/go.uuid" ) // Annotating as secure for gas scanning @@ -97,13 +112,13 @@ func (e *Entity) Get(timeout uint, ml MetadataLevel, options *GetEntityOptions) if err != nil { return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err = checkRespCode(resp, []int{http.StatusOK}); err != nil { return err } - respBody, err := ioutil.ReadAll(resp.body) + respBody, err := ioutil.ReadAll(resp.Body) if err != nil { return err } @@ -139,22 +154,21 @@ func (e *Entity) Insert(ml MetadataLevel, options *EntityOptions) error { if err != nil { return err } - defer resp.body.Close() - - data, err := ioutil.ReadAll(resp.body) - if err != nil { - return err - } + defer drainRespBody(resp) if ml != EmptyPayload { - if err = checkRespCode(resp.statusCode, []int{http.StatusCreated}); err != nil { + if err = checkRespCode(resp, []int{http.StatusCreated}); err != nil { + return err + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { return err } if err = e.UnmarshalJSON(data); err != nil { return err } } else { - if err = checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { + if err = checkRespCode(resp, []int{http.StatusNoContent}); err != nil { return err } } @@ -193,18 +207,18 @@ func (e *Entity) Delete(force bool, options *EntityOptions) error { uri := e.Table.tsc.client.getEndpoint(tableServiceName, e.buildPath(), query) resp, err := e.Table.tsc.client.exec(http.MethodDelete, uri, headers, nil, e.Table.tsc.auth) if err != nil { - if resp.statusCode == http.StatusPreconditionFailed { + if resp.StatusCode == http.StatusPreconditionFailed { return fmt.Errorf(etagErrorTemplate, err) } return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err = checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { + if err = checkRespCode(resp, []int{http.StatusNoContent}); err != nil { return err } - return e.updateTimestamp(resp.headers) + return e.updateTimestamp(resp.Header) } // InsertOrReplace inserts an entity or replaces the existing one. @@ -233,7 +247,7 @@ func (e *Entity) MarshalJSON() ([]byte, error) { switch t := v.(type) { case []byte: completeMap[typeKey] = OdataBinary - completeMap[k] = string(t) + completeMap[k] = t case time.Time: completeMap[typeKey] = OdataDateTime completeMap[k] = t.Format(time.RFC3339Nano) @@ -307,7 +321,10 @@ func (e *Entity) UnmarshalJSON(data []byte) error { } switch v { case OdataBinary: - props[valueKey] = []byte(str) + props[valueKey], err = base64.StdEncoding.DecodeString(str) + if err != nil { + return fmt.Errorf(errorTemplate, err) + } case OdataDateTime: t, err := time.Parse("2006-01-02T15:04:05Z", str) if err != nil { @@ -382,13 +399,13 @@ func (e *Entity) insertOr(verb string, options *EntityOptions) error { if err != nil { return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err = checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { + if err = checkRespCode(resp, []int{http.StatusNoContent}); err != nil { return err } - return e.updateEtagAndTimestamp(resp.headers) + return e.updateEtagAndTimestamp(resp.Header) } func (e *Entity) updateMerge(force bool, verb string, options *EntityOptions) error { @@ -406,18 +423,18 @@ func (e *Entity) updateMerge(force bool, verb string, options *EntityOptions) er uri := e.Table.tsc.client.getEndpoint(tableServiceName, e.buildPath(), query) resp, err := e.Table.tsc.client.exec(verb, uri, headers, bytes.NewReader(body), e.Table.tsc.auth) if err != nil { - if resp.statusCode == http.StatusPreconditionFailed { + if resp.StatusCode == http.StatusPreconditionFailed { return fmt.Errorf(etagErrorTemplate, err) } return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err = checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { + if err = checkRespCode(resp, []int{http.StatusNoContent}); err != nil { return err } - return e.updateEtagAndTimestamp(resp.headers) + return e.updateEtagAndTimestamp(resp.Header) } func stringFromMap(props map[string]interface{}, key string) string { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/file.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/file.go index 27dbdd1fc..06bbe4ba0 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/file.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/file.go @@ -1,5 +1,19 @@ package storage +// 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" "fmt" @@ -14,6 +28,10 @@ import ( const fourMB = uint64(4194304) const oneTB = uint64(1099511627776) +// Export maximum range and file sizes +const MaxRangeSize = fourMB +const MaxFileSize = oneTB + // File represents a file on a share. type File struct { fsc *FileServiceClient @@ -169,9 +187,9 @@ func (f *File) Delete(options *FileRequestOptions) error { func (f *File) DeleteIfExists(options *FileRequestOptions) (bool, error) { resp, err := f.fsc.deleteResourceNoClose(f.buildPath(), resourceFile, options) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound { + return resp.StatusCode == http.StatusAccepted, nil } } return false, err @@ -193,11 +211,11 @@ func (f *File) DownloadToStream(options *FileRequestOptions) (io.ReadCloser, err return nil, err } - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - readAndCloseBody(resp.body) + if err = checkRespCode(resp, []int{http.StatusOK}); err != nil { + drainRespBody(resp) return nil, err } - return resp.body, nil + return resp.Body, nil } // DownloadRangeToStream operation downloads the specified range of this file with optional MD5 hash. @@ -223,14 +241,14 @@ func (f *File) DownloadRangeToStream(fileRange FileRange, options *GetFileOption return fs, err } - if err = checkRespCode(resp.statusCode, []int{http.StatusOK, http.StatusPartialContent}); err != nil { - readAndCloseBody(resp.body) + if err = checkRespCode(resp, []int{http.StatusOK, http.StatusPartialContent}); err != nil { + drainRespBody(resp) return fs, err } - fs.Body = resp.body + fs.Body = resp.Body if options != nil && options.GetContentMD5 { - fs.ContentMD5 = resp.headers.Get("Content-MD5") + fs.ContentMD5 = resp.Header.Get("Content-MD5") } return fs, nil } @@ -296,20 +314,20 @@ func (f *File) ListRanges(options *ListRangesOptions) (*FileRanges, error) { return nil, err } - defer resp.body.Close() + defer resp.Body.Close() var cl uint64 - cl, err = strconv.ParseUint(resp.headers.Get("x-ms-content-length"), 10, 64) + cl, err = strconv.ParseUint(resp.Header.Get("x-ms-content-length"), 10, 64) if err != nil { - ioutil.ReadAll(resp.body) + ioutil.ReadAll(resp.Body) return nil, err } var out FileRanges out.ContentLength = cl - out.ETag = resp.headers.Get("ETag") - out.LastModified = resp.headers.Get("Last-Modified") + out.ETag = resp.Header.Get("ETag") + out.LastModified = resp.Header.Get("Last-Modified") - err = xmlUnmarshal(resp.body, &out) + err = xmlUnmarshal(resp.Body, &out) return &out, err } @@ -357,8 +375,8 @@ func (f *File) modifyRange(bytes io.Reader, fileRange FileRange, timeout *uint, if err != nil { return nil, err } - defer readAndCloseBody(resp.body) - return resp.headers, checkRespCode(resp.statusCode, []int{http.StatusCreated}) + defer drainRespBody(resp) + return resp.Header, checkRespCode(resp, []int{http.StatusCreated}) } // SetMetadata replaces the metadata for this file. @@ -426,7 +444,7 @@ func (f *File) URL() string { return f.fsc.client.getEndpoint(fileServiceName, f.buildPath(), nil) } -// WriteRangeOptions includes opptions for a write file range operation +// WriteRangeOptions includes options for a write file range operation type WriteRangeOptions struct { Timeout uint ContentMD5 string diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/fileserviceclient.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/fileserviceclient.go index 81217bdfa..1db8e7da6 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/fileserviceclient.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/fileserviceclient.go @@ -1,5 +1,19 @@ package storage +// 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/xml" "fmt" @@ -140,8 +154,8 @@ func (f FileServiceClient) ListShares(params ListSharesParameters) (*ShareListRe if err != nil { return nil, err } - defer resp.body.Close() - err = xmlUnmarshal(resp.body, &out) + defer resp.Body.Close() + err = xmlUnmarshal(resp.Body, &out) // assign our client to the newly created Share objects for i := range out.Shares { @@ -165,7 +179,7 @@ func (f *FileServiceClient) SetServiceProperties(props ServiceProperties) error } // retrieves directory or share content -func (f FileServiceClient) listContent(path string, params url.Values, extraHeaders map[string]string) (*storageResponse, error) { +func (f FileServiceClient) listContent(path string, params url.Values, extraHeaders map[string]string) (*http.Response, error) { if err := f.checkForStorageEmulator(); err != nil { return nil, err } @@ -179,8 +193,8 @@ func (f FileServiceClient) listContent(path string, params url.Values, extraHead return nil, err } - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { - readAndCloseBody(resp.body) + if err = checkRespCode(resp, []int{http.StatusOK}); err != nil { + drainRespBody(resp) return nil, err } @@ -198,9 +212,9 @@ func (f FileServiceClient) resourceExists(path string, res resourceType) (bool, resp, err := f.client.exec(http.MethodHead, uri, headers, nil, f.auth) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusOK, resp.headers, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotFound { + return resp.StatusCode == http.StatusOK, resp.Header, nil } } return false, nil, err @@ -212,12 +226,12 @@ func (f FileServiceClient) createResource(path string, res resourceType, urlPara if err != nil { return nil, err } - defer readAndCloseBody(resp.body) - return resp.headers, checkRespCode(resp.statusCode, expectedResponseCodes) + defer drainRespBody(resp) + return resp.Header, checkRespCode(resp, expectedResponseCodes) } // creates a resource depending on the specified resource type, doesn't close the response body -func (f FileServiceClient) createResourceNoClose(path string, res resourceType, urlParams url.Values, extraHeaders map[string]string) (*storageResponse, error) { +func (f FileServiceClient) createResourceNoClose(path string, res resourceType, urlParams url.Values, extraHeaders map[string]string) (*http.Response, error) { if err := f.checkForStorageEmulator(); err != nil { return nil, err } @@ -237,17 +251,17 @@ func (f FileServiceClient) getResourceHeaders(path string, comp compType, res re if err != nil { return nil, err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err = checkRespCode(resp, []int{http.StatusOK}); err != nil { return nil, err } - return resp.headers, nil + return resp.Header, nil } // gets the specified resource, doesn't close the response body -func (f FileServiceClient) getResourceNoClose(path string, comp compType, res resourceType, params url.Values, verb string, extraHeaders map[string]string) (*storageResponse, error) { +func (f FileServiceClient) getResourceNoClose(path string, comp compType, res resourceType, params url.Values, verb string, extraHeaders map[string]string) (*http.Response, error) { if err := f.checkForStorageEmulator(); err != nil { return nil, err } @@ -265,12 +279,12 @@ func (f FileServiceClient) deleteResource(path string, res resourceType, options if err != nil { return err } - defer readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusAccepted}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusAccepted}) } // deletes the resource and returns the response, doesn't close the response body -func (f FileServiceClient) deleteResourceNoClose(path string, res resourceType, options *FileRequestOptions) (*storageResponse, error) { +func (f FileServiceClient) deleteResourceNoClose(path string, res resourceType, options *FileRequestOptions) (*http.Response, error) { if err := f.checkForStorageEmulator(); err != nil { return nil, err } @@ -309,9 +323,9 @@ func (f FileServiceClient) setResourceHeaders(path string, comp compType, res re if err != nil { return nil, err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - return resp.headers, checkRespCode(resp.statusCode, []int{http.StatusOK}) + return resp.Header, checkRespCode(resp, []int{http.StatusOK}) } //checkForStorageEmulator determines if the client is setup for use with diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/leaseblob.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/leaseblob.go index 415b74018..5b4a65145 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/leaseblob.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/leaseblob.go @@ -1,5 +1,19 @@ package storage +// 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" "net/http" @@ -39,13 +53,13 @@ func (b *Blob) leaseCommonPut(headers map[string]string, expectedStatus int, opt if err != nil { return nil, err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err := checkRespCode(resp.statusCode, []int{expectedStatus}); err != nil { + if err := checkRespCode(resp, []int{expectedStatus}); err != nil { return nil, err } - return resp.headers, nil + return resp.Header, nil } // LeaseOptions includes options for all operations regarding leasing blobs diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/message.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/message.go index 3ededcd42..ffc183be6 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/message.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/message.go @@ -1,5 +1,19 @@ package storage +// 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/xml" "fmt" @@ -64,13 +78,16 @@ func (m *Message) Put(options *PutMessageOptions) error { if err != nil { return err } - defer readAndCloseBody(resp.body) - - err = xmlUnmarshal(resp.body, m) + defer drainRespBody(resp) + err = checkRespCode(resp, []int{http.StatusCreated}) if err != nil { return err } - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + err = xmlUnmarshal(resp.Body, m) + if err != nil { + return err + } + return nil } // UpdateMessageOptions is the set of options can be specified for Update Messsage @@ -97,7 +114,8 @@ func (m *Message) Update(options *UpdateMessageOptions) error { return err } headers["Content-Length"] = strconv.Itoa(nn) - + // visibilitytimeout is required for Update (zero or greater) so set the default here + query.Set("visibilitytimeout", "0") if options != nil { if options.VisibilityTimeout != 0 { query.Set("visibilitytimeout", strconv.Itoa(options.VisibilityTimeout)) @@ -111,10 +129,10 @@ func (m *Message) Update(options *UpdateMessageOptions) error { if err != nil { return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - m.PopReceipt = resp.headers.Get("x-ms-popreceipt") - nextTimeStr := resp.headers.Get("x-ms-time-next-visible") + m.PopReceipt = resp.Header.Get("x-ms-popreceipt") + nextTimeStr := resp.Header.Get("x-ms-time-next-visible") if nextTimeStr != "" { nextTime, err := time.Parse(time.RFC1123, nextTimeStr) if err != nil { @@ -123,7 +141,7 @@ func (m *Message) Update(options *UpdateMessageOptions) error { m.NextVisible = TimeRFC1123(nextTime) } - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) + return checkRespCode(resp, []int{http.StatusNoContent}) } // Delete operation deletes the specified message. @@ -143,8 +161,8 @@ func (m *Message) Delete(options *QueueServiceOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusNoContent}) } type putMessageRequest struct { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/odata.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/odata.go index 41d832e2b..800adf129 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/odata.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/odata.go @@ -1,5 +1,19 @@ package storage +// 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. + // MetadataLevel determines if operations should return a paylod, // and it level of detail. type MetadataLevel string diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/pageblob.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/pageblob.go index 468b3868a..7ffd63821 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/pageblob.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/pageblob.go @@ -1,5 +1,19 @@ package storage +// 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/xml" "errors" @@ -73,10 +87,10 @@ func (b *Blob) modifyRange(blobRange BlobRange, bytes io.Reader, options *PutPag return errors.New("the value for rangeEnd must be greater than or equal to rangeStart") } if blobRange.Start%512 != 0 { - return errors.New("the value for rangeStart must be a modulus of 512") + return errors.New("the value for rangeStart must be a multiple of 512") } if blobRange.End%512 != 511 { - return errors.New("the value for rangeEnd must be a modulus of 511") + return errors.New("the value for rangeEnd must be a multiple of 512 - 1") } params := url.Values{"comp": {"page"}} @@ -107,9 +121,8 @@ func (b *Blob) modifyRange(blobRange BlobRange, bytes io.Reader, options *PutPag if err != nil { return err } - readAndCloseBody(resp.body) - - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusCreated}) } // GetPageRangesOptions includes the options for a get page ranges operation @@ -133,7 +146,7 @@ func (b *Blob) GetPageRanges(options *GetPageRangesOptions) (GetPageRangesRespon params = addTimeout(params, options.Timeout) params = addSnapshot(params, options.Snapshot) if options.PreviousSnapshot != nil { - params.Add("prevsnapshot", timeRfc1123Formatted(*options.PreviousSnapshot)) + params.Add("prevsnapshot", timeRFC3339Formatted(*options.PreviousSnapshot)) } if options.Range != nil { headers["Range"] = options.Range.String() @@ -147,12 +160,12 @@ func (b *Blob) GetPageRanges(options *GetPageRangesOptions) (GetPageRangesRespon if err != nil { return out, err } - defer resp.body.Close() + defer drainRespBody(resp) - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err = checkRespCode(resp, []int{http.StatusOK}); err != nil { return out, err } - err = xmlUnmarshal(resp.body, &out) + err = xmlUnmarshal(resp.Body, &out) return out, err } @@ -186,6 +199,5 @@ func (b *Blob) PutPageBlob(options *PutBlobOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + return b.respondCreation(resp, BlobTypePage) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/queue.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/queue.go index c2c7f742c..f90050cb0 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/queue.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/queue.go @@ -1,8 +1,21 @@ package storage +// 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/xml" - "errors" "fmt" "io" "net/http" @@ -78,8 +91,8 @@ func (q *Queue) Create(options *QueueServiceOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusCreated}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusCreated}) } // Delete operation permanently deletes the specified queue. @@ -98,8 +111,8 @@ func (q *Queue) Delete(options *QueueServiceOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusNoContent}) } // Exists returns true if a queue with given name exists. @@ -107,10 +120,11 @@ func (q *Queue) Exists() (bool, error) { uri := q.qsc.client.getEndpoint(queueServiceName, q.buildPath(), url.Values{"comp": {"metadata"}}) resp, err := q.qsc.client.exec(http.MethodGet, uri, q.qsc.client.getStandardHeaders(), nil, q.qsc.auth) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusOK, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotFound { + return resp.StatusCode == http.StatusOK, nil } + err = getErrorFromResponse(resp) } return false, err } @@ -134,8 +148,8 @@ func (q *Queue) SetMetadata(options *QueueServiceOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusNoContent}) } // GetMetadata operation retrieves user-defined metadata and queue @@ -155,19 +169,19 @@ func (q *Queue) GetMetadata(options *QueueServiceOptions) error { params = addTimeout(params, options.Timeout) headers = mergeHeaders(headers, headersFromStruct(*options)) } - uri := q.qsc.client.getEndpoint(queueServiceName, q.buildPath(), url.Values{"comp": {"metadata"}}) + uri := q.qsc.client.getEndpoint(queueServiceName, q.buildPath(), params) resp, err := q.qsc.client.exec(http.MethodGet, uri, headers, nil, q.qsc.auth) if err != nil { return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err := checkRespCode(resp, []int{http.StatusOK}); err != nil { return err } - aproxMessagesStr := resp.headers.Get(http.CanonicalHeaderKey(approximateMessagesCountHeader)) + aproxMessagesStr := resp.Header.Get(http.CanonicalHeaderKey(approximateMessagesCountHeader)) if aproxMessagesStr != "" { aproxMessages, err := strconv.ParseUint(aproxMessagesStr, 10, 64) if err != nil { @@ -176,7 +190,7 @@ func (q *Queue) GetMetadata(options *QueueServiceOptions) error { q.AproxMessageCount = aproxMessages } - q.Metadata = getMetadataFromHeaders(resp.headers) + q.Metadata = getMetadataFromHeaders(resp.Header) return nil } @@ -227,10 +241,10 @@ func (q *Queue) GetMessages(options *GetMessagesOptions) ([]Message, error) { if err != nil { return []Message{}, err } - defer readAndCloseBody(resp.body) + defer resp.Body.Close() var out messages - err = xmlUnmarshal(resp.body, &out) + err = xmlUnmarshal(resp.Body, &out) if err != nil { return []Message{}, err } @@ -270,10 +284,10 @@ func (q *Queue) PeekMessages(options *PeekMessagesOptions) ([]Message, error) { if err != nil { return []Message{}, err } - defer readAndCloseBody(resp.body) + defer resp.Body.Close() var out messages - err = xmlUnmarshal(resp.body, &out) + err = xmlUnmarshal(resp.Body, &out) if err != nil { return []Message{}, err } @@ -300,8 +314,8 @@ func (q *Queue) ClearMessages(options *QueueServiceOptions) error { if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusNoContent}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusNoContent}) } // SetPermissions sets up queue permissions @@ -327,13 +341,8 @@ func (q *Queue) SetPermissions(permissions QueuePermissions, options *SetQueuePe if err != nil { return err } - defer readAndCloseBody(resp.body) - - if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { - return errors.New("Unable to set permissions") - } - - return nil + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusNoContent}) } func generateQueueACLpayload(policies []QueueAccessPolicy) (io.Reader, int, error) { @@ -395,14 +404,14 @@ func (q *Queue) GetPermissions(options *GetQueuePermissionOptions) (*QueuePermis if err != nil { return nil, err } - defer resp.body.Close() + defer resp.Body.Close() var ap AccessPolicy - err = xmlUnmarshal(resp.body, &ap.SignedIdentifiersList) + err = xmlUnmarshal(resp.Body, &ap.SignedIdentifiersList) if err != nil { return nil, err } - return buildQueueAccessPolicy(ap, &resp.headers), nil + return buildQueueAccessPolicy(ap, &resp.Header), nil } func buildQueueAccessPolicy(ap AccessPolicy, headers *http.Header) *QueuePermissions { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/queuesasuri.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/queuesasuri.go new file mode 100644 index 000000000..28d9ab937 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/queuesasuri.go @@ -0,0 +1,146 @@ +package storage + +// 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" + "fmt" + "net/url" + "strings" + "time" +) + +// QueueSASOptions are options to construct a blob SAS +// URI. +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas +type QueueSASOptions struct { + QueueSASPermissions + SASOptions +} + +// QueueSASPermissions includes the available permissions for +// a queue SAS URI. +type QueueSASPermissions struct { + Read bool + Add bool + Update bool + Process bool +} + +func (q QueueSASPermissions) buildString() string { + permissions := "" + + if q.Read { + permissions += "r" + } + if q.Add { + permissions += "a" + } + if q.Update { + permissions += "u" + } + if q.Process { + permissions += "p" + } + return permissions +} + +// GetSASURI creates an URL to the specified queue which contains the Shared +// Access Signature with specified permissions and expiration time. +// +// See https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas +func (q *Queue) GetSASURI(options QueueSASOptions) (string, error) { + canonicalizedResource, err := q.qsc.client.buildCanonicalizedResource(q.buildPath(), q.qsc.auth, true) + if err != nil { + return "", err + } + + // "The canonicalizedresouce portion of the string is a canonical path to the signed resource. + // It must include the service name (blob, table, queue or file) for version 2015-02-21 or + // later, the storage account name, and the resource name, and must be URL-decoded. + // -- https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx + // We need to replace + with %2b first to avoid being treated as a space (which is correct for query strings, but not the path component). + canonicalizedResource = strings.Replace(canonicalizedResource, "+", "%2b", -1) + canonicalizedResource, err = url.QueryUnescape(canonicalizedResource) + if err != nil { + return "", err + } + + signedStart := "" + if options.Start != (time.Time{}) { + signedStart = options.Start.UTC().Format(time.RFC3339) + } + signedExpiry := options.Expiry.UTC().Format(time.RFC3339) + + protocols := "https,http" + if options.UseHTTPS { + protocols = "https" + } + + permissions := options.QueueSASPermissions.buildString() + stringToSign, err := queueSASStringToSign(q.qsc.client.apiVersion, canonicalizedResource, signedStart, signedExpiry, options.IP, permissions, protocols, options.Identifier) + if err != nil { + return "", err + } + + sig := q.qsc.client.computeHmac256(stringToSign) + sasParams := url.Values{ + "sv": {q.qsc.client.apiVersion}, + "se": {signedExpiry}, + "sp": {permissions}, + "sig": {sig}, + } + + if q.qsc.client.apiVersion >= "2015-04-05" { + sasParams.Add("spr", protocols) + addQueryParameter(sasParams, "sip", options.IP) + } + + uri := q.qsc.client.getEndpoint(queueServiceName, q.buildPath(), nil) + sasURL, err := url.Parse(uri) + if err != nil { + return "", err + } + sasURL.RawQuery = sasParams.Encode() + return sasURL.String(), nil +} + +func queueSASStringToSign(signedVersion, canonicalizedResource, signedStart, signedExpiry, signedIP, signedPermissions, protocols, signedIdentifier string) (string, error) { + + if signedVersion >= "2015-02-21" { + canonicalizedResource = "/queue" + canonicalizedResource + } + + // https://msdn.microsoft.com/en-us/library/azure/dn140255.aspx#Anchor_12 + if signedVersion >= "2015-04-05" { + return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", + signedPermissions, + signedStart, + signedExpiry, + canonicalizedResource, + signedIdentifier, + signedIP, + protocols, + signedVersion), nil + + } + + // reference: http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx + if signedVersion >= "2013-08-15" { + return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", signedPermissions, signedStart, signedExpiry, canonicalizedResource, signedIdentifier, signedVersion), nil + } + + return "", errors.New("storage: not implemented SAS for versions earlier than 2013-08-15") +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/queueserviceclient.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/queueserviceclient.go index 19b44941c..29febe146 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/queueserviceclient.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/queueserviceclient.go @@ -1,5 +1,19 @@ package storage +// 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. + // QueueServiceClient contains operations for Microsoft Azure Queue Storage // Service. type QueueServiceClient struct { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/share.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/share.go index e6a868081..cf75a2659 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/share.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/share.go @@ -1,5 +1,19 @@ package storage +// 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" @@ -61,10 +75,10 @@ func (s *Share) CreateIfNotExists(options *FileRequestOptions) (bool, error) { params := prepareOptions(options) resp, err := s.fsc.createResourceNoClose(s.buildPath(), resourceShare, params, extraheaders) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict { - if resp.statusCode == http.StatusCreated { - s.updateEtagAndLastModified(resp.headers) + defer drainRespBody(resp) + if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusConflict { + if resp.StatusCode == http.StatusCreated { + s.updateEtagAndLastModified(resp.Header) return true, nil } return false, s.FetchAttributes(nil) @@ -89,9 +103,9 @@ func (s *Share) Delete(options *FileRequestOptions) error { func (s *Share) DeleteIfExists(options *FileRequestOptions) (bool, error) { resp, err := s.fsc.deleteResourceNoClose(s.buildPath(), resourceShare, options) if resp != nil { - defer readAndCloseBody(resp.body) - if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound { - return resp.statusCode == http.StatusAccepted, nil + defer drainRespBody(resp) + if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound { + return resp.StatusCode == http.StatusAccepted, nil } } return false, err diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/storagepolicy.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/storagepolicy.go index bee1c31ad..056ab398a 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/storagepolicy.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/storagepolicy.go @@ -1,5 +1,19 @@ package storage +// 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" diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/storageservice.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/storageservice.go index 88700fbc9..c338975ab 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/storageservice.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/storageservice.go @@ -1,5 +1,19 @@ package storage +// 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" "net/url" @@ -63,14 +77,14 @@ func (c Client) getServiceProperties(service string, auth authentication) (*Serv if err != nil { return nil, err } - defer resp.body.Close() + defer resp.Body.Close() - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err := checkRespCode(resp, []int{http.StatusOK}); err != nil { return nil, err } var out ServiceProperties - err = xmlUnmarshal(resp.body, &out) + err = xmlUnmarshal(resp.Body, &out) if err != nil { return nil, err } @@ -112,6 +126,6 @@ func (c Client) setServiceProperties(props ServiceProperties, service string, au if err != nil { return err } - readAndCloseBody(resp.body) - return checkRespCode(resp.statusCode, []int{http.StatusAccepted}) + defer drainRespBody(resp) + return checkRespCode(resp, []int{http.StatusAccepted}) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/table.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/table.go index 4eae3af9d..22d9b4f5c 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/table.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/table.go @@ -1,5 +1,19 @@ package storage +// 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" @@ -83,13 +97,13 @@ func (t *Table) Get(timeout uint, ml MetadataLevel) error { if err != nil { return err } - defer readAndCloseBody(resp.body) + defer resp.Body.Close() - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err = checkRespCode(resp, []int{http.StatusOK}); err != nil { return err } - respBody, err := ioutil.ReadAll(resp.body) + respBody, err := ioutil.ReadAll(resp.Body) if err != nil { return err } @@ -129,20 +143,20 @@ func (t *Table) Create(timeout uint, ml MetadataLevel, options *TableOptions) er if err != nil { return err } - defer readAndCloseBody(resp.body) + defer resp.Body.Close() if ml == EmptyPayload { - if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { + if err := checkRespCode(resp, []int{http.StatusNoContent}); err != nil { return err } } else { - if err := checkRespCode(resp.statusCode, []int{http.StatusCreated}); err != nil { + if err := checkRespCode(resp, []int{http.StatusCreated}); err != nil { return err } } if ml != EmptyPayload { - data, err := ioutil.ReadAll(resp.body) + data, err := ioutil.ReadAll(resp.Body) if err != nil { return err } @@ -172,13 +186,9 @@ func (t *Table) Delete(timeout uint, options *TableOptions) error { if err != nil { return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { - return err - - } - return nil + return checkRespCode(resp, []int{http.StatusNoContent}) } // QueryOptions includes options for a query entities operation. @@ -259,12 +269,9 @@ func (t *Table) SetPermissions(tap []TableAccessPolicy, timeout uint, options *T if err != nil { return err } - defer readAndCloseBody(resp.body) + defer drainRespBody(resp) - if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil { - return err - } - return nil + return checkRespCode(resp, []int{http.StatusNoContent}) } func generateTableACLPayload(policies []TableAccessPolicy) (io.Reader, int, error) { @@ -294,14 +301,14 @@ func (t *Table) GetPermissions(timeout int, options *TableOptions) ([]TableAcces if err != nil { return nil, err } - defer resp.body.Close() + defer resp.Body.Close() - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err = checkRespCode(resp, []int{http.StatusOK}); err != nil { return nil, err } var ap AccessPolicy - err = xmlUnmarshal(resp.body, &ap.SignedIdentifiersList) + err = xmlUnmarshal(resp.Body, &ap.SignedIdentifiersList) if err != nil { return nil, err } @@ -318,13 +325,13 @@ func (t *Table) queryEntities(uri string, headers map[string]string, ml Metadata if err != nil { return nil, err } - defer resp.body.Close() + defer resp.Body.Close() - if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err = checkRespCode(resp, []int{http.StatusOK}); err != nil { return nil, err } - data, err := ioutil.ReadAll(resp.body) + data, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } @@ -339,7 +346,7 @@ func (t *Table) queryEntities(uri string, headers map[string]string, ml Metadata } entities.table = t - contToken := extractContinuationTokenFromHeaders(resp.headers) + contToken := extractContinuationTokenFromHeaders(resp.Header) if contToken == nil { entities.NextLink = nil } else { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/table_batch.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/table_batch.go index 7a0f0915c..a2159e296 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/table_batch.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/table_batch.go @@ -1,5 +1,19 @@ package storage +// 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" @@ -12,7 +26,7 @@ import ( "sort" "strings" - "github.com/satori/uuid" + "github.com/marstr/guid" ) // Operation type. Insert, Delete, Replace etc. @@ -117,14 +131,26 @@ func (t *TableBatch) MergeEntity(entity *Entity) { // the changesets. // As per document https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/performing-entity-group-transactions func (t *TableBatch) ExecuteBatch() error { - changesetBoundary := fmt.Sprintf("changeset_%s", uuid.NewV1()) + + // Using `github.com/marstr/guid` is in response to issue #947 (https://github.com/Azure/azure-sdk-for-go/issues/947). + id, err := guid.NewGUIDs(guid.CreationStrategyVersion1) + if err != nil { + return err + } + + changesetBoundary := fmt.Sprintf("changeset_%s", id.String()) uri := t.Table.tsc.client.getEndpoint(tableServiceName, "$batch", nil) changesetBody, err := t.generateChangesetBody(changesetBoundary) if err != nil { return err } - boundary := fmt.Sprintf("batch_%s", uuid.NewV1()) + id, err = guid.NewGUIDs(guid.CreationStrategyVersion1) + if err != nil { + return err + } + + boundary := fmt.Sprintf("batch_%s", id.String()) body, err := generateBody(changesetBody, changesetBoundary, boundary) if err != nil { return err @@ -137,15 +163,15 @@ func (t *TableBatch) ExecuteBatch() error { if err != nil { return err } - defer resp.body.Close() + defer drainRespBody(resp.resp) - if err = checkRespCode(resp.statusCode, []int{http.StatusAccepted}); err != nil { + if err = checkRespCode(resp.resp, []int{http.StatusAccepted}); err != nil { // check which batch failed. operationFailedMessage := t.getFailedOperation(resp.odata.Err.Message.Value) - requestID, date, version := getDebugHeaders(resp.headers) + requestID, date, version := getDebugHeaders(resp.resp.Header) return AzureStorageServiceError{ - StatusCode: resp.statusCode, + StatusCode: resp.resp.StatusCode, Code: resp.odata.Err.Code, RequestID: requestID, Date: date, diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/tableserviceclient.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/tableserviceclient.go index 895dcfded..1f063a395 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/tableserviceclient.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/tableserviceclient.go @@ -1,5 +1,19 @@ package storage +// 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" @@ -131,13 +145,13 @@ func (t *TableServiceClient) queryTables(uri string, headers map[string]string, if err != nil { return nil, err } - defer resp.body.Close() + defer resp.Body.Close() - if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil { + if err := checkRespCode(resp, []int{http.StatusOK}); err != nil { return nil, err } - respBody, err := ioutil.ReadAll(resp.body) + respBody, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } @@ -152,7 +166,7 @@ func (t *TableServiceClient) queryTables(uri string, headers map[string]string, } out.tsc = t - nextLink := resp.headers.Get(http.CanonicalHeaderKey(headerXmsContinuation)) + nextLink := resp.Header.Get(http.CanonicalHeaderKey(headerXmsContinuation)) if nextLink == "" { out.NextLink = nil } else { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/util.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/util.go index d3ae9d092..e8a5dcf8c 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/util.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/storage/util.go @@ -1,5 +1,19 @@ package storage +// 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" "crypto/hmac" @@ -18,7 +32,29 @@ import ( ) var ( - fixedTime = time.Date(2050, time.December, 20, 21, 55, 0, 0, time.FixedZone("GMT", -6)) + fixedTime = time.Date(2050, time.December, 20, 21, 55, 0, 0, time.FixedZone("GMT", -6)) + accountSASOptions = AccountSASTokenOptions{ + Services: Services{ + Blob: true, + }, + ResourceTypes: ResourceTypes{ + Service: true, + Container: true, + Object: true, + }, + Permissions: Permissions{ + Read: true, + Write: true, + Delete: true, + List: true, + Add: true, + Create: true, + Update: true, + Process: true, + }, + Expiry: fixedTime, + UseHTTPS: true, + } ) func (c Client) computeHmac256(message string) string { @@ -35,6 +71,10 @@ func timeRfc1123Formatted(t time.Time) string { return t.Format(http.TimeFormat) } +func timeRFC3339Formatted(t time.Time) string { + return t.Format("2006-01-02T15:04:05.0000000Z") +} + func mergeParams(v1, v2 url.Values) url.Values { out := url.Values{} for k, v := range v1 { @@ -136,7 +176,7 @@ func addTimeout(params url.Values, timeout uint) url.Values { func addSnapshot(params url.Values, snapshot *time.Time) url.Values { if snapshot != nil { - params.Add("snapshot", snapshot.Format("2006-01-02T15:04:05.0000000Z")) + params.Add("snapshot", timeRFC3339Formatted(*snapshot)) } return params } @@ -169,6 +209,11 @@ func (t *TimeRFC1123) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error return nil } +// MarshalXML marshals using time.RFC1123. +func (t *TimeRFC1123) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + return e.EncodeElement(time.Time(*t).Format(time.RFC1123), start) +} + // returns a map of custom metadata values from the specified HTTP header func getMetadataFromHeaders(header http.Header) map[string]string { metadata := make(map[string]string) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/util_1.7.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/util_1.7.go deleted file mode 100644 index 345bb28f2..000000000 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/util_1.7.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !go1.8 - -package storage - -import ( - "io" - "net/http" -) - -func setContentLengthFromLimitedReader(req *http.Request, lr *io.LimitedReader) { - req.ContentLength = lr.N -} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/util_1.8.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/util_1.8.go deleted file mode 100644 index ed8b77919..000000000 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/util_1.8.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build go1.8 - -package storage - -import ( - "io" - "io/ioutil" - "net/http" -) - -func setContentLengthFromLimitedReader(req *http.Request, lr *io.LimitedReader) { - req.ContentLength = lr.N - snapshot := *lr - req.GetBody = func() (io.ReadCloser, error) { - r := snapshot - return ioutil.NopCloser(&r), nil - } -} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/storage/version.go b/vendor/github.com/Azure/azure-sdk-for-go/storage/version.go deleted file mode 100644 index a23fff1e2..000000000 --- a/vendor/github.com/Azure/azure-sdk-for-go/storage/version.go +++ /dev/null @@ -1,5 +0,0 @@ -package storage - -var ( - sdkVersion = "10.0.2" -) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/version/version.go b/vendor/github.com/Azure/azure-sdk-for-go/version/version.go new file mode 100644 index 000000000..7f0f6f2b6 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/version/version.go @@ -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 = "v21.3.0" diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/README.md b/vendor/github.com/Azure/go-autorest/autorest/adal/README.md index a17cf98c6..7b0c4bc4d 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/README.md +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/README.md @@ -1,19 +1,24 @@ -# Azure Active Directory library for Go +# Azure Active Directory authentication for Go -This project provides a stand alone Azure Active Directory library for Go. The code was extracted -from [go-autorest](https://github.com/Azure/go-autorest/) project, which is used as a base for -[azure-sdk-for-go](https://github.com/Azure/azure-sdk-for-go). +This is a standalone package for authenticating with Azure Active +Directory from other Go libraries and applications, in particular the [Azure SDK +for Go](https://github.com/Azure/azure-sdk-for-go). +Note: Despite the package's name it is not related to other "ADAL" libraries +maintained in the [github.com/AzureAD](https://github.com/AzureAD) org. Issues +should be opened in [this repo's](https://github.com/Azure/go-autorest/issues) +or [the SDK's](https://github.com/Azure/azure-sdk-for-go/issues) issue +trackers. -## Installation +## Install -``` +```bash go get -u github.com/Azure/go-autorest/autorest/adal ``` ## Usage -An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) follow these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli). +An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) by following these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli). ### Register an Azure AD Application with secret @@ -218,6 +223,40 @@ if (err == nil) { } ``` +#### Username password authenticate + +```Go +spt, err := adal.NewServicePrincipalTokenFromUsernamePassword( + oauthConfig, + applicationID, + username, + password, + resource, + callbacks...) + +if (err == nil) { + token := spt.Token +} +``` + +#### Authorization code authenticate + +``` Go +spt, err := adal.NewServicePrincipalTokenFromAuthorizationCode( + oauthConfig, + applicationID, + clientSecret, + authorizationCode, + redirectURI, + resource, + callbacks...) + +err = spt.Refresh() +if (err == nil) { + token := spt.Token +} +``` + ### Command Line Tool A command line tool is available in `cmd/adal.go` that can acquire a token for a given resource. It supports all flows mentioned above. diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/config.go b/vendor/github.com/Azure/go-autorest/autorest/adal/config.go index 12375e0e4..bee5e61dd 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/config.go +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/config.go @@ -1,5 +1,19 @@ package adal +// Copyright 2017 Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + import ( "fmt" "net/url" @@ -12,14 +26,30 @@ const ( // OAuthConfig represents the endpoints needed // in OAuth operations type OAuthConfig struct { - AuthorityEndpoint url.URL - AuthorizeEndpoint url.URL - TokenEndpoint url.URL - DeviceCodeEndpoint url.URL + AuthorityEndpoint url.URL `json:"authorityEndpoint"` + AuthorizeEndpoint url.URL `json:"authorizeEndpoint"` + TokenEndpoint url.URL `json:"tokenEndpoint"` + DeviceCodeEndpoint url.URL `json:"deviceCodeEndpoint"` +} + +// IsZero returns true if the OAuthConfig object is zero-initialized. +func (oac OAuthConfig) IsZero() bool { + return oac == OAuthConfig{} +} + +func validateStringParam(param, name string) error { + if len(param) == 0 { + return fmt.Errorf("parameter '" + name + "' cannot be empty") + } + return nil } // NewOAuthConfig returns an OAuthConfig with tenant specific urls func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) { + if err := validateStringParam(activeDirectoryEndpoint, "activeDirectoryEndpoint"); err != nil { + return nil, err + } + // it's legal for tenantID to be empty so don't validate it const activeDirectoryEndpointTemplate = "%s/oauth2/%s?api-version=%s" u, err := url.Parse(activeDirectoryEndpoint) if err != nil { diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken.go b/vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken.go index 6c511f8c8..b38f4c245 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken.go +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/devicetoken.go @@ -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 diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/persist.go b/vendor/github.com/Azure/go-autorest/autorest/adal/persist.go index 73711c667..9e15f2751 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/persist.go +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/persist.go @@ -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" diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/sender.go b/vendor/github.com/Azure/go-autorest/autorest/adal/sender.go index 7928c971a..0e5ad14d3 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/sender.go +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/sender.go @@ -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" ) diff --git a/vendor/github.com/Azure/go-autorest/autorest/adal/token.go b/vendor/github.com/Azure/go-autorest/autorest/adal/token.go index 55361139a..32aea8389 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/adal/token.go +++ b/vendor/github.com/Azure/go-autorest/autorest/adal/token.go @@ -1,26 +1,46 @@ package adal +// Copyright 2017 Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + import ( + "context" "crypto/rand" "crypto/rsa" "crypto/sha1" "crypto/x509" "encoding/base64" "encoding/json" + "errors" "fmt" "io/ioutil" + "math" + "net" "net/http" "net/url" "strconv" "strings" + "sync" "time" + "github.com/Azure/go-autorest/autorest/date" + "github.com/Azure/go-autorest/version" "github.com/dgrijalva/jwt-go" ) const ( defaultRefresh = 5 * time.Minute - tokenBaseDate = "1970-01-01T00:00:00Z" // OAuthGrantTypeDeviceCode is the "grant_type" identifier used in device flow OAuthGrantTypeDeviceCode = "device_code" @@ -28,27 +48,36 @@ const ( // OAuthGrantTypeClientCredentials is the "grant_type" identifier used in credential flows OAuthGrantTypeClientCredentials = "client_credentials" + // OAuthGrantTypeUserPass is the "grant_type" identifier used in username and password auth flows + OAuthGrantTypeUserPass = "password" + // OAuthGrantTypeRefreshToken is the "grant_type" identifier used in refresh token flows OAuthGrantTypeRefreshToken = "refresh_token" - // managedIdentitySettingsPath is the path to the MSI Extension settings file (to discover the endpoint) - managedIdentitySettingsPath = "/var/lib/waagent/ManagedIdentity-Settings" + // OAuthGrantTypeAuthorizationCode is the "grant_type" identifier used in authorization code flows + OAuthGrantTypeAuthorizationCode = "authorization_code" // metadataHeader is the header required by MSI extension metadataHeader = "Metadata" + + // msiEndpoint is the well known endpoint for getting MSI authentications tokens + msiEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token" + + // the default number of attempts to refresh an MSI authentication token + defaultMaxMSIRefreshAttempts = 5 ) -var expirationBase time.Time - -func init() { - expirationBase, _ = time.Parse(time.RFC3339, tokenBaseDate) -} - // OAuthTokenProvider is an interface which should be implemented by an access token retriever type OAuthTokenProvider interface { OAuthToken() string } +// TokenRefreshError is an interface used by errors returned during token refresh. +type TokenRefreshError interface { + error + Response() *http.Response +} + // Refresher is an interface for token refresh functionality type Refresher interface { Refresh() error @@ -56,6 +85,13 @@ type Refresher interface { EnsureFresh() error } +// RefresherWithContext is an interface for token refresh functionality +type RefresherWithContext interface { + RefreshWithContext(ctx context.Context) error + RefreshExchangeWithContext(ctx context.Context, resource string) error + EnsureFreshWithContext(ctx context.Context) error +} + // TokenRefreshCallback is the type representing callbacks that will be called after // a successful token refresh type TokenRefreshCallback func(Token) error @@ -73,13 +109,21 @@ type Token struct { Type string `json:"token_type"` } +// IsZero returns true if the token object is zero-initialized. +func (t Token) IsZero() bool { + return t == Token{} +} + // Expires returns the time.Time when the Token expires. func (t Token) Expires() time.Time { s, err := strconv.Atoi(t.ExpiresOn) if err != nil { s = -3600 } - return expirationBase.Add(time.Duration(s) * time.Second).UTC() + + expiration := date.NewUnixTimeFromSeconds(float64(s)) + + return time.Time(expiration).UTC() } // IsExpired returns true if the Token is expired, false otherwise. @@ -98,6 +142,12 @@ func (t *Token) OAuthToken() string { return t.AccessToken } +// ServicePrincipalSecret is an interface that allows various secret mechanism to fill the form +// that is submitted when acquiring an oAuth token. +type ServicePrincipalSecret interface { + SetAuthenticationValues(spt *ServicePrincipalToken, values *url.Values) error +} + // ServicePrincipalNoSecret represents a secret type that contains no secret // meaning it is not valid for fetching a fresh token. This is used by Manual type ServicePrincipalNoSecret struct { @@ -109,15 +159,19 @@ func (noSecret *ServicePrincipalNoSecret) SetAuthenticationValues(spt *ServicePr return fmt.Errorf("Manually created ServicePrincipalToken does not contain secret material to retrieve a new access token") } -// ServicePrincipalSecret is an interface that allows various secret mechanism to fill the form -// that is submitted when acquiring an oAuth token. -type ServicePrincipalSecret interface { - SetAuthenticationValues(spt *ServicePrincipalToken, values *url.Values) error +// MarshalJSON implements the json.Marshaler interface. +func (noSecret ServicePrincipalNoSecret) MarshalJSON() ([]byte, error) { + type tokenType struct { + Type string `json:"type"` + } + return json.Marshal(tokenType{ + Type: "ServicePrincipalNoSecret", + }) } // ServicePrincipalTokenSecret implements ServicePrincipalSecret for client_secret type authorization. type ServicePrincipalTokenSecret struct { - ClientSecret string + ClientSecret string `json:"value"` } // SetAuthenticationValues is a method of the interface ServicePrincipalSecret. @@ -127,23 +181,24 @@ func (tokenSecret *ServicePrincipalTokenSecret) SetAuthenticationValues(spt *Ser return nil } +// MarshalJSON implements the json.Marshaler interface. +func (tokenSecret ServicePrincipalTokenSecret) MarshalJSON() ([]byte, error) { + type tokenType struct { + Type string `json:"type"` + Value string `json:"value"` + } + return json.Marshal(tokenType{ + Type: "ServicePrincipalTokenSecret", + Value: tokenSecret.ClientSecret, + }) +} + // ServicePrincipalCertificateSecret implements ServicePrincipalSecret for generic RSA cert auth with signed JWTs. type ServicePrincipalCertificateSecret struct { Certificate *x509.Certificate PrivateKey *rsa.PrivateKey } -// ServicePrincipalMSISecret implements ServicePrincipalSecret for machines running the MSI Extension. -type ServicePrincipalMSISecret struct { -} - -// SetAuthenticationValues is a method of the interface ServicePrincipalSecret. -// MSI extension requires the authority field to be set to the real tenant authority endpoint -func (msiSecret *ServicePrincipalMSISecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error { - v.Set("authority", spt.oauthConfig.AuthorityEndpoint.String()) - return nil -} - // SignJwt returns the JWT signed with the certificate's private key. func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalToken) (string, error) { hasher := sha1.New() @@ -164,9 +219,9 @@ func (secret *ServicePrincipalCertificateSecret) SignJwt(spt *ServicePrincipalTo token := jwt.New(jwt.SigningMethodRS256) token.Header["x5t"] = thumbprint token.Claims = jwt.MapClaims{ - "aud": spt.oauthConfig.TokenEndpoint.String(), - "iss": spt.clientID, - "sub": spt.clientID, + "aud": spt.inner.OauthConfig.TokenEndpoint.String(), + "iss": spt.inner.ClientID, + "sub": spt.inner.ClientID, "jti": base64.URLEncoding.EncodeToString(jti), "nbf": time.Now().Unix(), "exp": time.Now().Add(time.Hour * 24).Unix(), @@ -189,30 +244,184 @@ func (secret *ServicePrincipalCertificateSecret) SetAuthenticationValues(spt *Se return nil } +// MarshalJSON implements the json.Marshaler interface. +func (secret ServicePrincipalCertificateSecret) MarshalJSON() ([]byte, error) { + return nil, errors.New("marshalling ServicePrincipalCertificateSecret is not supported") +} + +// ServicePrincipalMSISecret implements ServicePrincipalSecret for machines running the MSI Extension. +type ServicePrincipalMSISecret struct { +} + +// SetAuthenticationValues is a method of the interface ServicePrincipalSecret. +func (msiSecret *ServicePrincipalMSISecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error { + return nil +} + +// MarshalJSON implements the json.Marshaler interface. +func (msiSecret ServicePrincipalMSISecret) MarshalJSON() ([]byte, error) { + return nil, errors.New("marshalling ServicePrincipalMSISecret is not supported") +} + +// ServicePrincipalUsernamePasswordSecret implements ServicePrincipalSecret for username and password auth. +type ServicePrincipalUsernamePasswordSecret struct { + Username string `json:"username"` + Password string `json:"password"` +} + +// SetAuthenticationValues is a method of the interface ServicePrincipalSecret. +func (secret *ServicePrincipalUsernamePasswordSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error { + v.Set("username", secret.Username) + v.Set("password", secret.Password) + return nil +} + +// MarshalJSON implements the json.Marshaler interface. +func (secret ServicePrincipalUsernamePasswordSecret) MarshalJSON() ([]byte, error) { + type tokenType struct { + Type string `json:"type"` + Username string `json:"username"` + Password string `json:"password"` + } + return json.Marshal(tokenType{ + Type: "ServicePrincipalUsernamePasswordSecret", + Username: secret.Username, + Password: secret.Password, + }) +} + +// ServicePrincipalAuthorizationCodeSecret implements ServicePrincipalSecret for authorization code auth. +type ServicePrincipalAuthorizationCodeSecret struct { + ClientSecret string `json:"value"` + AuthorizationCode string `json:"authCode"` + RedirectURI string `json:"redirect"` +} + +// SetAuthenticationValues is a method of the interface ServicePrincipalSecret. +func (secret *ServicePrincipalAuthorizationCodeSecret) SetAuthenticationValues(spt *ServicePrincipalToken, v *url.Values) error { + v.Set("code", secret.AuthorizationCode) + v.Set("client_secret", secret.ClientSecret) + v.Set("redirect_uri", secret.RedirectURI) + return nil +} + +// MarshalJSON implements the json.Marshaler interface. +func (secret ServicePrincipalAuthorizationCodeSecret) MarshalJSON() ([]byte, error) { + type tokenType struct { + Type string `json:"type"` + Value string `json:"value"` + AuthCode string `json:"authCode"` + Redirect string `json:"redirect"` + } + return json.Marshal(tokenType{ + Type: "ServicePrincipalAuthorizationCodeSecret", + Value: secret.ClientSecret, + AuthCode: secret.AuthorizationCode, + Redirect: secret.RedirectURI, + }) +} + // ServicePrincipalToken encapsulates a Token created for a Service Principal. type ServicePrincipalToken struct { - Token - - secret ServicePrincipalSecret - oauthConfig OAuthConfig - clientID string - resource string - autoRefresh bool - refreshWithin time.Duration - sender Sender - + inner servicePrincipalToken + refreshLock *sync.RWMutex + sender Sender refreshCallbacks []TokenRefreshCallback + // MaxMSIRefreshAttempts is the maximum number of attempts to refresh an MSI token. + MaxMSIRefreshAttempts int +} + +// MarshalTokenJSON returns the marshalled inner token. +func (spt ServicePrincipalToken) MarshalTokenJSON() ([]byte, error) { + return json.Marshal(spt.inner.Token) +} + +// SetRefreshCallbacks replaces any existing refresh callbacks with the specified callbacks. +func (spt *ServicePrincipalToken) SetRefreshCallbacks(callbacks []TokenRefreshCallback) { + spt.refreshCallbacks = callbacks +} + +// MarshalJSON implements the json.Marshaler interface. +func (spt ServicePrincipalToken) MarshalJSON() ([]byte, error) { + return json.Marshal(spt.inner) +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (spt *ServicePrincipalToken) UnmarshalJSON(data []byte) error { + // need to determine the token type + raw := map[string]interface{}{} + err := json.Unmarshal(data, &raw) + if err != nil { + return err + } + secret := raw["secret"].(map[string]interface{}) + switch secret["type"] { + case "ServicePrincipalNoSecret": + spt.inner.Secret = &ServicePrincipalNoSecret{} + case "ServicePrincipalTokenSecret": + spt.inner.Secret = &ServicePrincipalTokenSecret{} + case "ServicePrincipalCertificateSecret": + return errors.New("unmarshalling ServicePrincipalCertificateSecret is not supported") + case "ServicePrincipalMSISecret": + return errors.New("unmarshalling ServicePrincipalMSISecret is not supported") + case "ServicePrincipalUsernamePasswordSecret": + spt.inner.Secret = &ServicePrincipalUsernamePasswordSecret{} + case "ServicePrincipalAuthorizationCodeSecret": + spt.inner.Secret = &ServicePrincipalAuthorizationCodeSecret{} + default: + return fmt.Errorf("unrecognized token type '%s'", secret["type"]) + } + err = json.Unmarshal(data, &spt.inner) + if err != nil { + return err + } + spt.refreshLock = &sync.RWMutex{} + spt.sender = &http.Client{} + return nil +} + +// internal type used for marshalling/unmarshalling +type servicePrincipalToken struct { + Token Token `json:"token"` + Secret ServicePrincipalSecret `json:"secret"` + OauthConfig OAuthConfig `json:"oauth"` + ClientID string `json:"clientID"` + Resource string `json:"resource"` + AutoRefresh bool `json:"autoRefresh"` + RefreshWithin time.Duration `json:"refreshWithin"` +} + +func validateOAuthConfig(oac OAuthConfig) error { + if oac.IsZero() { + return fmt.Errorf("parameter 'oauthConfig' cannot be zero-initialized") + } + return nil } // NewServicePrincipalTokenWithSecret create a ServicePrincipalToken using the supplied ServicePrincipalSecret implementation. func NewServicePrincipalTokenWithSecret(oauthConfig OAuthConfig, id string, resource string, secret ServicePrincipalSecret, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { + if err := validateOAuthConfig(oauthConfig); err != nil { + return nil, err + } + if err := validateStringParam(id, "id"); err != nil { + return nil, err + } + if err := validateStringParam(resource, "resource"); err != nil { + return nil, err + } + if secret == nil { + return nil, fmt.Errorf("parameter 'secret' cannot be nil") + } spt := &ServicePrincipalToken{ - oauthConfig: oauthConfig, - secret: secret, - clientID: id, - resource: resource, - autoRefresh: true, - refreshWithin: defaultRefresh, + inner: servicePrincipalToken{ + OauthConfig: oauthConfig, + Secret: secret, + ClientID: id, + Resource: resource, + AutoRefresh: true, + RefreshWithin: defaultRefresh, + }, + refreshLock: &sync.RWMutex{}, sender: &http.Client{}, refreshCallbacks: callbacks, } @@ -221,6 +430,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, @@ -231,7 +452,39 @@ func NewServicePrincipalTokenFromManualToken(oauthConfig OAuthConfig, clientID s return nil, err } - spt.Token = token + spt.inner.Token = token + + return spt, nil +} + +// NewServicePrincipalTokenFromManualTokenSecret creates a ServicePrincipalToken using the supplied token and secret +func NewServicePrincipalTokenFromManualTokenSecret(oauthConfig OAuthConfig, clientID string, resource string, token Token, secret ServicePrincipalSecret, 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 secret == nil { + return nil, fmt.Errorf("parameter 'secret' cannot be nil") + } + if token.IsZero() { + return nil, fmt.Errorf("parameter 'token' cannot be zero-initialized") + } + spt, err := NewServicePrincipalTokenWithSecret( + oauthConfig, + clientID, + resource, + secret, + callbacks...) + if err != nil { + return nil, err + } + + spt.inner.Token = token return spt, nil } @@ -239,6 +492,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, @@ -250,8 +515,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, @@ -264,57 +544,172 @@ func NewServicePrincipalTokenFromCertificate(oauthConfig OAuthConfig, clientID s ) } -// NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension. -func NewServicePrincipalTokenFromMSI(oauthConfig OAuthConfig, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { - return newServicePrincipalTokenFromMSI(oauthConfig, resource, managedIdentitySettingsPath, callbacks...) +// NewServicePrincipalTokenFromUsernamePassword creates a ServicePrincipalToken from the username and password. +func NewServicePrincipalTokenFromUsernamePassword(oauthConfig OAuthConfig, clientID string, username string, password string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { + if err := validateOAuthConfig(oauthConfig); err != nil { + return nil, err + } + if err := validateStringParam(clientID, "clientID"); err != nil { + return nil, err + } + if err := validateStringParam(username, "username"); err != nil { + return nil, err + } + if err := validateStringParam(password, "password"); err != nil { + return nil, err + } + if err := validateStringParam(resource, "resource"); err != nil { + return nil, err + } + return NewServicePrincipalTokenWithSecret( + oauthConfig, + clientID, + resource, + &ServicePrincipalUsernamePasswordSecret{ + Username: username, + Password: password, + }, + callbacks..., + ) } -func newServicePrincipalTokenFromMSI(oauthConfig OAuthConfig, resource, settingsPath string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { - // Read MSI settings - bytes, err := ioutil.ReadFile(settingsPath) - if err != nil { +// NewServicePrincipalTokenFromAuthorizationCode creates a ServicePrincipalToken from the +func NewServicePrincipalTokenFromAuthorizationCode(oauthConfig OAuthConfig, clientID string, clientSecret string, authorizationCode string, redirectURI string, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { + + if err := validateOAuthConfig(oauthConfig); err != nil { return nil, err } - msiSettings := struct { - URL string `json:"url"` - }{} - err = json.Unmarshal(bytes, &msiSettings) - if err != nil { + if err := validateStringParam(clientID, "clientID"); err != nil { + return nil, err + } + if err := validateStringParam(clientSecret, "clientSecret"); err != nil { + return nil, err + } + if err := validateStringParam(authorizationCode, "authorizationCode"); err != nil { + return nil, err + } + if err := validateStringParam(redirectURI, "redirectURI"); err != nil { + return nil, err + } + if err := validateStringParam(resource, "resource"); err != nil { return nil, err } + return NewServicePrincipalTokenWithSecret( + oauthConfig, + clientID, + resource, + &ServicePrincipalAuthorizationCodeSecret{ + ClientSecret: clientSecret, + AuthorizationCode: authorizationCode, + RedirectURI: redirectURI, + }, + callbacks..., + ) +} + +// GetMSIVMEndpoint gets the MSI endpoint on Virtual Machines. +func GetMSIVMEndpoint() (string, error) { + return msiEndpoint, nil +} + +// NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension. +// It will use the system assigned identity when creating the token. +func NewServicePrincipalTokenFromMSI(msiEndpoint, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { + return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, callbacks...) +} + +// NewServicePrincipalTokenFromMSIWithUserAssignedID creates a ServicePrincipalToken via the MSI VM Extension. +// It will use the specified user assigned identity when creating the token. +func NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, resource string, userAssignedID string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { + return newServicePrincipalTokenFromMSI(msiEndpoint, resource, &userAssignedID, callbacks...) +} + +func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedID *string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) { + if err := validateStringParam(msiEndpoint, "msiEndpoint"); err != nil { + return nil, err + } + if err := validateStringParam(resource, "resource"); err != nil { + return nil, err + } + if userAssignedID != nil { + if err := validateStringParam(*userAssignedID, "userAssignedID"); err != nil { + return nil, err + } + } // We set the oauth config token endpoint to be MSI's endpoint - // We leave the authority as-is so MSI can POST it with the token request - msiEndpointURL, err := url.Parse(msiSettings.URL) + msiEndpointURL, err := url.Parse(msiEndpoint) if err != nil { return nil, err } - msiTokenEndpointURL, err := msiEndpointURL.Parse("/oauth2/token") - if err != nil { - return nil, err + v := url.Values{} + v.Set("resource", resource) + v.Set("api-version", "2018-02-01") + if userAssignedID != nil { + v.Set("client_id", *userAssignedID) } - - oauthConfig.TokenEndpoint = *msiTokenEndpointURL + msiEndpointURL.RawQuery = v.Encode() spt := &ServicePrincipalToken{ - oauthConfig: oauthConfig, - secret: &ServicePrincipalMSISecret{}, - resource: resource, - autoRefresh: true, - refreshWithin: defaultRefresh, - sender: &http.Client{}, - refreshCallbacks: callbacks, + inner: servicePrincipalToken{ + OauthConfig: OAuthConfig{ + TokenEndpoint: *msiEndpointURL, + }, + Secret: &ServicePrincipalMSISecret{}, + Resource: resource, + AutoRefresh: true, + RefreshWithin: defaultRefresh, + }, + refreshLock: &sync.RWMutex{}, + sender: &http.Client{}, + refreshCallbacks: callbacks, + MaxMSIRefreshAttempts: defaultMaxMSIRefreshAttempts, + } + + if userAssignedID != nil { + spt.inner.ClientID = *userAssignedID } return spt, nil } +// internal type that implements TokenRefreshError +type tokenRefreshError struct { + message string + resp *http.Response +} + +// Error implements the error interface which is part of the TokenRefreshError interface. +func (tre tokenRefreshError) Error() string { + return tre.message +} + +// Response implements the TokenRefreshError interface, it returns the raw HTTP response from the refresh operation. +func (tre tokenRefreshError) Response() *http.Response { + return tre.resp +} + +func newTokenRefreshError(message string, resp *http.Response) TokenRefreshError { + return tokenRefreshError{message: message, resp: resp} +} + // EnsureFresh will refresh the token if it will expire within the refresh window (as set by -// RefreshWithin) and autoRefresh flag is on. +// RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use. func (spt *ServicePrincipalToken) EnsureFresh() error { - if spt.autoRefresh && spt.WillExpireIn(spt.refreshWithin) { - return spt.Refresh() + return spt.EnsureFreshWithContext(context.Background()) +} + +// EnsureFreshWithContext will refresh the token if it will expire within the refresh window (as set by +// RefreshWithin) and autoRefresh flag is on. This method is safe for concurrent use. +func (spt *ServicePrincipalToken) EnsureFreshWithContext(ctx context.Context) error { + if spt.inner.AutoRefresh && spt.inner.Token.WillExpireIn(spt.inner.RefreshWithin) { + // take the write lock then check to see if the token was already refreshed + spt.refreshLock.Lock() + defer spt.refreshLock.Unlock() + if spt.inner.Token.WillExpireIn(spt.inner.RefreshWithin) { + return spt.refreshInternal(ctx, spt.inner.Resource) + } } return nil } @@ -323,7 +718,7 @@ func (spt *ServicePrincipalToken) EnsureFresh() error { func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error { if spt.refreshCallbacks != nil { for _, callback := range spt.refreshCallbacks { - err := callback(spt.Token) + err := callback(spt.inner.Token) if err != nil { return fmt.Errorf("adal: TokenRefreshCallback handler failed. Error = '%v'", err) } @@ -333,53 +728,119 @@ func (spt *ServicePrincipalToken) InvokeRefreshCallbacks(token Token) error { } // Refresh obtains a fresh token for the Service Principal. +// This method is not safe for concurrent use and should be syncrhonized. func (spt *ServicePrincipalToken) Refresh() error { - return spt.refreshInternal(spt.resource) + return spt.RefreshWithContext(context.Background()) +} + +// RefreshWithContext obtains a fresh token for the Service Principal. +// This method is not safe for concurrent use and should be syncrhonized. +func (spt *ServicePrincipalToken) RefreshWithContext(ctx context.Context) error { + spt.refreshLock.Lock() + defer spt.refreshLock.Unlock() + return spt.refreshInternal(ctx, spt.inner.Resource) } // RefreshExchange refreshes the token, but for a different resource. +// This method is not safe for concurrent use and should be syncrhonized. func (spt *ServicePrincipalToken) RefreshExchange(resource string) error { - return spt.refreshInternal(resource) + return spt.RefreshExchangeWithContext(context.Background(), resource) } -func (spt *ServicePrincipalToken) refreshInternal(resource string) error { - v := url.Values{} - v.Set("client_id", spt.clientID) - v.Set("resource", resource) +// RefreshExchangeWithContext refreshes the token, but for a different resource. +// This method is not safe for concurrent use and should be syncrhonized. +func (spt *ServicePrincipalToken) RefreshExchangeWithContext(ctx context.Context, resource string) error { + spt.refreshLock.Lock() + defer spt.refreshLock.Unlock() + return spt.refreshInternal(ctx, resource) +} - if spt.RefreshToken != "" { - v.Set("grant_type", OAuthGrantTypeRefreshToken) - v.Set("refresh_token", spt.RefreshToken) - } else { - v.Set("grant_type", OAuthGrantTypeClientCredentials) - err := spt.secret.SetAuthenticationValues(spt, &v) - if err != nil { - return err - } +func (spt *ServicePrincipalToken) getGrantType() string { + switch spt.inner.Secret.(type) { + case *ServicePrincipalUsernamePasswordSecret: + return OAuthGrantTypeUserPass + case *ServicePrincipalAuthorizationCodeSecret: + return OAuthGrantTypeAuthorizationCode + default: + return OAuthGrantTypeClientCredentials } +} - s := v.Encode() - body := ioutil.NopCloser(strings.NewReader(s)) - req, err := http.NewRequest(http.MethodPost, spt.oauthConfig.TokenEndpoint.String(), body) +func isIMDS(u url.URL) bool { + imds, err := url.Parse(msiEndpoint) + if err != nil { + return false + } + return u.Host == imds.Host && u.Path == imds.Path +} + +func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource string) error { + req, err := http.NewRequest(http.MethodPost, spt.inner.OauthConfig.TokenEndpoint.String(), nil) if err != nil { return fmt.Errorf("adal: Failed to build the refresh request. Error = '%v'", err) } + req.Header.Add("User-Agent", version.UserAgent()) + req = req.WithContext(ctx) + if !isIMDS(spt.inner.OauthConfig.TokenEndpoint) { + v := url.Values{} + v.Set("client_id", spt.inner.ClientID) + v.Set("resource", resource) - req.ContentLength = int64(len(s)) - req.Header.Set(contentType, mimeTypeFormPost) - if _, ok := spt.secret.(*ServicePrincipalMSISecret); ok { + if spt.inner.Token.RefreshToken != "" { + v.Set("grant_type", OAuthGrantTypeRefreshToken) + v.Set("refresh_token", spt.inner.Token.RefreshToken) + // web apps must specify client_secret when refreshing tokens + // see https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code#refreshing-the-access-tokens + if spt.getGrantType() == OAuthGrantTypeAuthorizationCode { + err := spt.inner.Secret.SetAuthenticationValues(spt, &v) + if err != nil { + return err + } + } + } else { + v.Set("grant_type", spt.getGrantType()) + err := spt.inner.Secret.SetAuthenticationValues(spt, &v) + if err != nil { + return err + } + } + + s := v.Encode() + body := ioutil.NopCloser(strings.NewReader(s)) + req.ContentLength = int64(len(s)) + req.Header.Set(contentType, mimeTypeFormPost) + req.Body = body + } + + if _, ok := spt.inner.Secret.(*ServicePrincipalMSISecret); ok { + req.Method = http.MethodGet req.Header.Set(metadataHeader, "true") } - resp, err := spt.sender.Do(req) - if err != nil { - return fmt.Errorf("adal: Failed to execute the refresh request. Error = '%v'", err) + + var resp *http.Response + if isIMDS(spt.inner.OauthConfig.TokenEndpoint) { + resp, err = retryForIMDS(spt.sender, req, spt.MaxMSIRefreshAttempts) + } else { + resp, err = spt.sender.Do(req) } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("adal: Refresh request failed. Status Code = '%d'", resp.StatusCode) + if err != nil { + return newTokenRefreshError(fmt.Sprintf("adal: Failed to execute the refresh request. Error = '%v'", err), nil) } + defer resp.Body.Close() rb, err := ioutil.ReadAll(resp.Body) + + if resp.StatusCode != http.StatusOK { + if err != nil { + return newTokenRefreshError(fmt.Sprintf("adal: Refresh request failed. Status Code = '%d'. Failed reading response body: %v", resp.StatusCode, err), resp) + } + return newTokenRefreshError(fmt.Sprintf("adal: Refresh request failed. Status Code = '%d'. Response body: %s", resp.StatusCode, string(rb)), resp) + } + + // for the following error cases don't return a TokenRefreshError. the operation succeeded + // but some transient failure happened during deserialization. by returning a generic error + // the retry logic will kick in (we don't retry on TokenRefreshError). + if err != nil { return fmt.Errorf("adal: Failed to read a new service principal token during refresh. Error = '%v'", err) } @@ -392,23 +853,116 @@ func (spt *ServicePrincipalToken) refreshInternal(resource string) error { return fmt.Errorf("adal: Failed to unmarshal the service principal token during refresh. Error = '%v' JSON = '%s'", err, string(rb)) } - spt.Token = token + spt.inner.Token = token return spt.InvokeRefreshCallbacks(token) } +// retry logic specific to retrieving a token from the IMDS endpoint +func retryForIMDS(sender Sender, req *http.Request, maxAttempts int) (resp *http.Response, err error) { + // copied from client.go due to circular dependency + retries := []int{ + http.StatusRequestTimeout, // 408 + http.StatusTooManyRequests, // 429 + http.StatusInternalServerError, // 500 + http.StatusBadGateway, // 502 + http.StatusServiceUnavailable, // 503 + http.StatusGatewayTimeout, // 504 + } + // extra retry status codes specific to IMDS + retries = append(retries, + http.StatusNotFound, + http.StatusGone, + // all remaining 5xx + http.StatusNotImplemented, + http.StatusHTTPVersionNotSupported, + http.StatusVariantAlsoNegotiates, + http.StatusInsufficientStorage, + http.StatusLoopDetected, + http.StatusNotExtended, + http.StatusNetworkAuthenticationRequired) + + // see https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/how-to-use-vm-token#retry-guidance + + const maxDelay time.Duration = 60 * time.Second + + attempt := 0 + delay := time.Duration(0) + + for attempt < maxAttempts { + resp, err = sender.Do(req) + // retry on temporary network errors, e.g. transient network failures. + // if we don't receive a response then assume we can't connect to the + // endpoint so we're likely not running on an Azure VM so don't retry. + if (err != nil && !isTemporaryNetworkError(err)) || resp == nil || resp.StatusCode == http.StatusOK || !containsInt(retries, resp.StatusCode) { + return + } + + // perform exponential backoff with a cap. + // must increment attempt before calculating delay. + attempt++ + // the base value of 2 is the "delta backoff" as specified in the guidance doc + delay += (time.Duration(math.Pow(2, float64(attempt))) * time.Second) + if delay > maxDelay { + delay = maxDelay + } + + select { + case <-time.After(delay): + // intentionally left blank + case <-req.Context().Done(): + err = req.Context().Err() + return + } + } + return +} + +// returns true if the specified error is a temporary network error or false if it's not. +// if the error doesn't implement the net.Error interface the return value is true. +func isTemporaryNetworkError(err error) bool { + if netErr, ok := err.(net.Error); !ok || (ok && netErr.Temporary()) { + return true + } + return false +} + +// returns true if slice ints contains the value n +func containsInt(ints []int, n int) bool { + for _, i := range ints { + if i == n { + return true + } + } + return false +} + // SetAutoRefresh enables or disables automatic refreshing of stale tokens. func (spt *ServicePrincipalToken) SetAutoRefresh(autoRefresh bool) { - spt.autoRefresh = autoRefresh + spt.inner.AutoRefresh = autoRefresh } // SetRefreshWithin sets the interval within which if the token will expire, EnsureFresh will // refresh the token. func (spt *ServicePrincipalToken) SetRefreshWithin(d time.Duration) { - spt.refreshWithin = d + spt.inner.RefreshWithin = d return } // SetSender sets the http.Client used when obtaining the Service Principal token. An // undecorated http.Client is used by default. func (spt *ServicePrincipalToken) SetSender(s Sender) { spt.sender = s } + +// OAuthToken implements the OAuthTokenProvider interface. It returns the current access token. +func (spt *ServicePrincipalToken) OAuthToken() string { + spt.refreshLock.RLock() + defer spt.refreshLock.RUnlock() + return spt.inner.Token.OAuthToken() +} + +// Token returns a copy of the current token. +func (spt *ServicePrincipalToken) Token() Token { + spt.refreshLock.RLock() + defer spt.refreshLock.RUnlock() + return spt.inner.Token +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/authorization.go b/vendor/github.com/Azure/go-autorest/autorest/authorization.go index 314ed7876..77eff45bd 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/authorization.go +++ b/vendor/github.com/Azure/go-autorest/autorest/authorization.go @@ -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,25 @@ func (ba *BearerAuthorizer) withBearerAuthorization() PrepareDecorator { func (ba *BearerAuthorizer) WithAuthorization() PrepareDecorator { return func(p Preparer) Preparer { return PreparerFunc(func(r *http.Request) (*http.Request, error) { - refresher, ok := ba.tokenProvider.(adal.Refresher) - if ok { - err := refresher.EnsureFresh() + r, err := p.Prepare(r) + if err == nil { + // the ordering is important here, prefer RefresherWithContext if available + if refresher, ok := ba.tokenProvider.(adal.RefresherWithContext); ok { + err = refresher.EnsureFreshWithContext(r.Context()) + } else if refresher, ok := ba.tokenProvider.(adal.Refresher); ok { + err = refresher.EnsureFresh() + } if err != nil { - return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", nil, + var resp *http.Response + if tokError, ok := err.(adal.TokenRefreshError); ok { + resp = tokError.Response() + } + return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", resp, "Failed to refresh the Token for request to %s", r.URL) } + return Prepare(r, WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", ba.tokenProvider.OAuthToken()))) } - return (ba.withBearerAuthorization()(p)).Prepare(r) + return r, err }) } } @@ -89,25 +159,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 +238,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() +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/autorest.go b/vendor/github.com/Azure/go-autorest/autorest/autorest.go index 51f1c4bbc..aafdf021f 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/autorest.go +++ b/vendor/github.com/Azure/go-autorest/autorest/autorest.go @@ -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 +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/async.go b/vendor/github.com/Azure/go-autorest/autorest/azure/async.go index 332a8909d..9dd7a1d27 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/async.go +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/async.go @@ -1,15 +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 ( "bytes" + "context" + "encoding/json" "fmt" "io/ioutil" "net/http" + "net/url" "strings" "time" "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/date" ) const ( @@ -23,280 +39,920 @@ const ( operationSucceeded string = "Succeeded" ) -// 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 -// closing the optional channel on the http.Request. -func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator { - return func(s autorest.Sender) autorest.Sender { - return autorest.SenderFunc(func(r *http.Request) (resp *http.Response, err error) { - resp, err = s.Do(r) - if err != nil { - return resp, err - } - pollingCodes := []int{http.StatusAccepted, http.StatusCreated, http.StatusOK} - if !autorest.ResponseHasStatusCode(resp, pollingCodes...) { - return resp, nil - } +var pollingCodes = [...]int{http.StatusNoContent, http.StatusAccepted, http.StatusCreated, http.StatusOK} - ps := pollingState{} - for err == nil { - err = updatePollingState(resp, &ps) - if err != nil { - break - } - if ps.hasTerminated() { - if !ps.hasSucceeded() { - err = ps - } - break - } +// Future provides a mechanism to access the status and results of an asynchronous request. +// Since futures are stateful they should be passed by value to avoid race conditions. +type Future struct { + req *http.Request // legacy + pt pollingTracker +} - r, err = newPollingRequest(resp, ps) - if err != nil { - return resp, err - } +// NewFuture returns a new Future object initialized with the specified request. +// Deprecated: Please use NewFutureFromResponse instead. +func NewFuture(req *http.Request) Future { + return Future{req: req} +} - delay = autorest.GetRetryAfter(resp, delay) - resp, err = autorest.SendWithSender(s, r, - autorest.AfterDelay(delay)) - } - - return resp, err - }) +// NewFutureFromResponse returns a new Future object initialized +// with the initial response from an asynchronous operation. +func NewFutureFromResponse(resp *http.Response) (Future, error) { + pt, err := createPollingTracker(resp) + if err != nil { + return Future{}, err } + return Future{pt: pt}, nil } -func getAsyncOperation(resp *http.Response) string { - return resp.Header.Get(http.CanonicalHeaderKey(headerAsyncOperation)) -} - -func hasSucceeded(state string) bool { - return state == operationSucceeded -} - -func hasTerminated(state string) bool { - switch state { - case operationCanceled, operationFailed, operationSucceeded: - return true - default: - return false +// Response returns the last HTTP response. +func (f Future) Response() *http.Response { + if f.pt == nil { + return nil } + return f.pt.latestResponse() } -func hasFailed(state string) bool { - return state == operationFailed -} - -type provisioningTracker interface { - state() string - hasSucceeded() bool - hasTerminated() bool -} - -type operationResource struct { - // Note: - // The specification states services should return the "id" field. However some return it as - // "operationId". - ID string `json:"id"` - OperationID string `json:"operationId"` - Name string `json:"name"` - Status string `json:"status"` - Properties map[string]interface{} `json:"properties"` - OperationError ServiceError `json:"error"` - StartTime date.Time `json:"startTime"` - EndTime date.Time `json:"endTime"` - PercentComplete float64 `json:"percentComplete"` -} - -func (or operationResource) state() string { - return or.Status -} - -func (or operationResource) hasSucceeded() bool { - return hasSucceeded(or.state()) -} - -func (or operationResource) hasTerminated() bool { - return hasTerminated(or.state()) -} - -type provisioningProperties struct { - ProvisioningState string `json:"provisioningState"` -} - -type provisioningStatus struct { - Properties provisioningProperties `json:"properties,omitempty"` - ProvisioningError ServiceError `json:"error,omitempty"` -} - -func (ps provisioningStatus) state() string { - return ps.Properties.ProvisioningState -} - -func (ps provisioningStatus) hasSucceeded() bool { - return hasSucceeded(ps.state()) -} - -func (ps provisioningStatus) hasTerminated() bool { - return hasTerminated(ps.state()) -} - -func (ps provisioningStatus) hasProvisioningError() bool { - return ps.ProvisioningError != ServiceError{} -} - -type pollingResponseFormat string - -const ( - usesOperationResponse pollingResponseFormat = "OperationResponse" - usesProvisioningStatus pollingResponseFormat = "ProvisioningStatus" - formatIsUnknown pollingResponseFormat = "" -) - -type pollingState struct { - responseFormat pollingResponseFormat - uri string - state string - code string - message string -} - -func (ps pollingState) hasSucceeded() bool { - return hasSucceeded(ps.state) -} - -func (ps pollingState) hasTerminated() bool { - return hasTerminated(ps.state) -} - -func (ps pollingState) hasFailed() bool { - 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) -} - -// updatePollingState maps the operation status -- retrieved from either a provisioningState -// field, the status field of an OperationResource, or inferred from the HTTP status code -- -// into a well-known states. Since the process begins from the initial request, the state -// always comes from either a the provisioningState returned or is inferred from the HTTP -// status code. Subsequent requests will read an Azure OperationResource object if the -// service initially returned the Azure-AsyncOperation header. The responseFormat field notes -// the expected response format. -func updatePollingState(resp *http.Response, ps *pollingState) error { - // Determine the response shape - // -- 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 { - pt = &operationResource{} - } else { - pt = &provisioningStatus{} +// Status returns the last status message of the operation. +func (f Future) Status() string { + if f.pt == nil { + return "" } + return f.pt.pollingStatus() +} - // 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 { - req := resp.Request - if req == nil { - return autorest.NewError("azure", "updatePollingState", "Azure Polling Error - Original HTTP request is missing") +// PollingMethod returns the method used to monitor the status of the asynchronous operation. +func (f Future) PollingMethod() PollingMethodType { + if f.pt == nil { + return PollingUnknown + } + return f.pt.pollingMethod() +} + +// Done queries the service to see if the operation has completed. +func (f *Future) Done(sender autorest.Sender) (bool, error) { + // support for legacy Future implementation + if f.req != nil { + resp, err := sender.Do(f.req) + if err != nil { + return false, err } + pt, err := createPollingTracker(resp) + if err != nil { + return false, err + } + f.pt = pt + f.req = nil + } + // end legacy + if f.pt == nil { + return false, autorest.NewError("Future", "Done", "future is not initialized") + } + if f.pt.hasTerminated() { + return true, f.pt.pollingError() + } + if err := f.pt.pollForStatus(sender); err != nil { + return false, err + } + if err := f.pt.checkForErrors(); err != nil { + return f.pt.hasTerminated(), err + } + if err := f.pt.updatePollingState(f.pt.provisioningStateApplicable()); err != nil { + return false, err + } + if err := f.pt.initPollingMethod(); err != nil { + return false, err + } + if err := f.pt.updatePollingMethod(); err != nil { + return false, err + } + return f.pt.hasTerminated(), f.pt.pollingError() +} - // Prefer the Azure-AsyncOperation header - ps.uri = getAsyncOperation(resp) - if ps.uri != "" { - ps.responseFormat = usesOperationResponse +// GetPollingDelay returns a duration the application should wait before checking +// the status of the asynchronous request and true; this value is returned from +// the service via the Retry-After response header. If the header wasn't returned +// then the function returns the zero-value time.Duration and false. +func (f Future) GetPollingDelay() (time.Duration, bool) { + if f.pt == nil { + return 0, false + } + resp := f.pt.latestResponse() + if resp == nil { + return 0, false + } + + retry := resp.Header.Get(autorest.HeaderRetryAfter) + if retry == "" { + return 0, false + } + + d, err := time.ParseDuration(retry + "s") + if err != nil { + panic(err) + } + + return d, true +} + +// WaitForCompletion will return when one of the following conditions is met: the long +// running operation has completed, the provided context is cancelled, or the client's +// polling duration has been exceeded. It will retry failed polling attempts based on +// the retry value defined in the client up to the maximum retry attempts. +// Deprecated: Please use WaitForCompletionRef() instead. +func (f Future) WaitForCompletion(ctx context.Context, client autorest.Client) error { + return f.WaitForCompletionRef(ctx, client) +} + +// WaitForCompletionRef will return when one of the following conditions is met: the long +// running operation has completed, the provided context is cancelled, or the client's +// polling duration has been exceeded. It will retry failed polling attempts based on +// the retry value defined in the client up to the maximum retry attempts. +func (f *Future) WaitForCompletionRef(ctx context.Context, client autorest.Client) error { + ctx, cancel := context.WithTimeout(ctx, client.PollingDuration) + defer cancel() + done, err := f.Done(client) + for attempts := 0; !done; done, err = f.Done(client) { + if attempts >= client.RetryAttempts { + return autorest.NewErrorWithError(err, "Future", "WaitForCompletion", f.pt.latestResponse(), "the number of retries has been exceeded") + } + // we want delayAttempt to be zero in the non-error case so + // that DelayForBackoff doesn't perform exponential back-off + var delayAttempt int + var delay time.Duration + if err == nil { + // check for Retry-After delay, if not present use the client's polling delay + var ok bool + delay, ok = f.GetPollingDelay() + if !ok { + delay = client.PollingDelay + } } else { - ps.responseFormat = usesProvisioningStatus + // 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++ } - - // Else, use the Location header - if ps.uri == "" { - ps.uri = autorest.GetLocation(resp) - } - - // Lastly, requests against an existing resource, use the last request URI - if ps.uri == "" { - m := strings.ToUpper(req.Method) - if m == http.MethodPatch || m == http.MethodPut || m == http.MethodGet { - ps.uri = req.URL.String() - } + // wait until the delay elapses or the context is cancelled + delayElapsed := autorest.DelayForBackoff(delay, delayAttempt, ctx.Done()) + if !delayElapsed { + return autorest.NewErrorWithError(ctx.Err(), "Future", "WaitForCompletion", f.pt.latestResponse(), "context has been cancelled") } } + return err +} - // Read and interpret the response (saving the Body in case no polling is necessary) - b := &bytes.Buffer{} - err := autorest.Respond(resp, - autorest.ByCopying(b), - autorest.ByUnmarshallingJSON(pt), - autorest.ByClosing()) - resp.Body = ioutil.NopCloser(b) +// MarshalJSON implements the json.Marshaler interface. +func (f Future) MarshalJSON() ([]byte, error) { + return json.Marshal(f.pt) +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (f *Future) UnmarshalJSON(data []byte) error { + // unmarshal into JSON object to determine the tracker type + obj := map[string]interface{}{} + err := json.Unmarshal(data, &obj) if err != nil { return err } + if obj["method"] == nil { + return autorest.NewError("Future", "UnmarshalJSON", "missing 'method' property") + } + method := obj["method"].(string) + switch strings.ToUpper(method) { + case http.MethodDelete: + f.pt = &pollingTrackerDelete{} + case http.MethodPatch: + f.pt = &pollingTrackerPatch{} + case http.MethodPost: + f.pt = &pollingTrackerPost{} + case http.MethodPut: + f.pt = &pollingTrackerPut{} + default: + return autorest.NewError("Future", "UnmarshalJSON", "unsupoorted method '%s'", method) + } + // now unmarshal into the tracker + return json.Unmarshal(data, &f.pt) +} - // Interpret the results - // -- Terminal states apply regardless - // -- Unknown states are per-service inprogress states - // -- Otherwise, infer state from HTTP status code - if pt.hasTerminated() { - ps.state = pt.state() - } else if pt.state() != "" { - ps.state = operationInProgress - } else { - switch resp.StatusCode { - case http.StatusAccepted: - ps.state = operationInProgress +// PollingURL returns the URL used for retrieving the status of the long-running operation. +func (f Future) PollingURL() string { + if f.pt == nil { + return "" + } + return f.pt.pollingURL() +} - case http.StatusNoContent, http.StatusCreated, http.StatusOK: - ps.state = operationSucceeded +// GetResult should be called once polling has completed successfully. +// It makes the final GET call to retrieve the resultant payload. +func (f Future) GetResult(sender autorest.Sender) (*http.Response, error) { + if f.pt.finalGetURL() == "" { + // we can end up in this situation if the async operation returns a 200 + // with no polling URLs. in that case return the response which should + // contain the JSON payload (only do this for successful terminal cases). + if lr := f.pt.latestResponse(); lr != nil && f.pt.hasSucceeded() { + return lr, nil + } + return nil, autorest.NewError("Future", "GetResult", "missing URL for retrieving result") + } + req, err := http.NewRequest(http.MethodGet, f.pt.finalGetURL(), nil) + if err != nil { + return nil, err + } + return sender.Do(req) +} - default: - ps.state = operationFailed +type pollingTracker interface { + // these methods can differ per tracker + + // checks the response headers and status code to determine the polling mechanism + updatePollingMethod() error + + // checks the response for tracker-specific error conditions + checkForErrors() error + + // returns true if provisioning state should be checked + provisioningStateApplicable() bool + + // methods common to all trackers + + // initializes a tracker's polling URL and method, called for each iteration. + // these values can be overridden by each polling tracker as required. + initPollingMethod() error + + // initializes the tracker's internal state, call this when the tracker is created + initializeState() error + + // makes an HTTP request to check the status of the LRO + pollForStatus(sender autorest.Sender) error + + // updates internal tracker state, call this after each call to pollForStatus + updatePollingState(provStateApl bool) error + + // returns the error response from the service, can be nil + pollingError() error + + // returns the polling method being used + pollingMethod() PollingMethodType + + // returns the state of the LRO as returned from the service + pollingStatus() string + + // returns the URL used for polling status + pollingURL() string + + // returns the URL used for the final GET to retrieve the resource + finalGetURL() string + + // returns true if the LRO is in a terminal state + hasTerminated() bool + + // returns true if the LRO is in a failed terminal state + hasFailed() bool + + // returns true if the LRO is in a successful terminal state + hasSucceeded() bool + + // returns the cached HTTP response after a call to pollForStatus(), can be nil + latestResponse() *http.Response +} + +type pollingTrackerBase struct { + // resp is the last response, either from the submission of the LRO or from polling + resp *http.Response + + // method is the HTTP verb, this is needed for deserialization + Method string `json:"method"` + + // rawBody is the raw JSON response body + rawBody map[string]interface{} + + // denotes if polling is using async-operation or location header + Pm PollingMethodType `json:"pollingMethod"` + + // the URL to poll for status + URI string `json:"pollingURI"` + + // the state of the LRO as returned from the service + State string `json:"lroState"` + + // the URL to GET for the final result + FinalGetURI string `json:"resultURI"` + + // used to hold an error object returned from the service + Err *ServiceError `json:"error,omitempty"` +} + +func (pt *pollingTrackerBase) initializeState() error { + // determine the initial polling state based on response body and/or HTTP status + // code. this is applicable to the initial LRO response, not polling responses! + pt.Method = pt.resp.Request.Method + if err := pt.updateRawBody(); err != nil { + return err + } + switch pt.resp.StatusCode { + case http.StatusOK: + if ps := pt.getProvisioningState(); ps != nil { + pt.State = *ps + if pt.hasFailed() { + pt.updateErrorFromResponse() + return pt.pollingError() + } + } else { + pt.State = operationSucceeded + } + case http.StatusCreated: + if ps := pt.getProvisioningState(); ps != nil { + pt.State = *ps + } else { + pt.State = operationInProgress + } + case http.StatusAccepted: + pt.State = operationInProgress + case http.StatusNoContent: + pt.State = operationSucceeded + default: + pt.State = operationFailed + pt.updateErrorFromResponse() + return pt.pollingError() + } + return pt.initPollingMethod() +} + +func (pt pollingTrackerBase) getProvisioningState() *string { + if pt.rawBody != nil && pt.rawBody["properties"] != nil { + p := pt.rawBody["properties"].(map[string]interface{}) + if ps := p["provisioningState"]; ps != nil { + s := ps.(string) + return &s } } + return nil +} - if 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) +func (pt *pollingTrackerBase) updateRawBody() error { + pt.rawBody = map[string]interface{}{} + if pt.resp.ContentLength != 0 { + defer pt.resp.Body.Close() + b, err := ioutil.ReadAll(pt.resp.Body) + if err != nil { + return autorest.NewErrorWithError(err, "pollingTrackerBase", "updateRawBody", nil, "failed to read response body") + } + // put the body back so it's available to other callers + pt.resp.Body = ioutil.NopCloser(bytes.NewReader(b)) + if err = json.Unmarshal(b, &pt.rawBody); err != nil { + return autorest.NewErrorWithError(err, "pollingTrackerBase", "updateRawBody", nil, "failed to unmarshal response body") + } } + return nil +} - // For failed operation, check for error code and message in - // -- Operation resource - // -- Response - // -- Otherwise, Unknown - if ps.hasFailed() { - if ps.responseFormat == usesOperationResponse { - or := pt.(*operationResource) - ps.code = or.OperationError.Code - ps.message = or.OperationError.Message - } else { - p := pt.(*provisioningStatus) - if p.hasProvisioningError() { - ps.code = p.ProvisioningError.Code - ps.message = p.ProvisioningError.Message +func (pt *pollingTrackerBase) pollForStatus(sender autorest.Sender) error { + req, err := http.NewRequest(http.MethodGet, pt.URI, nil) + if err != nil { + return autorest.NewErrorWithError(err, "pollingTrackerBase", "pollForStatus", nil, "failed to create HTTP request") + } + // attach the context from the original request if available (it will be absent for deserialized futures) + if pt.resp != nil { + req = req.WithContext(pt.resp.Request.Context()) + } + pt.resp, err = sender.Do(req) + if err != nil { + return autorest.NewErrorWithError(err, "pollingTrackerBase", "pollForStatus", nil, "failed to send HTTP request") + } + if autorest.ResponseHasStatusCode(pt.resp, pollingCodes[:]...) { + // reset the service error on success case + pt.Err = nil + err = pt.updateRawBody() + } else { + // check response body for error content + pt.updateErrorFromResponse() + err = pt.pollingError() + } + return err +} + +// attempts to unmarshal a ServiceError type from the response body. +// if that fails then make a best attempt at creating something meaningful. +// NOTE: this assumes that the async operation has failed. +func (pt *pollingTrackerBase) updateErrorFromResponse() { + var err error + if pt.resp.ContentLength != 0 { + type respErr struct { + ServiceError *ServiceError `json:"error"` + } + re := respErr{} + defer pt.resp.Body.Close() + var b []byte + if b, err = ioutil.ReadAll(pt.resp.Body); err != nil { + goto Default + } + if err = json.Unmarshal(b, &re); err != nil { + goto Default + } + // unmarshalling the error didn't yield anything, try unwrapped error + if re.ServiceError == nil { + err = json.Unmarshal(b, &re.ServiceError) + if err != nil { + goto Default + } + } + // the unmarshaller will ensure re.ServiceError is non-nil + // even if there was no content unmarshalled so check the code. + if re.ServiceError.Code != "" { + pt.Err = re.ServiceError + return + } + } +Default: + se := &ServiceError{ + Code: pt.pollingStatus(), + Message: "The async operation failed.", + } + if err != nil { + se.InnerError = make(map[string]interface{}) + se.InnerError["unmarshalError"] = err.Error() + } + // stick the response body into the error object in hopes + // it contains something useful to help diagnose the failure. + if len(pt.rawBody) > 0 { + se.AdditionalInfo = []map[string]interface{}{ + pt.rawBody, + } + } + pt.Err = se +} + +func (pt *pollingTrackerBase) updatePollingState(provStateApl bool) error { + if pt.Pm == PollingAsyncOperation && pt.rawBody["status"] != nil { + pt.State = pt.rawBody["status"].(string) + } else { + if pt.resp.StatusCode == http.StatusAccepted { + pt.State = operationInProgress + } else if provStateApl { + if ps := pt.getProvisioningState(); ps != nil { + pt.State = *ps } else { - ps.code = "Unknown" - ps.message = "None" + pt.State = operationSucceeded + } + } else { + return autorest.NewError("pollingTrackerBase", "updatePollingState", "the response from the async operation has an invalid status code") + } + } + // if the operation has failed update the error state + if pt.hasFailed() { + pt.updateErrorFromResponse() + } + return nil +} + +func (pt pollingTrackerBase) pollingError() error { + if pt.Err == nil { + return nil + } + return pt.Err +} + +func (pt pollingTrackerBase) pollingMethod() PollingMethodType { + return pt.Pm +} + +func (pt pollingTrackerBase) pollingStatus() string { + return pt.State +} + +func (pt pollingTrackerBase) pollingURL() string { + return pt.URI +} + +func (pt pollingTrackerBase) finalGetURL() string { + return pt.FinalGetURI +} + +func (pt pollingTrackerBase) hasTerminated() bool { + return strings.EqualFold(pt.State, operationCanceled) || strings.EqualFold(pt.State, operationFailed) || strings.EqualFold(pt.State, operationSucceeded) +} + +func (pt pollingTrackerBase) hasFailed() bool { + return strings.EqualFold(pt.State, operationCanceled) || strings.EqualFold(pt.State, operationFailed) +} + +func (pt pollingTrackerBase) hasSucceeded() bool { + return strings.EqualFold(pt.State, operationSucceeded) +} + +func (pt pollingTrackerBase) latestResponse() *http.Response { + return pt.resp +} + +// error checking common to all trackers +func (pt pollingTrackerBase) baseCheckForErrors() error { + // for Azure-AsyncOperations the response body cannot be nil or empty + if pt.Pm == PollingAsyncOperation { + if pt.resp.Body == nil || pt.resp.ContentLength == 0 { + return autorest.NewError("pollingTrackerBase", "baseCheckForErrors", "for Azure-AsyncOperation response body cannot be nil") + } + if pt.rawBody["status"] == nil { + return autorest.NewError("pollingTrackerBase", "baseCheckForErrors", "missing status property in Azure-AsyncOperation response body") + } + } + return nil +} + +// default initialization of polling URL/method. each verb tracker will update this as required. +func (pt *pollingTrackerBase) initPollingMethod() error { + if ao, err := getURLFromAsyncOpHeader(pt.resp); err != nil { + return err + } else if ao != "" { + pt.URI = ao + pt.Pm = PollingAsyncOperation + return nil + } + if lh, err := getURLFromLocationHeader(pt.resp); err != nil { + return err + } else if lh != "" { + pt.URI = lh + pt.Pm = PollingLocation + return nil + } + // it's ok if we didn't find a polling header, this will be handled elsewhere + return nil +} + +// DELETE + +type pollingTrackerDelete struct { + pollingTrackerBase +} + +func (pt *pollingTrackerDelete) updatePollingMethod() error { + // for 201 the Location header is required + if pt.resp.StatusCode == http.StatusCreated { + if lh, err := getURLFromLocationHeader(pt.resp); err != nil { + return err + } else if lh == "" { + return autorest.NewError("pollingTrackerDelete", "updateHeaders", "missing Location header in 201 response") + } else { + pt.URI = lh + } + pt.Pm = PollingLocation + pt.FinalGetURI = pt.URI + } + // for 202 prefer the Azure-AsyncOperation header but fall back to Location if necessary + if pt.resp.StatusCode == http.StatusAccepted { + ao, err := getURLFromAsyncOpHeader(pt.resp) + if err != nil { + return err + } else if ao != "" { + pt.URI = ao + pt.Pm = PollingAsyncOperation + } + // if the Location header is invalid and we already have a polling URL + // then we don't care if the Location header URL is malformed. + if lh, err := getURLFromLocationHeader(pt.resp); err != nil && pt.URI == "" { + return err + } else if lh != "" { + if ao == "" { + pt.URI = lh + pt.Pm = PollingLocation + } + // when both headers are returned we use the value in the Location header for the final GET + pt.FinalGetURI = lh + } + // make sure a polling URL was found + if pt.URI == "" { + return autorest.NewError("pollingTrackerPost", "updateHeaders", "didn't get any suitable polling URLs in 202 response") + } + } + return nil +} + +func (pt pollingTrackerDelete) checkForErrors() error { + return pt.baseCheckForErrors() +} + +func (pt pollingTrackerDelete) provisioningStateApplicable() bool { + return pt.resp.StatusCode == http.StatusOK || pt.resp.StatusCode == http.StatusNoContent +} + +// PATCH + +type pollingTrackerPatch struct { + pollingTrackerBase +} + +func (pt *pollingTrackerPatch) updatePollingMethod() error { + // by default we can use the original URL for polling and final GET + if pt.URI == "" { + pt.URI = pt.resp.Request.URL.String() + } + if pt.FinalGetURI == "" { + pt.FinalGetURI = pt.resp.Request.URL.String() + } + if pt.Pm == PollingUnknown { + pt.Pm = PollingRequestURI + } + // for 201 it's permissible for no headers to be returned + if pt.resp.StatusCode == http.StatusCreated { + if ao, err := getURLFromAsyncOpHeader(pt.resp); err != nil { + return err + } else if ao != "" { + pt.URI = ao + pt.Pm = PollingAsyncOperation + } + } + // for 202 prefer the Azure-AsyncOperation header but fall back to Location if necessary + // note the absense of the "final GET" mechanism for PATCH + if pt.resp.StatusCode == http.StatusAccepted { + ao, err := getURLFromAsyncOpHeader(pt.resp) + if err != nil { + return err + } else if ao != "" { + pt.URI = ao + pt.Pm = PollingAsyncOperation + } + if ao == "" { + if lh, err := getURLFromLocationHeader(pt.resp); err != nil { + return err + } else if lh == "" { + return autorest.NewError("pollingTrackerPatch", "updateHeaders", "didn't get any suitable polling URLs in 202 response") + } else { + pt.URI = lh + pt.Pm = PollingLocation } } } return nil } -func 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}, - autorest.AsGet(), - autorest.WithBaseURL(ps.uri)) - if err != nil { - return nil, autorest.NewErrorWithError(err, "azure", "newPollingRequest", nil, "Failure creating poll request to %s", ps.uri) - } - - return reqPoll, nil +func (pt pollingTrackerPatch) checkForErrors() error { + return pt.baseCheckForErrors() +} + +func (pt pollingTrackerPatch) provisioningStateApplicable() bool { + return pt.resp.StatusCode == http.StatusOK || pt.resp.StatusCode == http.StatusCreated +} + +// POST + +type pollingTrackerPost struct { + pollingTrackerBase +} + +func (pt *pollingTrackerPost) updatePollingMethod() error { + // 201 requires Location header + if pt.resp.StatusCode == http.StatusCreated { + if lh, err := getURLFromLocationHeader(pt.resp); err != nil { + return err + } else if lh == "" { + return autorest.NewError("pollingTrackerPost", "updateHeaders", "missing Location header in 201 response") + } else { + pt.URI = lh + pt.FinalGetURI = lh + pt.Pm = PollingLocation + } + } + // for 202 prefer the Azure-AsyncOperation header but fall back to Location if necessary + if pt.resp.StatusCode == http.StatusAccepted { + ao, err := getURLFromAsyncOpHeader(pt.resp) + if err != nil { + return err + } else if ao != "" { + pt.URI = ao + pt.Pm = PollingAsyncOperation + } + // if the Location header is invalid and we already have a polling URL + // then we don't care if the Location header URL is malformed. + if lh, err := getURLFromLocationHeader(pt.resp); err != nil && pt.URI == "" { + return err + } else if lh != "" { + if ao == "" { + pt.URI = lh + pt.Pm = PollingLocation + } + // when both headers are returned we use the value in the Location header for the final GET + pt.FinalGetURI = lh + } + // make sure a polling URL was found + if pt.URI == "" { + return autorest.NewError("pollingTrackerPost", "updateHeaders", "didn't get any suitable polling URLs in 202 response") + } + } + return nil +} + +func (pt pollingTrackerPost) checkForErrors() error { + return pt.baseCheckForErrors() +} + +func (pt pollingTrackerPost) provisioningStateApplicable() bool { + return pt.resp.StatusCode == http.StatusOK || pt.resp.StatusCode == http.StatusNoContent +} + +// PUT + +type pollingTrackerPut struct { + pollingTrackerBase +} + +func (pt *pollingTrackerPut) updatePollingMethod() error { + // by default we can use the original URL for polling and final GET + if pt.URI == "" { + pt.URI = pt.resp.Request.URL.String() + } + if pt.FinalGetURI == "" { + pt.FinalGetURI = pt.resp.Request.URL.String() + } + if pt.Pm == PollingUnknown { + pt.Pm = PollingRequestURI + } + // for 201 it's permissible for no headers to be returned + if pt.resp.StatusCode == http.StatusCreated { + if ao, err := getURLFromAsyncOpHeader(pt.resp); err != nil { + return err + } else if ao != "" { + pt.URI = ao + pt.Pm = PollingAsyncOperation + } + } + // for 202 prefer the Azure-AsyncOperation header but fall back to Location if necessary + if pt.resp.StatusCode == http.StatusAccepted { + ao, err := getURLFromAsyncOpHeader(pt.resp) + if err != nil { + return err + } else if ao != "" { + pt.URI = ao + pt.Pm = PollingAsyncOperation + } + // if the Location header is invalid and we already have a polling URL + // then we don't care if the Location header URL is malformed. + if lh, err := getURLFromLocationHeader(pt.resp); err != nil && pt.URI == "" { + return err + } else if lh != "" { + if ao == "" { + pt.URI = lh + pt.Pm = PollingLocation + } + // when both headers are returned we use the value in the Location header for the final GET + pt.FinalGetURI = lh + } + // make sure a polling URL was found + if pt.URI == "" { + return autorest.NewError("pollingTrackerPut", "updateHeaders", "didn't get any suitable polling URLs in 202 response") + } + } + return nil +} + +func (pt pollingTrackerPut) checkForErrors() error { + err := pt.baseCheckForErrors() + if err != nil { + return err + } + // if there are no LRO headers then the body cannot be empty + ao, err := getURLFromAsyncOpHeader(pt.resp) + if err != nil { + return err + } + lh, err := getURLFromLocationHeader(pt.resp) + if err != nil { + return err + } + if ao == "" && lh == "" && len(pt.rawBody) == 0 { + return autorest.NewError("pollingTrackerPut", "checkForErrors", "the response did not contain a body") + } + return nil +} + +func (pt pollingTrackerPut) provisioningStateApplicable() bool { + return pt.resp.StatusCode == http.StatusOK || pt.resp.StatusCode == http.StatusCreated +} + +// creates a polling tracker based on the verb of the original request +func createPollingTracker(resp *http.Response) (pollingTracker, error) { + var pt pollingTracker + switch strings.ToUpper(resp.Request.Method) { + case http.MethodDelete: + pt = &pollingTrackerDelete{pollingTrackerBase: pollingTrackerBase{resp: resp}} + case http.MethodPatch: + pt = &pollingTrackerPatch{pollingTrackerBase: pollingTrackerBase{resp: resp}} + case http.MethodPost: + pt = &pollingTrackerPost{pollingTrackerBase: pollingTrackerBase{resp: resp}} + case http.MethodPut: + pt = &pollingTrackerPut{pollingTrackerBase: pollingTrackerBase{resp: resp}} + default: + return nil, autorest.NewError("azure", "createPollingTracker", "unsupported HTTP method %s", resp.Request.Method) + } + if err := pt.initializeState(); err != nil { + return pt, err + } + // this initializes the polling header values, we do this during creation in case the + // initial response send us invalid values; this way the API call will return a non-nil + // error (not doing this means the error shows up in Future.Done) + return pt, pt.updatePollingMethod() +} + +// gets the polling URL from the Azure-AsyncOperation header. +// ensures the URL is well-formed and absolute. +func getURLFromAsyncOpHeader(resp *http.Response) (string, error) { + s := resp.Header.Get(http.CanonicalHeaderKey(headerAsyncOperation)) + if s == "" { + return "", nil + } + if !isValidURL(s) { + return "", autorest.NewError("azure", "getURLFromAsyncOpHeader", "invalid polling URL '%s'", s) + } + return s, nil +} + +// gets the polling URL from the Location header. +// ensures the URL is well-formed and absolute. +func getURLFromLocationHeader(resp *http.Response) (string, error) { + s := resp.Header.Get(http.CanonicalHeaderKey(autorest.HeaderLocation)) + if s == "" { + return "", nil + } + if !isValidURL(s) { + return "", autorest.NewError("azure", "getURLFromLocationHeader", "invalid polling URL '%s'", s) + } + return s, nil +} + +// verify that the URL is valid and absolute +func isValidURL(s string) bool { + u, err := url.Parse(s) + return err == nil && u.IsAbs() +} + +// DoPollForAsynchronous returns a SendDecorator that polls if the http.Response is for an Azure +// long-running operation. It will delay between requests for the duration specified in the +// RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled via +// the context associated with the http.Request. +// Deprecated: Prefer using Futures to allow for non-blocking async operations. +func DoPollForAsynchronous(delay time.Duration) autorest.SendDecorator { + return func(s autorest.Sender) autorest.Sender { + return autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { + resp, err := s.Do(r) + if err != nil { + return resp, err + } + if !autorest.ResponseHasStatusCode(resp, pollingCodes[:]...) { + return resp, nil + } + future, err := NewFutureFromResponse(resp) + if err != nil { + return resp, err + } + // retry until either the LRO completes or we receive an error + var done bool + for done, err = future.Done(s); !done && err == nil; done, err = future.Done(s) { + // check for Retry-After delay, if not present use the specified polling delay + if pd, ok := future.GetPollingDelay(); ok { + delay = pd + } + // wait until the delay elapses or the context is cancelled + if delayElapsed := autorest.DelayForBackoff(delay, 0, r.Context().Done()); !delayElapsed { + return future.Response(), + autorest.NewErrorWithError(r.Context().Err(), "azure", "DoPollForAsynchronous", future.Response(), "context has been cancelled") + } + } + return future.Response(), err + }) + } +} + +// PollingMethodType defines a type used for enumerating polling mechanisms. +type PollingMethodType string + +const ( + // PollingAsyncOperation indicates the polling method uses the Azure-AsyncOperation header. + PollingAsyncOperation PollingMethodType = "AsyncOperation" + + // PollingLocation indicates the polling method uses the Location header. + PollingLocation PollingMethodType = "Location" + + // PollingRequestURI indicates the polling method uses the original request URI. + PollingRequestURI PollingMethodType = "RequestURI" + + // PollingUnknown indicates an unknown polling method and is the default value. + PollingUnknown PollingMethodType = "" +) + +// AsyncOpIncompleteError is the type that's returned from a future that has not completed. +type AsyncOpIncompleteError struct { + // FutureType is the name of the type composed of a azure.Future. + FutureType string +} + +// Error returns an error message including the originating type name of the error. +func (e AsyncOpIncompleteError) Error() string { + return fmt.Sprintf("%s: asynchronous operation has not completed", e.FutureType) +} + +// NewAsyncOpIncompleteError creates a new AsyncOpIncompleteError with the specified parameters. +func NewAsyncOpIncompleteError(futureType string) AsyncOpIncompleteError { + return AsyncOpIncompleteError{ + FutureType: futureType, + } } diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go b/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go index 3f4d13421..3a0a439ff 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/azure.go @@ -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,100 @@ 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"` + AdditionalInfo []map[string]interface{} `json:"additionalInfo"` } 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)) + } + + if se.AdditionalInfo != nil { + d, err := json.Marshal(se.AdditionalInfo) + if err != nil { + result += fmt.Sprintf(" AdditionalInfo=%v", se.AdditionalInfo) + } + result += fmt.Sprintf(" AdditionalInfo=%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"` + AdditionalInfo []map[string]interface{} `json:"additionalInfo"` + } + + 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"` + AdditionalInfo []map[string]interface{} `json:"additionalInfo"` + } + + se1 := serviceError1{} + err := json.Unmarshal(b, &se1) + if err == nil { + se.populate(se1.Code, se1.Message, se1.Target, se1.Details, se1.InnerError, se1.AdditionalInfo) + return nil + } + + se2 := serviceError2{} + err = json.Unmarshal(b, &se2) + if err == nil { + se.populate(se2.Code, se2.Message, se2.Target, nil, se2.InnerError, se2.AdditionalInfo) + 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{}, additional []map[string]interface{}) { + se.Code = code + se.Message = message + se.Target = target + se.Details = details + se.InnerError = inner + se.AdditionalInfo = additional } // RequestError describes an error response returned by Azure service. @@ -69,6 +161,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 @@ -164,10 +291,29 @@ func WithErrorUnlessStatusCode(codes ...int) autorest.RespondDecorator { resp.Body = ioutil.NopCloser(&b) if decodeErr != nil { return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b.String(), decodeErr) - } else if e.ServiceError == nil { - e.ServiceError = &ServiceError{Code: "Unknown", Message: "Unknown service error"} } - + if e.ServiceError == nil { + // Check if error is unwrapped ServiceError + if err := json.Unmarshal(b.Bytes(), &e.ServiceError); err != nil { + return err + } + } + if e.ServiceError.Message == "" { + // if we're here it means the returned error wasn't OData v4 compliant. + // try to unmarshal the body as raw JSON in hopes of getting something. + rawBody := map[string]interface{}{} + if err := json.Unmarshal(b.Bytes(), &rawBody); err != nil { + return err + } + e.ServiceError = &ServiceError{ + Code: "Unknown", + Message: "Unknown service error", + } + if len(rawBody) > 0 { + e.ServiceError.Details = []map[string]interface{}{rawBody} + } + } + e.Response = resp e.RequestID = ExtractRequestID(resp) if e.StatusCode == nil { e.StatusCode = resp.StatusCode diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/cli/profile.go b/vendor/github.com/Azure/go-autorest/autorest/azure/cli/profile.go new file mode 100644 index 000000000..b62bf03ba --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/cli/profile.go @@ -0,0 +1,72 @@ +package cli + +// Copyright 2017 Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + + "github.com/dimchansky/utfbom" + "github.com/mitchellh/go-homedir" +) + +// Profile represents a Profile from the Azure CLI +type Profile struct { + InstallationID string `json:"installationId"` + Subscriptions []Subscription `json:"subscriptions"` +} + +// Subscription represents a Subscription from the Azure CLI +type Subscription struct { + EnvironmentName string `json:"environmentName"` + ID string `json:"id"` + IsDefault bool `json:"isDefault"` + Name string `json:"name"` + State string `json:"state"` + TenantID string `json:"tenantId"` + User *User `json:"user"` +} + +// User represents a User from the Azure CLI +type User struct { + Name string `json:"name"` + Type string `json:"type"` +} + +// ProfilePath returns the path where the Azure Profile is stored from the Azure CLI +func ProfilePath() (string, error) { + return homedir.Expand("~/.azure/azureProfile.json") +} + +// LoadProfile restores a Profile object from a file located at 'path'. +func LoadProfile(path string) (result Profile, err error) { + var contents []byte + contents, err = ioutil.ReadFile(path) + if err != nil { + err = fmt.Errorf("failed to open file (%s) while loading token: %v", path, err) + return + } + reader := utfbom.SkipOnly(bytes.NewReader(contents)) + + dec := json.NewDecoder(reader) + if err = dec.Decode(&result); err != nil { + err = fmt.Errorf("failed to decode contents of file (%s) into a Profile representation: %v", path, err) + return + } + + return +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/cli/token.go b/vendor/github.com/Azure/go-autorest/autorest/azure/cli/token.go new file mode 100644 index 000000000..83b81c34b --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/cli/token.go @@ -0,0 +1,114 @@ +package cli + +// 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" + "os" + "strconv" + "time" + + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/go-autorest/autorest/date" + "github.com/mitchellh/go-homedir" +) + +// Token represents an AccessToken from the Azure CLI +type Token struct { + AccessToken string `json:"accessToken"` + Authority string `json:"_authority"` + ClientID string `json:"_clientId"` + ExpiresOn string `json:"expiresOn"` + IdentityProvider string `json:"identityProvider"` + IsMRRT bool `json:"isMRRT"` + RefreshToken string `json:"refreshToken"` + Resource string `json:"resource"` + TokenType string `json:"tokenType"` + UserID string `json:"userId"` +} + +// ToADALToken converts an Azure CLI `Token`` to an `adal.Token`` +func (t Token) ToADALToken() (converted adal.Token, err error) { + tokenExpirationDate, err := ParseExpirationDate(t.ExpiresOn) + if err != nil { + err = fmt.Errorf("Error parsing Token Expiration Date %q: %+v", t.ExpiresOn, err) + return + } + + difference := tokenExpirationDate.Sub(date.UnixEpoch()) + + converted = adal.Token{ + AccessToken: t.AccessToken, + Type: t.TokenType, + ExpiresIn: "3600", + ExpiresOn: strconv.Itoa(int(difference.Seconds())), + RefreshToken: t.RefreshToken, + Resource: t.Resource, + } + return +} + +// AccessTokensPath returns the path where access tokens are stored from the Azure CLI +// TODO(#199): add unit test. +func AccessTokensPath() (string, error) { + // Azure-CLI allows user to customize the path of access tokens thorugh environment variable. + var accessTokenPath = os.Getenv("AZURE_ACCESS_TOKEN_FILE") + var err error + + // Fallback logic to default path on non-cloud-shell environment. + // TODO(#200): remove the dependency on hard-coding path. + if accessTokenPath == "" { + accessTokenPath, err = homedir.Expand("~/.azure/accessTokens.json") + } + + return accessTokenPath, err +} + +// ParseExpirationDate parses either a Azure CLI or CloudShell date into a time object +func ParseExpirationDate(input string) (*time.Time, error) { + // CloudShell (and potentially the Azure CLI in future) + expirationDate, cloudShellErr := time.Parse(time.RFC3339, input) + if cloudShellErr != nil { + // Azure CLI (Python) e.g. 2017-08-31 19:48:57.998857 (plus the local timezone) + const cliFormat = "2006-01-02 15:04:05.999999" + expirationDate, cliErr := time.ParseInLocation(cliFormat, input, time.Local) + if cliErr == nil { + return &expirationDate, nil + } + + return nil, fmt.Errorf("Error parsing expiration date %q.\n\nCloudShell Error: \n%+v\n\nCLI Error:\n%+v", input, cloudShellErr, cliErr) + } + + return &expirationDate, nil +} + +// LoadTokens restores a set of Token objects from a file located at 'path'. +func LoadTokens(path string) ([]Token, error) { + file, err := os.Open(path) + if err != nil { + return nil, fmt.Errorf("failed to open file (%s) while loading token: %v", path, err) + } + defer file.Close() + + var tokens []Token + + dec := json.NewDecoder(file) + if err = dec.Decode(&tokens); err != nil { + return nil, fmt.Errorf("failed to decode contents of file (%s) into a `cli.Token` representation: %v", path, err) + } + + return tokens, nil +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go b/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go index 1cf55651f..7e41f7fd9 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/environments.go @@ -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 +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/metadata_environment.go b/vendor/github.com/Azure/go-autorest/autorest/azure/metadata_environment.go new file mode 100644 index 000000000..507f9e95c --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/metadata_environment.go @@ -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 +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/azure/rp.go b/vendor/github.com/Azure/go-autorest/autorest/azure/rp.go new file mode 100644 index 000000000..bd34f0ed5 --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/azure/rp.go @@ -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, 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 "" +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/client.go b/vendor/github.com/Azure/go-autorest/autorest/client.go index 5f1e72fbe..5c558c83a 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/client.go +++ b/vendor/github.com/Azure/go-autorest/autorest/client.go @@ -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" @@ -8,8 +22,11 @@ import ( "log" "net/http" "net/http/cookiejar" - "runtime" + "strings" "time" + + "github.com/Azure/go-autorest/logger" + "github.com/Azure/go-autorest/version" ) const ( @@ -21,19 +38,14 @@ 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 ( - // defaultUserAgent builds a string containing the Go version, system archityecture and OS, - // and the go-autorest version. - defaultUserAgent = fmt.Sprintf("Go/%s (%s-%s) go-autorest/%s", - runtime.Version(), - runtime.GOARCH, - runtime.GOOS, - Version(), - ) - - statusCodesForRetry = []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 +160,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 +172,10 @@ func NewClientWithUserAgent(ua string) Client { PollingDelay: DefaultPollingDelay, PollingDuration: DefaultPollingDuration, RetryAttempts: DefaultRetryAttempts, - RetryDuration: 30 * time.Second, - UserAgent: defaultUserAgent, + RetryDuration: DefaultRetryDuration, + UserAgent: version.UserAgent(), } + c.Sender = c.sender() c.AddToUserAgent(ua) return c } @@ -181,16 +197,31 @@ 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()) + logger.Instance.WriteRequest(r, logger.Filter{ + Header: func(k string, v []string) (bool, []string) { + // remove the auth token from the log + if strings.EqualFold(k, "Authorization") || strings.EqualFold(k, "Ocp-Apim-Subscription-Key") { + v = []string{"**REDACTED**"} + } + return true, v + }, + }) + resp, err := SendWithSender(c.sender(), r) + logger.Instance.WriteResponse(resp, logger.Filter{}) + Respond(resp, c.ByInspecting()) return resp, err } diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/date.go b/vendor/github.com/Azure/go-autorest/autorest/date/date.go index 80ca60e9b..c45710656 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/date/date.go +++ b/vendor/github.com/Azure/go-autorest/autorest/date/date.go @@ -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" diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/time.go b/vendor/github.com/Azure/go-autorest/autorest/date/time.go index c1af62963..b453fad04 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/date/time.go +++ b/vendor/github.com/Azure/go-autorest/autorest/date/time.go @@ -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" diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go b/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go index 11995fb9f..48fb39ba9 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go +++ b/vendor/github.com/Azure/go-autorest/autorest/date/timerfc1123.go @@ -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" diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/unixtime.go b/vendor/github.com/Azure/go-autorest/autorest/date/unixtime.go index e085c77ee..7073959b2 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/date/unixtime.go +++ b/vendor/github.com/Azure/go-autorest/autorest/date/unixtime.go @@ -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" diff --git a/vendor/github.com/Azure/go-autorest/autorest/date/utility.go b/vendor/github.com/Azure/go-autorest/autorest/date/utility.go index 207b1a240..12addf0eb 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/date/utility.go +++ b/vendor/github.com/Azure/go-autorest/autorest/date/utility.go @@ -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" diff --git a/vendor/github.com/Azure/go-autorest/autorest/error.go b/vendor/github.com/Azure/go-autorest/autorest/error.go index aaef2ac8e..f724f3332 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/error.go +++ b/vendor/github.com/Azure/go-autorest/autorest/error.go @@ -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" diff --git a/vendor/github.com/Azure/go-autorest/autorest/preparer.go b/vendor/github.com/Azure/go-autorest/autorest/preparer.go index afd114821..6d67bd733 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/preparer.go +++ b/vendor/github.com/Azure/go-autorest/autorest/preparer.go @@ -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 }) diff --git a/vendor/github.com/Azure/go-autorest/autorest/responder.go b/vendor/github.com/Azure/go-autorest/autorest/responder.go index 87f71e585..a908a0adb 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/responder.go +++ b/vendor/github.com/Azure/go-autorest/autorest/responder.go @@ -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" diff --git a/vendor/github.com/Azure/go-autorest/autorest/retriablerequest.go b/vendor/github.com/Azure/go-autorest/autorest/retriablerequest.go index 0ab1eb300..fa11dbed7 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/retriablerequest.go +++ b/vendor/github.com/Azure/go-autorest/autorest/retriablerequest.go @@ -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" diff --git a/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.7.go b/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.7.go index e28eb2cbd..7143cc61b 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.7.go +++ b/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.7.go @@ -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 } diff --git a/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.8.go b/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.8.go index 8c1d1aec8..ae15c6bf9 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.8.go +++ b/vendor/github.com/Azure/go-autorest/autorest/retriablerequest_1.8.go @@ -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 } diff --git a/vendor/github.com/Azure/go-autorest/autorest/sender.go b/vendor/github.com/Azure/go-autorest/autorest/sender.go index 94b029847..cacbd8157 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/sender.go +++ b/vendor/github.com/Azure/go-autorest/autorest/sender.go @@ -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,29 @@ 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...) { + // if the error isn't temporary don't bother retrying + if err != nil && !IsTemporaryNetworkError(err) { + return nil, err + } + // we want to retry if err is not nil (e.g. transient network failure). note that for failed authentication + // resp and err will both have a value, so in this case we don't want to retry as it will never succeed. + if err == nil && !ResponseHasStatusCode(resp, codes...) || IsTokenRefreshError(err) { return resp, err } - delayed := DelayWithRetryAfter(resp, r.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 +250,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 +283,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 }) diff --git a/vendor/github.com/Azure/go-autorest/autorest/to/convert.go b/vendor/github.com/Azure/go-autorest/autorest/to/convert.go index 7b180b866..fdda2ce1a 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/to/convert.go +++ b/vendor/github.com/Azure/go-autorest/autorest/to/convert.go @@ -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 { diff --git a/vendor/github.com/Azure/go-autorest/autorest/utility.go b/vendor/github.com/Azure/go-autorest/autorest/utility.go index 78067148b..bfddd90b5 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/utility.go +++ b/vendor/github.com/Azure/go-autorest/autorest/utility.go @@ -1,15 +1,32 @@ package autorest +// Copyright 2017 Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + import ( "bytes" "encoding/json" "encoding/xml" "fmt" "io" + "net" + "net/http" "net/url" "reflect" - "sort" "strings" + + "github.com/Azure/go-autorest/autorest/adal" ) // EncodedAs is a series of constants specifying various data encodings @@ -123,13 +140,38 @@ func MapToValues(m map[string]interface{}) url.Values { return v } -// String method converts interface v to string. If interface is a list, it -// joins list elements using separator. -func String(v interface{}, sep ...string) string { - if len(sep) > 0 { - return ensureValueString(strings.Join(v.([]string), sep[0])) +// AsStringSlice method converts interface{} to []string. This expects a +//that the parameter passed to be a slice or array of a type that has the underlying +//type a string. +func AsStringSlice(s interface{}) ([]string, error) { + v := reflect.ValueOf(s) + if v.Kind() != reflect.Slice && v.Kind() != reflect.Array { + return nil, NewError("autorest", "AsStringSlice", "the value's type is not an array.") } - return ensureValueString(v) + stringSlice := make([]string, 0, v.Len()) + + for i := 0; i < v.Len(); i++ { + stringSlice = append(stringSlice, v.Index(i).String()) + } + return stringSlice, nil +} + +// String method converts interface v to string. If interface is a list, it +// joins list elements using the seperator. Note that only sep[0] will be used for +// joining if any separator is specified. +func String(v interface{}, sep ...string) string { + if len(sep) == 0 { + return ensureValueString(v) + } + stringSlice, ok := v.([]string) + if ok == false { + var err error + stringSlice, err = AsStringSlice(v) + if err != nil { + panic(fmt.Sprintf("autorest: Couldn't convert value to a string %s.", err)) + } + } + return ensureValueString(strings.Join(stringSlice, sep[0])) } // Encode method encodes url path and query parameters. @@ -153,26 +195,34 @@ func queryEscape(s string) string { return url.QueryEscape(s) } -// This method is same as Encode() method of "net/url" go package, -// except it does not encode the query parameters because they -// already come encoded. It formats values map in query format (bar=foo&a=b). -func createQuery(v url.Values) string { - var buf bytes.Buffer - keys := make([]string, 0, len(v)) - for k := range v { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - vs := v[k] - prefix := url.QueryEscape(k) + "=" - for _, v := range vs { - if buf.Len() > 0 { - buf.WriteByte('&') - } - buf.WriteString(prefix) - buf.WriteString(v) - } - } - return buf.String() +// ChangeToGet turns the specified http.Request into a GET (it assumes it wasn't). +// This is mainly useful for long-running operations that use the Azure-AsyncOperation +// header, so we change the initial PUT into a GET to retrieve the final result. +func ChangeToGet(req *http.Request) *http.Request { + req.Method = "GET" + req.Body = nil + req.ContentLength = 0 + req.Header.Del("Content-Length") + return req +} + +// IsTokenRefreshError returns true if the specified error implements the TokenRefreshError +// interface. If err is a DetailedError it will walk the chain of Original errors. +func IsTokenRefreshError(err error) bool { + if _, ok := err.(adal.TokenRefreshError); ok { + return true + } + if de, ok := err.(DetailedError); ok { + return IsTokenRefreshError(de.Original) + } + return false +} + +// IsTemporaryNetworkError returns true if the specified error is a temporary network error or false +// if it's not. If the error doesn't implement the net.Error interface the return value is true. +func IsTemporaryNetworkError(err error) bool { + if netErr, ok := err.(net.Error); !ok || (ok && netErr.Temporary()) { + return true + } + return false } diff --git a/vendor/github.com/Azure/go-autorest/autorest/validation/error.go b/vendor/github.com/Azure/go-autorest/autorest/validation/error.go new file mode 100644 index 000000000..fed156dbf --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/autorest/validation/error.go @@ -0,0 +1,48 @@ +package validation + +// 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" +) + +// Error is the type that's returned when the validation of an APIs arguments constraints fails. +type Error struct { + // PackageType is the package type of the object emitting the error. For types, the value + // matches that produced the the '%T' format specifier of the fmt package. For other elements, + // such as functions, it is just the package name (e.g., "autorest"). + PackageType string + + // Method is the name of the method raising the error. + Method string + + // Message is the error message. + Message string +} + +// Error returns a string containing the details of the validation failure. +func (e Error) Error() string { + return fmt.Sprintf("%s#%s: Invalid input: %s", e.PackageType, e.Method, e.Message) +} + +// NewError creates a new Error object with the specified parameters. +// message is treated as a format string to which the optional args apply. +func NewError(packageType string, method string, message string, args ...interface{}) Error { + return Error{ + PackageType: packageType, + Method: method, + Message: fmt.Sprintf(message, args...), + } +} diff --git a/vendor/github.com/Azure/go-autorest/autorest/validation/validation.go b/vendor/github.com/Azure/go-autorest/autorest/validation/validation.go index 38f0074d0..ae987f8fa 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/validation/validation.go +++ b/vendor/github.com/Azure/go-autorest/autorest/validation/validation.go @@ -3,6 +3,20 @@ Package validation provides methods for validating parameter value using reflect */ package validation +// 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" "reflect" @@ -91,15 +105,12 @@ func validateStruct(x reflect.Value, v Constraint, name ...string) error { return createError(x, v, fmt.Sprintf("field %q doesn't exist", v.Target)) } - if err := Validate([]Validation{ + return Validate([]Validation{ { TargetValue: getInterfaceValue(f), Constraints: []Constraint{v}, }, - }); err != nil { - return err - } - return nil + }) } func validatePtr(x reflect.Value, v Constraint) error { @@ -125,29 +136,29 @@ func validatePtr(x reflect.Value, v Constraint) error { func validateInt(x reflect.Value, v Constraint) error { i := x.Int() - r, ok := v.Rule.(int) + r, ok := toInt64(v.Rule) if !ok { return createError(x, v, fmt.Sprintf("rule must be integer value for %v constraint; got: %v", v.Name, v.Rule)) } switch v.Name { case MultipleOf: - if i%int64(r) != 0 { + if i%r != 0 { return createError(x, v, fmt.Sprintf("value must be a multiple of %v", r)) } case ExclusiveMinimum: - if i <= int64(r) { + if i <= r { return createError(x, v, fmt.Sprintf("value must be greater than %v", r)) } case ExclusiveMaximum: - if i >= int64(r) { + if i >= r { return createError(x, v, fmt.Sprintf("value must be less than %v", r)) } case InclusiveMinimum: - if i < int64(r) { + if i < r { return createError(x, v, fmt.Sprintf("value must be greater than or equal to %v", r)) } case InclusiveMaximum: - if i > int64(r) { + if i > r { return createError(x, v, fmt.Sprintf("value must be less than or equal to %v", r)) } default: @@ -377,8 +388,21 @@ func createError(x reflect.Value, v Constraint, err string) error { v.Target, v.Name, getInterfaceValue(x), err) } +func toInt64(v interface{}) (int64, bool) { + if i64, ok := v.(int64); ok { + return i64, true + } + // older generators emit max constants as int, so if int64 fails fall back to int + if i32, ok := v.(int); ok { + return int64(i32), true + } + return 0, false +} + // NewErrorWithValidationError appends package type and method name in // validation error. +// +// Deprecated: Please use validation.NewError() instead. func NewErrorWithValidationError(err error, packageType, method string) error { - return fmt.Errorf("%s#%s: Invalid input: %v", packageType, method, err) + return NewError(packageType, method, err.Error()) } diff --git a/vendor/github.com/Azure/go-autorest/autorest/version.go b/vendor/github.com/Azure/go-autorest/autorest/version.go index a222e8efa..3c6451546 100644 --- a/vendor/github.com/Azure/go-autorest/autorest/version.go +++ b/vendor/github.com/Azure/go-autorest/autorest/version.go @@ -1,35 +1,22 @@ package autorest -import ( - "bytes" - "fmt" - "strings" - "sync" -) +import "github.com/Azure/go-autorest/version" -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 version.Number } diff --git a/vendor/github.com/Azure/go-autorest/logger/logger.go b/vendor/github.com/Azure/go-autorest/logger/logger.go new file mode 100644 index 000000000..756fd80ca --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/logger/logger.go @@ -0,0 +1,328 @@ +package logger + +// Copyright 2017 Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "strings" + "sync" + "time" +) + +// LevelType tells a logger the minimum level to log. When code reports a log entry, +// the LogLevel indicates the level of the log entry. The logger only records entries +// whose level is at least the level it was told to log. See the Log* constants. +// For example, if a logger is configured with LogError, then LogError, LogPanic, +// and LogFatal entries will be logged; lower level entries are ignored. +type LevelType uint32 + +const ( + // LogNone tells a logger not to log any entries passed to it. + LogNone LevelType = iota + + // LogFatal tells a logger to log all LogFatal entries passed to it. + LogFatal + + // LogPanic tells a logger to log all LogPanic and LogFatal entries passed to it. + LogPanic + + // LogError tells a logger to log all LogError, LogPanic and LogFatal entries passed to it. + LogError + + // LogWarning tells a logger to log all LogWarning, LogError, LogPanic and LogFatal entries passed to it. + LogWarning + + // LogInfo tells a logger to log all LogInfo, LogWarning, LogError, LogPanic and LogFatal entries passed to it. + LogInfo + + // LogDebug tells a logger to log all LogDebug, LogInfo, LogWarning, LogError, LogPanic and LogFatal entries passed to it. + LogDebug +) + +const ( + logNone = "NONE" + logFatal = "FATAL" + logPanic = "PANIC" + logError = "ERROR" + logWarning = "WARNING" + logInfo = "INFO" + logDebug = "DEBUG" + logUnknown = "UNKNOWN" +) + +// ParseLevel converts the specified string into the corresponding LevelType. +func ParseLevel(s string) (lt LevelType, err error) { + switch strings.ToUpper(s) { + case logFatal: + lt = LogFatal + case logPanic: + lt = LogPanic + case logError: + lt = LogError + case logWarning: + lt = LogWarning + case logInfo: + lt = LogInfo + case logDebug: + lt = LogDebug + default: + err = fmt.Errorf("bad log level '%s'", s) + } + return +} + +// String implements the stringer interface for LevelType. +func (lt LevelType) String() string { + switch lt { + case LogNone: + return logNone + case LogFatal: + return logFatal + case LogPanic: + return logPanic + case LogError: + return logError + case LogWarning: + return logWarning + case LogInfo: + return logInfo + case LogDebug: + return logDebug + default: + return logUnknown + } +} + +// Filter defines functions for filtering HTTP request/response content. +type Filter struct { + // URL returns a potentially modified string representation of a request URL. + URL func(u *url.URL) string + + // Header returns a potentially modified set of values for the specified key. + // To completely exclude the header key/values return false. + Header func(key string, val []string) (bool, []string) + + // Body returns a potentially modified request/response body. + Body func(b []byte) []byte +} + +func (f Filter) processURL(u *url.URL) string { + if f.URL == nil { + return u.String() + } + return f.URL(u) +} + +func (f Filter) processHeader(k string, val []string) (bool, []string) { + if f.Header == nil { + return true, val + } + return f.Header(k, val) +} + +func (f Filter) processBody(b []byte) []byte { + if f.Body == nil { + return b + } + return f.Body(b) +} + +// Writer defines methods for writing to a logging facility. +type Writer interface { + // Writeln writes the specified message with the standard log entry header and new-line character. + Writeln(level LevelType, message string) + + // Writef writes the specified format specifier with the standard log entry header and no new-line character. + Writef(level LevelType, format string, a ...interface{}) + + // WriteRequest writes the specified HTTP request to the logger if the log level is greater than + // or equal to LogInfo. The request body, if set, is logged at level LogDebug or higher. + // Custom filters can be specified to exclude URL, header, and/or body content from the log. + // By default no request content is excluded. + WriteRequest(req *http.Request, filter Filter) + + // WriteResponse writes the specified HTTP response to the logger if the log level is greater than + // or equal to LogInfo. The response body, if set, is logged at level LogDebug or higher. + // Custom filters can be specified to exclude URL, header, and/or body content from the log. + // By default no respone content is excluded. + WriteResponse(resp *http.Response, filter Filter) +} + +// Instance is the default log writer initialized during package init. +// This can be replaced with a custom implementation as required. +var Instance Writer + +// default log level +var logLevel = LogNone + +// Level returns the value specified in AZURE_GO_AUTOREST_LOG_LEVEL. +// If no value was specified the default value is LogNone. +// Custom loggers can call this to retrieve the configured log level. +func Level() LevelType { + return logLevel +} + +func init() { + // separated for testing purposes + initDefaultLogger() +} + +func initDefaultLogger() { + // init with nilLogger so callers don't have to do a nil check on Default + Instance = nilLogger{} + llStr := strings.ToLower(os.Getenv("AZURE_GO_SDK_LOG_LEVEL")) + if llStr == "" { + return + } + var err error + logLevel, err = ParseLevel(llStr) + if err != nil { + fmt.Fprintf(os.Stderr, "go-autorest: failed to parse log level: %s\n", err.Error()) + return + } + if logLevel == LogNone { + return + } + // default to stderr + dest := os.Stderr + lfStr := os.Getenv("AZURE_GO_SDK_LOG_FILE") + if strings.EqualFold(lfStr, "stdout") { + dest = os.Stdout + } else if lfStr != "" { + lf, err := os.Create(lfStr) + if err == nil { + dest = lf + } else { + fmt.Fprintf(os.Stderr, "go-autorest: failed to create log file, using stderr: %s\n", err.Error()) + } + } + Instance = fileLogger{ + logLevel: logLevel, + mu: &sync.Mutex{}, + logFile: dest, + } +} + +// the nil logger does nothing +type nilLogger struct{} + +func (nilLogger) Writeln(LevelType, string) {} + +func (nilLogger) Writef(LevelType, string, ...interface{}) {} + +func (nilLogger) WriteRequest(*http.Request, Filter) {} + +func (nilLogger) WriteResponse(*http.Response, Filter) {} + +// A File is used instead of a Logger so the stream can be flushed after every write. +type fileLogger struct { + logLevel LevelType + mu *sync.Mutex // for synchronizing writes to logFile + logFile *os.File +} + +func (fl fileLogger) Writeln(level LevelType, message string) { + fl.Writef(level, "%s\n", message) +} + +func (fl fileLogger) Writef(level LevelType, format string, a ...interface{}) { + if fl.logLevel >= level { + fl.mu.Lock() + defer fl.mu.Unlock() + fmt.Fprintf(fl.logFile, "%s %s", entryHeader(level), fmt.Sprintf(format, a...)) + fl.logFile.Sync() + } +} + +func (fl fileLogger) WriteRequest(req *http.Request, filter Filter) { + if req == nil || fl.logLevel < LogInfo { + return + } + b := &bytes.Buffer{} + fmt.Fprintf(b, "%s REQUEST: %s %s\n", entryHeader(LogInfo), req.Method, filter.processURL(req.URL)) + // dump headers + for k, v := range req.Header { + if ok, mv := filter.processHeader(k, v); ok { + fmt.Fprintf(b, "%s: %s\n", k, strings.Join(mv, ",")) + } + } + if fl.shouldLogBody(req.Header, req.Body) { + // dump body + body, err := ioutil.ReadAll(req.Body) + if err == nil { + fmt.Fprintln(b, string(filter.processBody(body))) + if nc, ok := req.Body.(io.Seeker); ok { + // rewind to the beginning + nc.Seek(0, io.SeekStart) + } else { + // recreate the body + req.Body = ioutil.NopCloser(bytes.NewReader(body)) + } + } else { + fmt.Fprintf(b, "failed to read body: %v\n", err) + } + } + fl.mu.Lock() + defer fl.mu.Unlock() + fmt.Fprint(fl.logFile, b.String()) + fl.logFile.Sync() +} + +func (fl fileLogger) WriteResponse(resp *http.Response, filter Filter) { + if resp == nil || fl.logLevel < LogInfo { + return + } + b := &bytes.Buffer{} + fmt.Fprintf(b, "%s RESPONSE: %d %s\n", entryHeader(LogInfo), resp.StatusCode, filter.processURL(resp.Request.URL)) + // dump headers + for k, v := range resp.Header { + if ok, mv := filter.processHeader(k, v); ok { + fmt.Fprintf(b, "%s: %s\n", k, strings.Join(mv, ",")) + } + } + if fl.shouldLogBody(resp.Header, resp.Body) { + // dump body + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err == nil { + fmt.Fprintln(b, string(filter.processBody(body))) + resp.Body = ioutil.NopCloser(bytes.NewReader(body)) + } else { + fmt.Fprintf(b, "failed to read body: %v\n", err) + } + } + fl.mu.Lock() + defer fl.mu.Unlock() + fmt.Fprint(fl.logFile, b.String()) + fl.logFile.Sync() +} + +// returns true if the provided body should be included in the log +func (fl fileLogger) shouldLogBody(header http.Header, body io.ReadCloser) bool { + ct := header.Get("Content-Type") + return fl.logLevel >= LogDebug && body != nil && strings.Index(ct, "application/octet-stream") == -1 +} + +// creates standard header for log entries, it contains a timestamp and the log level +func entryHeader(level LevelType) string { + // this format provides a fixed number of digits so the size of the timestamp is constant + return fmt.Sprintf("(%s) %s:", time.Now().Format("2006-01-02T15:04:05.0000000Z07:00"), level.String()) +} diff --git a/vendor/github.com/Azure/go-autorest/version/version.go b/vendor/github.com/Azure/go-autorest/version/version.go new file mode 100644 index 000000000..ad2d6099f --- /dev/null +++ b/vendor/github.com/Azure/go-autorest/version/version.go @@ -0,0 +1,37 @@ +package version + +// 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" + "runtime" +) + +// Number contains the semantic version of this SDK. +const Number = "v10.15.4" + +var ( + userAgent = fmt.Sprintf("Go/%s (%s-%s) go-autorest/%s", + runtime.Version(), + runtime.GOARCH, + runtime.GOOS, + Number, + ) +) + +// UserAgent returns a string containing the Go version, system archityecture and OS, and the go-autorest version. +func UserAgent() string { + return userAgent +} diff --git a/vendor/github.com/dimchansky/utfbom/.gitignore b/vendor/github.com/dimchansky/utfbom/.gitignore new file mode 100644 index 000000000..d7ec5cebb --- /dev/null +++ b/vendor/github.com/dimchansky/utfbom/.gitignore @@ -0,0 +1,37 @@ +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib +*.o +*.a + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.prof + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ + +# Gogland +.idea/ \ No newline at end of file diff --git a/vendor/github.com/dimchansky/utfbom/.travis.yml b/vendor/github.com/dimchansky/utfbom/.travis.yml new file mode 100644 index 000000000..df88e37b2 --- /dev/null +++ b/vendor/github.com/dimchansky/utfbom/.travis.yml @@ -0,0 +1,18 @@ +language: go + +go: + - 1.7 + - tip + +# sudo=false makes the build run using a container +sudo: false + +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover + - go get golang.org/x/tools/cmd/goimports + - go get github.com/golang/lint/golint +script: + - gofiles=$(find ./ -name '*.go') && [ -z "$gofiles" ] || unformatted=$(goimports -l $gofiles) && [ -z "$unformatted" ] || (echo >&2 "Go files must be formatted with gofmt. Following files has problem:\n $unformatted" && false) + - golint ./... # This won't break the build, just show warnings + - $HOME/gopath/bin/goveralls -service=travis-ci \ No newline at end of file diff --git a/vendor/github.com/dimchansky/utfbom/LICENSE b/vendor/github.com/dimchansky/utfbom/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/vendor/github.com/dimchansky/utfbom/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/dimchansky/utfbom/README.md b/vendor/github.com/dimchansky/utfbom/README.md new file mode 100644 index 000000000..2f06ecacd --- /dev/null +++ b/vendor/github.com/dimchansky/utfbom/README.md @@ -0,0 +1,81 @@ +# utfbom [![Godoc](https://godoc.org/github.com/dimchansky/utfbom?status.png)](https://godoc.org/github.com/dimchansky/utfbom) [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Build Status](https://travis-ci.org/dimchansky/utfbom.svg?branch=master)](https://travis-ci.org/dimchansky/utfbom) [![Go Report Card](https://goreportcard.com/badge/github.com/dimchansky/utfbom)](https://goreportcard.com/report/github.com/dimchansky/utfbom) [![Coverage Status](https://coveralls.io/repos/github/dimchansky/utfbom/badge.svg?branch=master)](https://coveralls.io/github/dimchansky/utfbom?branch=master) + +The package utfbom implements the detection of the BOM (Unicode Byte Order Mark) and removing as necessary. It can also return the encoding detected by the BOM. + +## Installation + + go get -u github.com/dimchansky/utfbom + +## Example + +```go +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + + "github.com/dimchansky/utfbom" +) + +func main() { + trySkip([]byte("\xEF\xBB\xBFhello")) + trySkip([]byte("hello")) +} + +func trySkip(byteData []byte) { + fmt.Println("Input:", byteData) + + // just skip BOM + output, err := ioutil.ReadAll(utfbom.SkipOnly(bytes.NewReader(byteData))) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("ReadAll with BOM skipping", output) + + // skip BOM and detect encoding + sr, enc := utfbom.Skip(bytes.NewReader(byteData)) + var encStr string + switch enc { + case utfbom.UTF8: + encStr = "UTF8" + case utfbom.UTF16BigEndian: + encStr = "UTF16 big endian" + case utfbom.UTF16LittleEndian: + encStr = "UTF16 little endian" + case utfbom.UTF32BigEndian: + encStr = "UTF32 big endian" + case utfbom.UTF32LittleEndian: + encStr = "UTF32 little endian" + default: + encStr = "Unknown, no byte-order mark found" + } + fmt.Println("Detected encoding:", encStr) + output, err = ioutil.ReadAll(sr) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("ReadAll with BOM detection and skipping", output) + fmt.Println() +} +``` + +Output: + +``` +$ go run main.go +Input: [239 187 191 104 101 108 108 111] +ReadAll with BOM skipping [104 101 108 108 111] +Detected encoding: UTF8 +ReadAll with BOM detection and skipping [104 101 108 108 111] + +Input: [104 101 108 108 111] +ReadAll with BOM skipping [104 101 108 108 111] +Detected encoding: Unknown, no byte-order mark found +ReadAll with BOM detection and skipping [104 101 108 108 111] +``` + + diff --git a/vendor/github.com/dimchansky/utfbom/go.mod b/vendor/github.com/dimchansky/utfbom/go.mod new file mode 100644 index 000000000..4b9ecc6f5 --- /dev/null +++ b/vendor/github.com/dimchansky/utfbom/go.mod @@ -0,0 +1 @@ +module github.com/dimchansky/utfbom \ No newline at end of file diff --git a/vendor/github.com/dimchansky/utfbom/utfbom.go b/vendor/github.com/dimchansky/utfbom/utfbom.go new file mode 100644 index 000000000..648184a12 --- /dev/null +++ b/vendor/github.com/dimchansky/utfbom/utfbom.go @@ -0,0 +1,174 @@ +// Package utfbom implements the detection of the BOM (Unicode Byte Order Mark) and removing as necessary. +// It wraps an io.Reader object, creating another object (Reader) that also implements the io.Reader +// interface but provides automatic BOM checking and removing as necessary. +package utfbom + +import ( + "errors" + "io" +) + +// Encoding is type alias for detected UTF encoding. +type Encoding int + +// Constants to identify detected UTF encodings. +const ( + // Unknown encoding, returned when no BOM was detected + Unknown Encoding = iota + + // UTF8, BOM bytes: EF BB BF + UTF8 + + // UTF-16, big-endian, BOM bytes: FE FF + UTF16BigEndian + + // UTF-16, little-endian, BOM bytes: FF FE + UTF16LittleEndian + + // UTF-32, big-endian, BOM bytes: 00 00 FE FF + UTF32BigEndian + + // UTF-32, little-endian, BOM bytes: FF FE 00 00 + UTF32LittleEndian +) + +const maxConsecutiveEmptyReads = 100 + +// Skip creates Reader which automatically detects BOM (Unicode Byte Order Mark) and removes it as necessary. +// It also returns the encoding detected by the BOM. +// If the detected encoding is not needed, you can call the SkipOnly function. +func Skip(rd io.Reader) (*Reader, Encoding) { + // Is it already a Reader? + b, ok := rd.(*Reader) + if ok { + return b, Unknown + } + + enc, left, err := detectUtf(rd) + return &Reader{ + rd: rd, + buf: left, + err: err, + }, enc +} + +// SkipOnly creates Reader which automatically detects BOM (Unicode Byte Order Mark) and removes it as necessary. +func SkipOnly(rd io.Reader) *Reader { + r, _ := Skip(rd) + return r +} + +// Reader implements automatic BOM (Unicode Byte Order Mark) checking and +// removing as necessary for an io.Reader object. +type Reader struct { + rd io.Reader // reader provided by the client + buf []byte // buffered data + err error // last error +} + +// Read is an implementation of io.Reader interface. +// The bytes are taken from the underlying Reader, but it checks for BOMs, removing them as necessary. +func (r *Reader) Read(p []byte) (n int, err error) { + if len(p) == 0 { + return 0, nil + } + + if r.buf == nil { + if r.err != nil { + return 0, r.readErr() + } + + return r.rd.Read(p) + } + + // copy as much as we can + n = copy(p, r.buf) + r.buf = nilIfEmpty(r.buf[n:]) + return n, nil +} + +func (r *Reader) readErr() error { + err := r.err + r.err = nil + return err +} + +var errNegativeRead = errors.New("utfbom: reader returned negative count from Read") + +func detectUtf(rd io.Reader) (enc Encoding, buf []byte, err error) { + buf, err = readBOM(rd) + + if len(buf) >= 4 { + if isUTF32BigEndianBOM4(buf) { + return UTF32BigEndian, nilIfEmpty(buf[4:]), err + } + if isUTF32LittleEndianBOM4(buf) { + return UTF32LittleEndian, nilIfEmpty(buf[4:]), err + } + } + + if len(buf) > 2 && isUTF8BOM3(buf) { + return UTF8, nilIfEmpty(buf[3:]), err + } + + if (err != nil && err != io.EOF) || (len(buf) < 2) { + return Unknown, nilIfEmpty(buf), err + } + + if isUTF16BigEndianBOM2(buf) { + return UTF16BigEndian, nilIfEmpty(buf[2:]), err + } + if isUTF16LittleEndianBOM2(buf) { + return UTF16LittleEndian, nilIfEmpty(buf[2:]), err + } + + return Unknown, nilIfEmpty(buf), err +} + +func readBOM(rd io.Reader) (buf []byte, err error) { + const maxBOMSize = 4 + var bom [maxBOMSize]byte // used to read BOM + + // read as many bytes as possible + for nEmpty, n := 0, 0; err == nil && len(buf) < maxBOMSize; buf = bom[:len(buf)+n] { + if n, err = rd.Read(bom[len(buf):]); n < 0 { + panic(errNegativeRead) + } + if n > 0 { + nEmpty = 0 + } else { + nEmpty++ + if nEmpty >= maxConsecutiveEmptyReads { + err = io.ErrNoProgress + } + } + } + return +} + +func isUTF32BigEndianBOM4(buf []byte) bool { + return buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0xFE && buf[3] == 0xFF +} + +func isUTF32LittleEndianBOM4(buf []byte) bool { + return buf[0] == 0xFF && buf[1] == 0xFE && buf[2] == 0x00 && buf[3] == 0x00 +} + +func isUTF8BOM3(buf []byte) bool { + return buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF +} + +func isUTF16BigEndianBOM2(buf []byte) bool { + return buf[0] == 0xFE && buf[1] == 0xFF +} + +func isUTF16LittleEndianBOM2(buf []byte) bool { + return buf[0] == 0xFF && buf[1] == 0xFE +} + +func nilIfEmpty(buf []byte) (res []byte) { + if len(buf) > 0 { + res = buf + } + return +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/LICENSE b/vendor/github.com/hashicorp/go-azure-helpers/LICENSE new file mode 100644 index 000000000..be2cc4dfb --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/LICENSE @@ -0,0 +1,362 @@ +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. "Contributor" + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. "Contributor Version" + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. + +1.6. "Executable Form" + + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. + +1.8. "License" + + means this document. + +1.9. "Licensable" + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. + +1.10. "Modifications" + + means any of the following: + + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. "Patent Claims" of a Contributor + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. + +1.12. "Secondary License" + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. "Source Code Form" + + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. + + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice + + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method.go new file mode 100644 index 000000000..d599b2eee --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method.go @@ -0,0 +1,20 @@ +package authentication + +import ( + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" +) + +type authMethod interface { + build(b Builder) (authMethod, error) + + isApplicable(b Builder) bool + + getAuthorizationToken(oauthConfig *adal.OAuthConfig, endpoint string) (*autorest.BearerAuthorizer, error) + + name() string + + populateConfig(c *Config) error + + validate() error +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_azure_cli_parsing.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_azure_cli_parsing.go new file mode 100644 index 000000000..623e68d9e --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_azure_cli_parsing.go @@ -0,0 +1,116 @@ +package authentication + +import ( + "fmt" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/go-autorest/autorest/azure/cli" + "github.com/hashicorp/go-multierror" +) + +type azureCliParsingAuth struct { + profile *azureCLIProfile +} + +func (a azureCliParsingAuth) build(b Builder) (authMethod, error) { + auth := azureCliParsingAuth{ + profile: &azureCLIProfile{ + clientId: b.ClientID, + environment: b.Environment, + subscriptionId: b.SubscriptionID, + tenantId: b.TenantID, + }, + } + profilePath, err := cli.ProfilePath() + if err != nil { + return nil, fmt.Errorf("Error loading the Profile Path from the Azure CLI: %+v", err) + } + + profile, err := cli.LoadProfile(profilePath) + if err != nil { + return nil, fmt.Errorf("Azure CLI Authorization Profile was not found. Please ensure the Azure CLI is installed and then log-in with `az login`.") + } + + auth.profile.profile = profile + + err = auth.profile.populateFields() + if err != nil { + return nil, err + } + + err = auth.profile.populateClientIdAndAccessToken() + if err != nil { + return nil, fmt.Errorf("Error populating Access Tokens from the Azure CLI: %+v", err) + } + + return auth, nil +} + +func (a azureCliParsingAuth) isApplicable(b Builder) bool { + return b.SupportsAzureCliCloudShellParsing +} + +func (a azureCliParsingAuth) getAuthorizationToken(oauthConfig *adal.OAuthConfig, endpoint string) (*autorest.BearerAuthorizer, error) { + if a.profile.usingCloudShell { + // load the refreshed tokens from the CloudShell Azure CLI credentials + err := a.profile.populateClientIdAndAccessToken() + if err != nil { + return nil, fmt.Errorf("Error loading the refreshed CloudShell tokens: %+v", err) + } + } + + spt, err := adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, a.profile.clientId, endpoint, *a.profile.accessToken) + if err != nil { + return nil, err + } + + err = spt.Refresh() + + if err != nil { + return nil, fmt.Errorf("Error refreshing Service Principal Token: %+v", err) + } + + auth := autorest.NewBearerAuthorizer(spt) + return auth, nil +} + +func (a azureCliParsingAuth) name() string { + return "Parsing credentials from the Azure CLI" +} + +func (a azureCliParsingAuth) populateConfig(c *Config) error { + c.ClientID = a.profile.clientId + c.Environment = a.profile.environment + c.SubscriptionID = a.profile.subscriptionId + c.TenantID = a.profile.tenantId + return nil +} + +func (a azureCliParsingAuth) validate() error { + var err *multierror.Error + + errorMessageFmt := "A %s was not found in your Azure CLI Credentials.\n\nPlease login to the Azure CLI again via `az login`" + + if a.profile == nil { + return fmt.Errorf("Azure CLI Profile is nil - this is an internal error and should be reported.") + } + + if a.profile.accessToken == nil { + err = multierror.Append(err, fmt.Errorf(errorMessageFmt, "Access Token")) + } + + if a.profile.clientId == "" { + err = multierror.Append(err, fmt.Errorf(errorMessageFmt, "Client ID")) + } + + if a.profile.subscriptionId == "" { + err = multierror.Append(err, fmt.Errorf(errorMessageFmt, "Subscription ID")) + } + + if a.profile.tenantId == "" { + err = multierror.Append(err, fmt.Errorf(errorMessageFmt, "Tenant ID")) + } + + return err.ErrorOrNil() +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_client_cert.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_client_cert.go new file mode 100644 index 000000000..00a0d2794 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_client_cert.go @@ -0,0 +1,123 @@ +package authentication + +import ( + "crypto/rsa" + "crypto/x509" + "fmt" + "io/ioutil" + "os" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" + "github.com/hashicorp/go-multierror" + "golang.org/x/crypto/pkcs12" +) + +type servicePrincipalClientCertificateAuth struct { + clientId string + clientCertPath string + clientCertPassword string + subscriptionId string + tenantId string +} + +func (a servicePrincipalClientCertificateAuth) build(b Builder) (authMethod, error) { + method := servicePrincipalClientCertificateAuth{ + clientId: b.ClientID, + clientCertPath: b.ClientCertPath, + clientCertPassword: b.ClientCertPassword, + subscriptionId: b.SubscriptionID, + tenantId: b.TenantID, + } + return method, nil +} + +func (a servicePrincipalClientCertificateAuth) isApplicable(b Builder) bool { + return b.SupportsClientCertAuth && b.ClientCertPath != "" +} + +func (a servicePrincipalClientCertificateAuth) name() string { + return "Service Principal / Client Certificate" +} + +func (a servicePrincipalClientCertificateAuth) getAuthorizationToken(oauthConfig *adal.OAuthConfig, endpoint string) (*autorest.BearerAuthorizer, error) { + certificateData, err := ioutil.ReadFile(a.clientCertPath) + if err != nil { + return nil, fmt.Errorf("Error reading Client Certificate %q: %v", a.clientCertPath, err) + } + + // Get the certificate and private key from pfx file + certificate, rsaPrivateKey, err := decodePkcs12(certificateData, a.clientCertPassword) + if err != nil { + return nil, fmt.Errorf("Error decoding pkcs12 certificate: %v", err) + } + + spt, err := adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, a.clientId, certificate, rsaPrivateKey, endpoint) + if err != nil { + return nil, err + } + + err = spt.Refresh() + if err != nil { + return nil, err + } + + auth := autorest.NewBearerAuthorizer(spt) + return auth, nil +} + +func (a servicePrincipalClientCertificateAuth) populateConfig(c *Config) error { + c.AuthenticatedAsAServicePrincipal = true + return nil +} + +func (a servicePrincipalClientCertificateAuth) validate() error { + var err *multierror.Error + + fmtErrorMessage := "A %s must be configured when authenticating as a Service Principal using a Client Certificate." + + if a.subscriptionId == "" { + err = multierror.Append(err, fmt.Errorf(fmtErrorMessage, "Subscription ID")) + } + + if a.clientId == "" { + err = multierror.Append(err, fmt.Errorf(fmtErrorMessage, "Client ID")) + } + + if a.clientCertPath == "" { + err = multierror.Append(err, fmt.Errorf(fmtErrorMessage, "Client Certificate Path")) + } else { + if strings.HasSuffix(strings.ToLower(a.clientCertPath), ".pfx") { + // ensure it exists on disk + _, fileErr := os.Stat(a.clientCertPath) + if os.IsNotExist(fileErr) { + err = multierror.Append(err, fmt.Errorf("Error locating Client Certificate specified at %q: %s", a.clientCertPath, fileErr)) + } + + // we're intentionally /not/ checking it's an actual PFX file at this point, as that happens in the getAuthorizationToken + } else { + err = multierror.Append(err, fmt.Errorf("The Client Certificate Path is not a *.pfx file: %q", a.clientCertPath)) + } + } + + if a.tenantId == "" { + err = multierror.Append(err, fmt.Errorf(fmtErrorMessage, "Tenant ID")) + } + + return err.ErrorOrNil() +} + +func decodePkcs12(pkcs []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) { + privateKey, certificate, err := pkcs12.Decode(pkcs, password) + if err != nil { + return nil, nil, err + } + + rsaPrivateKey, isRsaKey := privateKey.(*rsa.PrivateKey) + if !isRsaKey { + return nil, nil, fmt.Errorf("PKCS#12 certificate must contain an RSA private key") + } + + return certificate, rsaPrivateKey, nil +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_client_secret.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_client_secret.go new file mode 100644 index 000000000..4e41d5a93 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_client_secret.go @@ -0,0 +1,70 @@ +package authentication + +import ( + "fmt" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" + "github.com/hashicorp/go-multierror" +) + +type servicePrincipalClientSecretAuth struct { + clientId string + clientSecret string + subscriptionId string + tenantId string +} + +func (a servicePrincipalClientSecretAuth) build(b Builder) (authMethod, error) { + method := servicePrincipalClientSecretAuth{ + clientId: b.ClientID, + clientSecret: b.ClientSecret, + subscriptionId: b.SubscriptionID, + tenantId: b.TenantID, + } + return method, nil +} + +func (a servicePrincipalClientSecretAuth) isApplicable(b Builder) bool { + return b.SupportsClientSecretAuth && b.ClientSecret != "" +} + +func (a servicePrincipalClientSecretAuth) name() string { + return "Service Principal / Client Secret" +} + +func (a servicePrincipalClientSecretAuth) getAuthorizationToken(oauthConfig *adal.OAuthConfig, endpoint string) (*autorest.BearerAuthorizer, error) { + spt, err := adal.NewServicePrincipalToken(*oauthConfig, a.clientId, a.clientSecret, endpoint) + if err != nil { + return nil, err + } + + auth := autorest.NewBearerAuthorizer(spt) + return auth, nil +} + +func (a servicePrincipalClientSecretAuth) populateConfig(c *Config) error { + c.AuthenticatedAsAServicePrincipal = true + return nil +} + +func (a servicePrincipalClientSecretAuth) validate() error { + var err *multierror.Error + + fmtErrorMessage := "A %s must be configured when authenticating as a Service Principal using a Client Secret." + + if a.subscriptionId == "" { + err = multierror.Append(err, fmt.Errorf(fmtErrorMessage, "Subscription ID")) + } + if a.clientId == "" { + err = multierror.Append(err, fmt.Errorf(fmtErrorMessage, "Client ID")) + } + if a.clientSecret == "" { + err = multierror.Append(err, fmt.Errorf(fmtErrorMessage, "Client Secret")) + } + if a.tenantId == "" { + err = multierror.Append(err, fmt.Errorf(fmtErrorMessage, "Tenant ID")) + } + + return err.ErrorOrNil() +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_msi.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_msi.go new file mode 100644 index 000000000..9b0de8f5d --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/auth_method_msi.go @@ -0,0 +1,64 @@ +package authentication + +import ( + "fmt" + "log" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" + "github.com/hashicorp/go-multierror" +) + +type managedServiceIdentityAuth struct { + endpoint string +} + +func (a managedServiceIdentityAuth) build(b Builder) (authMethod, error) { + endpoint := b.MsiEndpoint + if endpoint == "" { + msiEndpoint, err := adal.GetMSIVMEndpoint() + if err != nil { + return nil, fmt.Errorf("Error determining MSI Endpoint: ensure the VM has MSI enabled, or configure the MSI Endpoint. Error: %s", err) + } + endpoint = msiEndpoint + } + + log.Printf("[DEBUG] Using MSI endpoint %q", endpoint) + + auth := managedServiceIdentityAuth{ + endpoint: endpoint, + } + return auth, nil +} + +func (a managedServiceIdentityAuth) isApplicable(b Builder) bool { + return b.SupportsManagedServiceIdentity +} + +func (a managedServiceIdentityAuth) name() string { + return "Managed Service Identity" +} + +func (a managedServiceIdentityAuth) getAuthorizationToken(oauthConfig *adal.OAuthConfig, endpoint string) (*autorest.BearerAuthorizer, error) { + spt, err := adal.NewServicePrincipalTokenFromMSI(a.endpoint, endpoint) + if err != nil { + return nil, err + } + auth := autorest.NewBearerAuthorizer(spt) + return auth, nil +} + +func (a managedServiceIdentityAuth) populateConfig(c *Config) error { + // nothing to populate back + return nil +} + +func (a managedServiceIdentityAuth) validate() error { + var err *multierror.Error + + if a.endpoint == "" { + err = multierror.Append(err, fmt.Errorf("An MSI Endpoint must be configured")) + } + + return err.ErrorOrNil() +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/azure_cli_access_token.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/azure_cli_access_token.go new file mode 100644 index 000000000..fc35da359 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/azure_cli_access_token.go @@ -0,0 +1,55 @@ +package authentication + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/go-autorest/autorest/azure/cli" +) + +type azureCliAccessToken struct { + ClientID string + AccessToken *adal.Token + IsCloudShell bool +} + +func findValidAccessTokenForTenant(tokens []cli.Token, tenantId string) (*azureCliAccessToken, error) { + for _, accessToken := range tokens { + token, err := accessToken.ToADALToken() + if err != nil { + return nil, fmt.Errorf("[DEBUG] Error converting access token to token: %+v", err) + } + + expirationDate, err := cli.ParseExpirationDate(accessToken.ExpiresOn) + if err != nil { + return nil, fmt.Errorf("Error parsing expiration date: %q", accessToken.ExpiresOn) + } + + if expirationDate.UTC().Before(time.Now().UTC()) { + log.Printf("[DEBUG] Token %q has expired", token.AccessToken) + continue + } + + if !strings.Contains(accessToken.Resource, "management") { + log.Printf("[DEBUG] Resource %q isn't a management domain", accessToken.Resource) + continue + } + + if !strings.HasSuffix(accessToken.Authority, tenantId) { + log.Printf("[DEBUG] Resource %q isn't for the correct Tenant", accessToken.Resource) + continue + } + + validAccessToken := azureCliAccessToken{ + ClientID: accessToken.ClientID, + AccessToken: &token, + IsCloudShell: accessToken.RefreshToken == "", + } + return &validAccessToken, nil + } + + return nil, fmt.Errorf("No Access Token was found for the Tenant ID %q", tenantId) +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/azure_cli_profile.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/azure_cli_profile.go new file mode 100644 index 000000000..a70d90c39 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/azure_cli_profile.go @@ -0,0 +1,44 @@ +package authentication + +import ( + "github.com/Azure/go-autorest/autorest/adal" + "github.com/Azure/go-autorest/autorest/azure/cli" +) + +type azureCLIProfile struct { + profile cli.Profile + + clientId string + environment string + subscriptionId string + tenantId string + accessToken *adal.Token + usingCloudShell bool +} + +func (a *azureCLIProfile) populateFields() error { + // ensure we know the Subscription ID - since it's needed for everything else + if a.subscriptionId == "" { + err := a.populateSubscriptionID() + if err != nil { + return err + } + } + + if a.tenantId == "" { + // now we know the subscription ID, find the associated Tenant ID + err := a.populateTenantID() + if err != nil { + return err + } + } + + // now we know the Subscription ID & Tenant ID we can find the associated Client ID/Access Token + err := a.populateClientIdAndAccessToken() + if err != nil { + return err + } + + // always pull the environment from the Azure CLI, since the Access Token's associated with it + return a.populateEnvironment() +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/azure_cli_profile_population.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/azure_cli_profile_population.go new file mode 100644 index 000000000..65aa7f6d1 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/azure_cli_profile_population.go @@ -0,0 +1,83 @@ +package authentication + +import ( + "fmt" + "strings" + + "github.com/Azure/go-autorest/autorest/azure/cli" +) + +func (a *azureCLIProfile) populateSubscriptionID() error { + subscriptionId, err := a.findDefaultSubscriptionId() + if err != nil { + return err + } + + a.subscriptionId = subscriptionId + return nil +} + +func (a *azureCLIProfile) populateTenantID() error { + subscription, err := a.findSubscription(a.subscriptionId) + if err != nil { + return err + } + + a.tenantId = subscription.TenantID + return nil +} + +func (a *azureCLIProfile) populateClientIdAndAccessToken() error { + // we can now pull out the ClientID and the Access Token to use from the Access Token + tokensPath, err := cli.AccessTokensPath() + if err != nil { + return fmt.Errorf("Error loading the Tokens Path from the Azure CLI: %+v", err) + } + + tokens, err := cli.LoadTokens(tokensPath) + if err != nil { + return fmt.Errorf("No Authorization Tokens were found - please ensure the Azure CLI is installed and then log-in with `az login`.") + } + + validToken, err := findValidAccessTokenForTenant(tokens, a.tenantId) + if err != nil { + return fmt.Errorf("No (unexpired) Authorization Tokens were found - please re-authenticate using `az login`.") + } + + token := *validToken + a.accessToken = token.AccessToken + a.clientId = token.ClientID + a.usingCloudShell = token.IsCloudShell + + return nil +} + +func (a *azureCLIProfile) populateEnvironment() error { + subscription, err := a.findSubscription(a.subscriptionId) + if err != nil { + return err + } + + a.environment = normalizeEnvironmentName(subscription.EnvironmentName) + return nil +} + +func (a azureCLIProfile) findDefaultSubscriptionId() (string, error) { + for _, subscription := range a.profile.Subscriptions { + if subscription.IsDefault { + return subscription.ID, nil + } + } + + return "", fmt.Errorf("No Subscription was Marked as Default in the Azure Profile.") +} + +func (a azureCLIProfile) findSubscription(subscriptionId string) (*cli.Subscription, error) { + for _, subscription := range a.profile.Subscriptions { + if strings.EqualFold(subscription.ID, subscriptionId) { + return &subscription, nil + } + } + + return nil, fmt.Errorf("Subscription %q was not found in your Azure CLI credentials. Please verify it exists in `az account list`.", subscriptionId) +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/builder.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/builder.go new file mode 100644 index 000000000..b72ac805c --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/builder.go @@ -0,0 +1,81 @@ +package authentication + +import ( + "fmt" + "log" +) + +// Builder supports all of the possible Authentication values and feature toggles +// required to build a working Config for Authentication purposes. +type Builder struct { + // Core + ClientID string + SubscriptionID string + TenantID string + Environment string + + // The custom Resource Manager Endpoint which should be used + // only applicable for Azure Stack at this time. + CustomResourceManagerEndpoint string + + // Azure CLI Parsing / CloudShell Auth + SupportsAzureCliCloudShellParsing bool + + // Managed Service Identity Auth + SupportsManagedServiceIdentity bool + MsiEndpoint string + + // Service Principal (Client Cert) Auth + SupportsClientCertAuth bool + ClientCertPath string + ClientCertPassword string + + // Service Principal (Client Secret) Auth + SupportsClientSecretAuth bool + ClientSecret string +} + +// Build takes the configuration from the Builder and builds up a validated Config +// for authenticating with Azure +func (b Builder) Build() (*Config, error) { + config := Config{ + ClientID: b.ClientID, + SubscriptionID: b.SubscriptionID, + TenantID: b.TenantID, + Environment: b.Environment, + CustomResourceManagerEndpoint: b.CustomResourceManagerEndpoint, + } + + // NOTE: the ordering here is important + // since the Azure CLI Parsing should always be the last thing checked + supportedAuthenticationMethods := []authMethod{ + servicePrincipalClientCertificateAuth{}, + servicePrincipalClientSecretAuth{}, + managedServiceIdentityAuth{}, + azureCliParsingAuth{}, + } + + for _, method := range supportedAuthenticationMethods { + name := method.name() + log.Printf("Testing if %s is applicable for Authentication..", name) + if method.isApplicable(b) { + log.Printf("Using %s for Authentication", name) + auth, err := method.build(b) + if err != nil { + return nil, err + } + + // populate authentication specific fields on the Config + // (e.g. is service principal, fields parsed from the azure cli) + err = auth.populateConfig(&config) + if err != nil { + return nil, err + } + + config.authMethod = auth + return config.validate() + } + } + + return nil, fmt.Errorf("No supported authentication methods were found!") +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/config.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/config.go new file mode 100644 index 000000000..c3068152f --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/config.go @@ -0,0 +1,36 @@ +package authentication + +import ( + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/adal" +) + +// Config is the configuration structure used to instantiate a +// new Azure management client. +type Config struct { + ClientID string + SubscriptionID string + TenantID string + Environment string + AuthenticatedAsAServicePrincipal bool + + // A Custom Resource Manager Endpoint + // at this time this should only be applicable for Azure Stack. + CustomResourceManagerEndpoint string + + authMethod authMethod +} + +// GetAuthorizationToken returns an authorization token for the authentication method defined in the Config +func (c Config) GetAuthorizationToken(oauthConfig *adal.OAuthConfig, endpoint string) (*autorest.BearerAuthorizer, error) { + return c.authMethod.getAuthorizationToken(oauthConfig, endpoint) +} + +func (c Config) validate() (*Config, error) { + err := c.authMethod.validate() + if err != nil { + return nil, err + } + + return &c, nil +} diff --git a/vendor/github.com/hashicorp/go-azure-helpers/authentication/environment.go b/vendor/github.com/hashicorp/go-azure-helpers/authentication/environment.go new file mode 100644 index 000000000..7fc4e15b4 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-helpers/authentication/environment.go @@ -0,0 +1,55 @@ +package authentication + +import ( + "fmt" + "strings" + + "github.com/Azure/go-autorest/autorest/azure" +) + +// DetermineEnvironment determines what the Environment name is within +// the Azure SDK for Go and then returns the association environment, if it exists. +func DetermineEnvironment(name string) (*azure.Environment, error) { + // detect cloud from environment + env, envErr := azure.EnvironmentFromName(name) + + if envErr != nil { + // try again with wrapped value to support readable values like german instead of AZUREGERMANCLOUD + wrapped := fmt.Sprintf("AZURE%sCLOUD", name) + env, envErr = azure.EnvironmentFromName(wrapped) + if envErr != nil { + return nil, fmt.Errorf("An Azure Environment with name %q was not found: %+v", name, envErr) + } + } + + return &env, nil +} + +// LoadEnvironmentFromUrl attempts to load the specified environment from the endpoint. +// if the endpoint is an empty string, or an environment can't be +// found at the endpoint url then an error is returned +func LoadEnvironmentFromUrl(endpoint string) (*azure.Environment, error) { + if endpoint == "" { + return nil, fmt.Errorf("Endpoint was not set!") + } + + env, err := azure.EnvironmentFromURL(endpoint) + if err != nil { + return nil, fmt.Errorf("Error retrieving Environment from Endpoint %q: %+v", endpoint, err) + } + + return &env, nil +} + +func normalizeEnvironmentName(input string) string { + // Environment is stored as `Azure{Environment}Cloud` + output := strings.ToLower(input) + output = strings.TrimPrefix(output, "azure") + output = strings.TrimSuffix(output, "cloud") + + // however Azure Public is `AzureCloud` in the CLI Profile and not `AzurePublicCloud`. + if output == "" { + return "public" + } + return output +} diff --git a/vendor/github.com/marstr/guid/.travis.yml b/vendor/github.com/marstr/guid/.travis.yml new file mode 100644 index 000000000..35158ec53 --- /dev/null +++ b/vendor/github.com/marstr/guid/.travis.yml @@ -0,0 +1,18 @@ +sudo: false + +language: go + +go: + - 1.7 + - 1.8 + +install: + - go get -u github.com/golang/lint/golint + - go get -u github.com/HewlettPackard/gas + +script: + - golint --set_exit_status + - go vet + - go test -v -cover -race + - go test -bench . + - gas ./... \ No newline at end of file diff --git a/vendor/github.com/marstr/guid/LICENSE.txt b/vendor/github.com/marstr/guid/LICENSE.txt new file mode 100644 index 000000000..e18a0841a --- /dev/null +++ b/vendor/github.com/marstr/guid/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Martin Strobel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/marstr/guid/README.md b/vendor/github.com/marstr/guid/README.md new file mode 100644 index 000000000..355fad16d --- /dev/null +++ b/vendor/github.com/marstr/guid/README.md @@ -0,0 +1,27 @@ +[![Build Status](https://travis-ci.org/marstr/guid.svg?branch=master)](https://travis-ci.org/marstr/guid) +[![GoDoc](https://godoc.org/github.com/marstr/guid?status.svg)](https://godoc.org/github.com/marstr/guid) +[![Go Report Card](https://goreportcard.com/badge/github.com/marstr/guid)](https://goreportcard.com/report/github.com/marstr/guid) + +# Guid +Globally unique identifiers offer a quick means of generating non-colliding values across a distributed system. For this implemenation, [RFC 4122](http://ietf.org/rfc/rfc4122.txt) governs the desired behavior. + +## What's in a name? +You have likely already noticed that RFC and some implementations refer to these structures as UUIDs (Universally Unique Identifiers), where as this project is annotated as GUIDs (Globally Unique Identifiers). The name Guid was selected to make clear this project's ties to the [.NET struct Guid.](https://msdn.microsoft.com/en-us/library/system.guid(v=vs.110).aspx) The most obvious relationship is the desire to have the same format specifiers available in this library's Format and Parse methods as .NET would have in its ToString and Parse methods. + +# Installation +- Ensure you have the [Go Programming Language](https://golang.org/) installed on your system. +- Run the command: `go get -u github.com/marstr/guid` + +# Contribution +Contributions are welcome! Feel free to send Pull Requests. Continuous Integration will ensure that you have conformed to Go conventions. Please remember to add tests for your changes. + +# Versioning +This library will adhere to the +[Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html) specification. It may be worth noting this should allow for tools like [glide](https://glide.readthedocs.io/en/latest/) to pull in this library with ease. + +The Release Notes portion of this file will be updated to reflect the most recent major/minor updates, with the option to tag particular bug-fixes as well. Updates to the Release Notes for patches should be addative, where as major/minor updates should replace the previous version. If one desires to see the release notes for an older version, checkout that version of code and open this file. + +# Release Notes 1.1.* + +## v1.1.0 +Adding support for JSON marshaling and unmarshaling. diff --git a/vendor/github.com/marstr/guid/guid.go b/vendor/github.com/marstr/guid/guid.go new file mode 100644 index 000000000..51b038b75 --- /dev/null +++ b/vendor/github.com/marstr/guid/guid.go @@ -0,0 +1,301 @@ +package guid + +import ( + "bytes" + "crypto/rand" + "errors" + "fmt" + "net" + "strings" + "sync" + "time" +) + +// GUID is a unique identifier designed to virtually guarantee non-conflict between values generated +// across a distributed system. +type GUID struct { + timeHighAndVersion uint16 + timeMid uint16 + timeLow uint32 + clockSeqHighAndReserved uint8 + clockSeqLow uint8 + node [6]byte +} + +// Format enumerates the values that are supported by Parse and Format +type Format string + +// These constants define the possible string formats available via this implementation of Guid. +const ( + FormatB Format = "B" // {00000000-0000-0000-0000-000000000000} + FormatD Format = "D" // 00000000-0000-0000-0000-000000000000 + FormatN Format = "N" // 00000000000000000000000000000000 + FormatP Format = "P" // (00000000-0000-0000-0000-000000000000) + FormatX Format = "X" // {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} + FormatDefault Format = FormatD +) + +// CreationStrategy enumerates the values that are supported for populating the bits of a new Guid. +type CreationStrategy string + +// These constants define the possible creation strategies available via this implementation of Guid. +const ( + CreationStrategyVersion1 CreationStrategy = "version1" + CreationStrategyVersion2 CreationStrategy = "version2" + CreationStrategyVersion3 CreationStrategy = "version3" + CreationStrategyVersion4 CreationStrategy = "version4" + CreationStrategyVersion5 CreationStrategy = "version5" +) + +var emptyGUID GUID + +// NewGUID generates and returns a new globally unique identifier +func NewGUID() GUID { + result, err := version4() + if err != nil { + panic(err) //Version 4 (pseudo-random GUID) doesn't use anything that could fail. + } + return result +} + +var knownStrategies = map[CreationStrategy]func() (GUID, error){ + CreationStrategyVersion1: version1, + CreationStrategyVersion4: version4, +} + +// NewGUIDs generates and returns a new globally unique identifier that conforms to the given strategy. +func NewGUIDs(strategy CreationStrategy) (GUID, error) { + if creator, present := knownStrategies[strategy]; present { + result, err := creator() + return result, err + } + return emptyGUID, errors.New("Unsupported CreationStrategy") +} + +// Empty returns a copy of the default and empty GUID. +func Empty() GUID { + return emptyGUID +} + +var knownFormats = map[Format]string{ + FormatN: "%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x", + FormatD: "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + FormatB: "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + FormatP: "(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)", + FormatX: "{0x%08x,0x%04x,0x%04x,{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}}", +} + +// MarshalJSON writes a GUID as a JSON string. +func (guid GUID) MarshalJSON() (marshaled []byte, err error) { + buf := bytes.Buffer{} + + _, err = buf.WriteRune('"') + buf.WriteString(guid.String()) + buf.WriteRune('"') + + marshaled = buf.Bytes() + return +} + +// Parse instantiates a GUID from a text representation of the same GUID. +// This is the inverse of function family String() +func Parse(value string) (GUID, error) { + var guid GUID + for _, fullFormat := range knownFormats { + parity, err := fmt.Sscanf( + value, + fullFormat, + &guid.timeLow, + &guid.timeMid, + &guid.timeHighAndVersion, + &guid.clockSeqHighAndReserved, + &guid.clockSeqLow, + &guid.node[0], + &guid.node[1], + &guid.node[2], + &guid.node[3], + &guid.node[4], + &guid.node[5]) + if parity == 11 && err == nil { + return guid, err + } + } + return emptyGUID, fmt.Errorf("\"%s\" is not in a recognized format", value) +} + +// String returns a text representation of a GUID in the default format. +func (guid GUID) String() string { + return guid.Stringf(FormatDefault) +} + +// Stringf returns a text representation of a GUID that conforms to the specified format. +// If an unrecognized format is provided, the empty string is returned. +func (guid GUID) Stringf(format Format) string { + if format == "" { + format = FormatDefault + } + fullFormat, present := knownFormats[format] + if !present { + return "" + } + return fmt.Sprintf( + fullFormat, + guid.timeLow, + guid.timeMid, + guid.timeHighAndVersion, + guid.clockSeqHighAndReserved, + guid.clockSeqLow, + guid.node[0], + guid.node[1], + guid.node[2], + guid.node[3], + guid.node[4], + guid.node[5]) +} + +// UnmarshalJSON parses a GUID from a JSON string token. +func (guid *GUID) UnmarshalJSON(marshaled []byte) (err error) { + if len(marshaled) < 2 { + err = errors.New("JSON GUID must be surrounded by quotes") + return + } + stripped := marshaled[1 : len(marshaled)-1] + *guid, err = Parse(string(stripped)) + return +} + +// Version reads a GUID to parse which mechanism of generating GUIDS was employed. +// Values returned here are documented in rfc4122.txt. +func (guid GUID) Version() uint { + return uint(guid.timeHighAndVersion >> 12) +} + +var unixToGregorianOffset = time.Date(1970, 01, 01, 0, 0, 00, 0, time.UTC).Sub(time.Date(1582, 10, 15, 0, 0, 0, 0, time.UTC)) + +// getRFC4122Time returns a 60-bit count of 100-nanosecond intervals since 00:00:00.00 October 15th, 1582 +func getRFC4122Time() int64 { + currentTime := time.Now().UTC().Add(unixToGregorianOffset).UnixNano() + currentTime /= 100 + return currentTime & 0x0FFFFFFFFFFFFFFF +} + +var clockSeqVal uint16 +var clockSeqKey sync.Mutex + +func getClockSequence() (uint16, error) { + clockSeqKey.Lock() + defer clockSeqKey.Unlock() + + if 0 == clockSeqVal { + var temp [2]byte + if parity, err := rand.Read(temp[:]); !(2 == parity && nil == err) { + return 0, err + } + clockSeqVal = uint16(temp[0])<<8 | uint16(temp[1]) + } + clockSeqVal++ + return clockSeqVal, nil +} + +func getMACAddress() (mac [6]byte, err error) { + var hostNICs []net.Interface + + hostNICs, err = net.Interfaces() + if err != nil { + return + } + + for _, nic := range hostNICs { + var parity int + + parity, err = fmt.Sscanf( + strings.ToLower(nic.HardwareAddr.String()), + "%02x:%02x:%02x:%02x:%02x:%02x", + &mac[0], + &mac[1], + &mac[2], + &mac[3], + &mac[4], + &mac[5]) + + if parity == len(mac) { + return + } + } + + err = fmt.Errorf("No suitable address found") + + return +} + +func version1() (result GUID, err error) { + var localMAC [6]byte + var clockSeq uint16 + + currentTime := getRFC4122Time() + + result.timeLow = uint32(currentTime) + result.timeMid = uint16(currentTime >> 32) + result.timeHighAndVersion = uint16(currentTime >> 48) + if err = result.setVersion(1); err != nil { + return emptyGUID, err + } + + if localMAC, err = getMACAddress(); nil != err { + if parity, err := rand.Read(localMAC[:]); !(len(localMAC) != parity && err == nil) { + return emptyGUID, err + } + localMAC[0] |= 0x1 + } + copy(result.node[:], localMAC[:]) + + if clockSeq, err = getClockSequence(); nil != err { + return emptyGUID, err + } + + result.clockSeqLow = uint8(clockSeq) + result.clockSeqHighAndReserved = uint8(clockSeq >> 8) + + result.setReservedBits() + + return +} + +func version4() (GUID, error) { + var retval GUID + var bits [10]byte + + if parity, err := rand.Read(bits[:]); !(len(bits) == parity && err == nil) { + return emptyGUID, err + } + retval.timeHighAndVersion |= uint16(bits[0]) | uint16(bits[1])<<8 + retval.timeMid |= uint16(bits[2]) | uint16(bits[3])<<8 + retval.timeLow |= uint32(bits[4]) | uint32(bits[5])<<8 | uint32(bits[6])<<16 | uint32(bits[7])<<24 + retval.clockSeqHighAndReserved = uint8(bits[8]) + retval.clockSeqLow = uint8(bits[9]) + + //Randomly set clock-sequence, reserved, and node + if written, err := rand.Read(retval.node[:]); !(nil == err && written == len(retval.node)) { + retval = emptyGUID + return retval, err + } + + if err := retval.setVersion(4); nil != err { + return emptyGUID, err + } + retval.setReservedBits() + + return retval, nil +} + +func (guid *GUID) setVersion(version uint16) error { + if version > 5 || version == 0 { + return fmt.Errorf("While setting GUID version, unsupported version: %d", version) + } + guid.timeHighAndVersion = (guid.timeHighAndVersion & 0x0fff) | version<<12 + return nil +} + +func (guid *GUID) setReservedBits() { + guid.clockSeqHighAndReserved = (guid.clockSeqHighAndReserved & 0x3f) | 0x80 +} diff --git a/vendor/github.com/satori/uuid/.travis.yml b/vendor/github.com/satori/uuid/.travis.yml deleted file mode 100644 index bf90ad530..000000000 --- a/vendor/github.com/satori/uuid/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: go -sudo: false -go: - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - 1.6 - - 1.7 - - tip -matrix: - allow_failures: - - go: tip - fast_finish: true -before_install: - - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover -script: - - $HOME/gopath/bin/goveralls -service=travis-ci -notifications: - email: false diff --git a/vendor/github.com/satori/uuid/LICENSE b/vendor/github.com/satori/uuid/LICENSE deleted file mode 100644 index 488357b8a..000000000 --- a/vendor/github.com/satori/uuid/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (C) 2013-2016 by Maxim Bublis - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/satori/uuid/README.md b/vendor/github.com/satori/uuid/README.md deleted file mode 100644 index b6aad1c81..000000000 --- a/vendor/github.com/satori/uuid/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# UUID package for Go language - -[![Build Status](https://travis-ci.org/satori/go.uuid.png?branch=master)](https://travis-ci.org/satori/go.uuid) -[![Coverage Status](https://coveralls.io/repos/github/satori/go.uuid/badge.svg?branch=master)](https://coveralls.io/github/satori/go.uuid) -[![GoDoc](http://godoc.org/github.com/satori/go.uuid?status.png)](http://godoc.org/github.com/satori/go.uuid) - -This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs. - -With 100% test coverage and benchmarks out of box. - -Supported versions: -* Version 1, based on timestamp and MAC address (RFC 4122) -* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1) -* Version 3, based on MD5 hashing (RFC 4122) -* Version 4, based on random numbers (RFC 4122) -* Version 5, based on SHA-1 hashing (RFC 4122) - -## Installation - -Use the `go` command: - - $ go get github.com/satori/go.uuid - -## Requirements - -UUID package requires Go >= 1.2. - -## Example - -```go -package main - -import ( - "fmt" - "github.com/satori/go.uuid" -) - -func main() { - // Creating UUID Version 4 - u1 := uuid.NewV4() - fmt.Printf("UUIDv4: %s\n", u1) - - // Parsing UUID from string input - u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") - if err != nil { - fmt.Printf("Something gone wrong: %s", err) - } - fmt.Printf("Successfully parsed: %s", u2) -} -``` - -## Documentation - -[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project. - -## Links -* [RFC 4122](http://tools.ietf.org/html/rfc4122) -* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01) - -## Copyright - -Copyright (C) 2013-2016 by Maxim Bublis . - -UUID package released under MIT License. -See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details. diff --git a/vendor/github.com/satori/uuid/uuid.go b/vendor/github.com/satori/uuid/uuid.go deleted file mode 100644 index 295f3fc2c..000000000 --- a/vendor/github.com/satori/uuid/uuid.go +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright (C) 2013-2015 by Maxim Bublis -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -// Package uuid provides implementation of Universally Unique Identifier (UUID). -// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and -// version 2 (as specified in DCE 1.1). -package uuid - -import ( - "bytes" - "crypto/md5" - "crypto/rand" - "crypto/sha1" - "database/sql/driver" - "encoding/binary" - "encoding/hex" - "fmt" - "hash" - "net" - "os" - "sync" - "time" -) - -// UUID layout variants. -const ( - VariantNCS = iota - VariantRFC4122 - VariantMicrosoft - VariantFuture -) - -// UUID DCE domains. -const ( - DomainPerson = iota - DomainGroup - DomainOrg -) - -// Difference in 100-nanosecond intervals between -// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970). -const epochStart = 122192928000000000 - -// Used in string method conversion -const dash byte = '-' - -// UUID v1/v2 storage. -var ( - storageMutex sync.Mutex - storageOnce sync.Once - epochFunc = unixTimeFunc - clockSequence uint16 - lastTime uint64 - hardwareAddr [6]byte - posixUID = uint32(os.Getuid()) - posixGID = uint32(os.Getgid()) -) - -// String parse helpers. -var ( - urnPrefix = []byte("urn:uuid:") - byteGroups = []int{8, 4, 4, 4, 12} -) - -func initClockSequence() { - buf := make([]byte, 2) - safeRandom(buf) - clockSequence = binary.BigEndian.Uint16(buf) -} - -func initHardwareAddr() { - interfaces, err := net.Interfaces() - if err == nil { - for _, iface := range interfaces { - if len(iface.HardwareAddr) >= 6 { - copy(hardwareAddr[:], iface.HardwareAddr) - return - } - } - } - - // Initialize hardwareAddr randomly in case - // of real network interfaces absence - safeRandom(hardwareAddr[:]) - - // Set multicast bit as recommended in RFC 4122 - hardwareAddr[0] |= 0x01 -} - -func initStorage() { - initClockSequence() - initHardwareAddr() -} - -func safeRandom(dest []byte) { - if _, err := rand.Read(dest); err != nil { - panic(err) - } -} - -// Returns difference in 100-nanosecond intervals between -// UUID epoch (October 15, 1582) and current time. -// This is default epoch calculation function. -func unixTimeFunc() uint64 { - return epochStart + uint64(time.Now().UnixNano()/100) -} - -// UUID representation compliant with specification -// described in RFC 4122. -type UUID [16]byte - -// NullUUID can be used with the standard sql package to represent a -// UUID value that can be NULL in the database -type NullUUID struct { - UUID UUID - Valid bool -} - -// The nil UUID is special form of UUID that is specified to have all -// 128 bits set to zero. -var Nil = UUID{} - -// Predefined namespace UUIDs. -var ( - NamespaceDNS, _ = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") - NamespaceURL, _ = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8") - NamespaceOID, _ = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8") - NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8") -) - -// And returns result of binary AND of two UUIDs. -func And(u1 UUID, u2 UUID) UUID { - u := UUID{} - for i := 0; i < 16; i++ { - u[i] = u1[i] & u2[i] - } - return u -} - -// Or returns result of binary OR of two UUIDs. -func Or(u1 UUID, u2 UUID) UUID { - u := UUID{} - for i := 0; i < 16; i++ { - u[i] = u1[i] | u2[i] - } - return u -} - -// Equal returns true if u1 and u2 equals, otherwise returns false. -func Equal(u1 UUID, u2 UUID) bool { - return bytes.Equal(u1[:], u2[:]) -} - -// Version returns algorithm version used to generate UUID. -func (u UUID) Version() uint { - return uint(u[6] >> 4) -} - -// Variant returns UUID layout variant. -func (u UUID) Variant() uint { - switch { - case (u[8] & 0x80) == 0x00: - return VariantNCS - case (u[8]&0xc0)|0x80 == 0x80: - return VariantRFC4122 - case (u[8]&0xe0)|0xc0 == 0xc0: - return VariantMicrosoft - } - return VariantFuture -} - -// Bytes returns bytes slice representation of UUID. -func (u UUID) Bytes() []byte { - return u[:] -} - -// Returns canonical string representation of UUID: -// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. -func (u UUID) String() string { - buf := make([]byte, 36) - - hex.Encode(buf[0:8], u[0:4]) - buf[8] = dash - hex.Encode(buf[9:13], u[4:6]) - buf[13] = dash - hex.Encode(buf[14:18], u[6:8]) - buf[18] = dash - hex.Encode(buf[19:23], u[8:10]) - buf[23] = dash - hex.Encode(buf[24:], u[10:]) - - return string(buf) -} - -// SetVersion sets version bits. -func (u *UUID) SetVersion(v byte) { - u[6] = (u[6] & 0x0f) | (v << 4) -} - -// SetVariant sets variant bits as described in RFC 4122. -func (u *UUID) SetVariant() { - u[8] = (u[8] & 0xbf) | 0x80 -} - -// MarshalText implements the encoding.TextMarshaler interface. -// The encoding is the same as returned by String. -func (u UUID) MarshalText() (text []byte, err error) { - text = []byte(u.String()) - return -} - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -// Following formats are supported: -// "6ba7b810-9dad-11d1-80b4-00c04fd430c8", -// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", -// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" -func (u *UUID) UnmarshalText(text []byte) (err error) { - if len(text) < 32 { - err = fmt.Errorf("uuid: UUID string too short: %s", text) - return - } - - t := text[:] - braced := false - - if bytes.Equal(t[:9], urnPrefix) { - t = t[9:] - } else if t[0] == '{' { - braced = true - t = t[1:] - } - - b := u[:] - - for i, byteGroup := range byteGroups { - if i > 0 { - if t[0] != '-' { - err = fmt.Errorf("uuid: invalid string format") - return - } - t = t[1:] - } - - if len(t) < byteGroup { - err = fmt.Errorf("uuid: UUID string too short: %s", text) - return - } - - if i == 4 && len(t) > byteGroup && - ((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) { - err = fmt.Errorf("uuid: UUID string too long: %s", text) - return - } - - _, err = hex.Decode(b[:byteGroup/2], t[:byteGroup]) - if err != nil { - return - } - - t = t[byteGroup:] - b = b[byteGroup/2:] - } - - return -} - -// MarshalBinary implements the encoding.BinaryMarshaler interface. -func (u UUID) MarshalBinary() (data []byte, err error) { - data = u.Bytes() - return -} - -// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. -// It will return error if the slice isn't 16 bytes long. -func (u *UUID) UnmarshalBinary(data []byte) (err error) { - if len(data) != 16 { - err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data)) - return - } - copy(u[:], data) - - return -} - -// Value implements the driver.Valuer interface. -func (u UUID) Value() (driver.Value, error) { - return u.String(), nil -} - -// Scan implements the sql.Scanner interface. -// A 16-byte slice is handled by UnmarshalBinary, while -// a longer byte slice or a string is handled by UnmarshalText. -func (u *UUID) Scan(src interface{}) error { - switch src := src.(type) { - case []byte: - if len(src) == 16 { - return u.UnmarshalBinary(src) - } - return u.UnmarshalText(src) - - case string: - return u.UnmarshalText([]byte(src)) - } - - return fmt.Errorf("uuid: cannot convert %T to UUID", src) -} - -// Value implements the driver.Valuer interface. -func (u NullUUID) Value() (driver.Value, error) { - if !u.Valid { - return nil, nil - } - // Delegate to UUID Value function - return u.UUID.Value() -} - -// Scan implements the sql.Scanner interface. -func (u *NullUUID) Scan(src interface{}) error { - if src == nil { - u.UUID, u.Valid = Nil, false - return nil - } - - // Delegate to UUID Scan function - u.Valid = true - return u.UUID.Scan(src) -} - -// FromBytes returns UUID converted from raw byte slice input. -// It will return error if the slice isn't 16 bytes long. -func FromBytes(input []byte) (u UUID, err error) { - err = u.UnmarshalBinary(input) - return -} - -// FromBytesOrNil returns UUID converted from raw byte slice input. -// Same behavior as FromBytes, but returns a Nil UUID on error. -func FromBytesOrNil(input []byte) UUID { - uuid, err := FromBytes(input) - if err != nil { - return Nil - } - return uuid -} - -// FromString returns UUID parsed from string input. -// Input is expected in a form accepted by UnmarshalText. -func FromString(input string) (u UUID, err error) { - err = u.UnmarshalText([]byte(input)) - return -} - -// FromStringOrNil returns UUID parsed from string input. -// Same behavior as FromString, but returns a Nil UUID on error. -func FromStringOrNil(input string) UUID { - uuid, err := FromString(input) - if err != nil { - return Nil - } - return uuid -} - -// Returns UUID v1/v2 storage state. -// Returns epoch timestamp, clock sequence, and hardware address. -func getStorage() (uint64, uint16, []byte) { - storageOnce.Do(initStorage) - - storageMutex.Lock() - defer storageMutex.Unlock() - - timeNow := epochFunc() - // Clock changed backwards since last UUID generation. - // Should increase clock sequence. - if timeNow <= lastTime { - clockSequence++ - } - lastTime = timeNow - - return timeNow, clockSequence, hardwareAddr[:] -} - -// NewV1 returns UUID based on current timestamp and MAC address. -func NewV1() UUID { - u := UUID{} - - timeNow, clockSeq, hardwareAddr := getStorage() - - binary.BigEndian.PutUint32(u[0:], uint32(timeNow)) - binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) - binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) - binary.BigEndian.PutUint16(u[8:], clockSeq) - - copy(u[10:], hardwareAddr) - - u.SetVersion(1) - u.SetVariant() - - return u -} - -// NewV2 returns DCE Security UUID based on POSIX UID/GID. -func NewV2(domain byte) UUID { - u := UUID{} - - timeNow, clockSeq, hardwareAddr := getStorage() - - switch domain { - case DomainPerson: - binary.BigEndian.PutUint32(u[0:], posixUID) - case DomainGroup: - binary.BigEndian.PutUint32(u[0:], posixGID) - } - - binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32)) - binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48)) - binary.BigEndian.PutUint16(u[8:], clockSeq) - u[9] = domain - - copy(u[10:], hardwareAddr) - - u.SetVersion(2) - u.SetVariant() - - return u -} - -// NewV3 returns UUID based on MD5 hash of namespace UUID and name. -func NewV3(ns UUID, name string) UUID { - u := newFromHash(md5.New(), ns, name) - u.SetVersion(3) - u.SetVariant() - - return u -} - -// NewV4 returns random generated UUID. -func NewV4() UUID { - u := UUID{} - safeRandom(u[:]) - u.SetVersion(4) - u.SetVariant() - - return u -} - -// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name. -func NewV5(ns UUID, name string) UUID { - u := newFromHash(sha1.New(), ns, name) - u.SetVersion(5) - u.SetVariant() - - return u -} - -// Returns UUID based on hashing of namespace UUID and name. -func newFromHash(h hash.Hash, ns UUID, name string) UUID { - u := UUID{} - h.Write(ns[:]) - h.Write([]byte(name)) - copy(u[:], h.Sum(nil)) - - return u -} diff --git a/vendor/golang.org/x/crypto/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go index efe6e7302..3e2518600 100644 --- a/vendor/golang.org/x/crypto/openpgp/keys.go +++ b/vendor/golang.org/x/crypto/openpgp/keys.go @@ -345,36 +345,8 @@ EachPacket: switch pkt := p.(type) { case *packet.UserId: - // Make a new Identity object, that we might wind up throwing away. - // We'll only add it if we get a valid self-signature over this - // userID. - current := new(Identity) - current.Name = pkt.Id - current.UserId = pkt - - for { - p, err = packets.Next() - if err == io.EOF { - break EachPacket - } else if err != nil { - return nil, err - } - - sig, ok := p.(*packet.Signature) - if !ok { - packets.Unread(p) - continue EachPacket - } - - if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { - if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { - return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error()) - } - current.SelfSignature = sig - e.Identities[pkt.Id] = current - } else { - current.Signatures = append(current.Signatures, sig) - } + if err := addUserID(e, packets, pkt); err != nil { + return nil, err } case *packet.Signature: if pkt.SigType == packet.SigTypeKeyRevocation { @@ -426,6 +398,42 @@ EachPacket: return e, nil } +func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error { + // Make a new Identity object, that we might wind up throwing away. + // We'll only add it if we get a valid self-signature over this + // userID. + identity := new(Identity) + identity.Name = pkt.Id + identity.UserId = pkt + + for { + p, err := packets.Next() + if err == io.EOF { + break + } else if err != nil { + return err + } + + sig, ok := p.(*packet.Signature) + if !ok { + packets.Unread(p) + break + } + + if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { + if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { + return errors.StructuralError("user ID self-signature invalid: " + err.Error()) + } + identity.SelfSignature = sig + e.Identities[pkt.Id] = identity + } else { + identity.Signatures = append(identity.Signatures, sig) + } + } + + return nil +} + func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { var subKey Subkey subKey.PublicKey = pub @@ -457,7 +465,8 @@ func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *p case packet.SigTypeSubkeyRevocation: subKey.Sig = sig case packet.SigTypeSubkeyBinding: - if subKey.Sig == nil { + + if shouldReplaceSubkeySig(subKey.Sig, sig) { subKey.Sig = sig } } @@ -472,6 +481,22 @@ func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *p return nil } +func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool { + if potentialNewSig == nil { + return false + } + + if existingSig == nil { + return true + } + + if existingSig.SigType == packet.SigTypeSubkeyRevocation { + return false // never override a revocation signature + } + + return potentialNewSig.CreationTime.After(existingSig.CreationTime) +} + const defaultRSAKeyBits = 2048 // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go index 625bb5ac8..5af64c542 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/packet.go @@ -404,14 +404,16 @@ const ( type PublicKeyAlgorithm uint8 const ( - PubKeyAlgoRSA PublicKeyAlgorithm = 1 - PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 - PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 - PubKeyAlgoElGamal PublicKeyAlgorithm = 16 - PubKeyAlgoDSA PublicKeyAlgorithm = 17 + PubKeyAlgoRSA PublicKeyAlgorithm = 1 + PubKeyAlgoElGamal PublicKeyAlgorithm = 16 + PubKeyAlgoDSA PublicKeyAlgorithm = 17 // RFC 6637, Section 5. PubKeyAlgoECDH PublicKeyAlgorithm = 18 PubKeyAlgoECDSA PublicKeyAlgorithm = 19 + + // Deprecated in RFC 4880, Section 13.5. Use key flags instead. + PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 + PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 ) // CanEncrypt returns true if it's possible to encrypt a message to a public diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go index 34734cc63..bd31cceac 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go @@ -64,14 +64,19 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK return pk } -// NewSignerPrivateKey creates a sign-only PrivateKey from a crypto.Signer that +// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that // implements RSA or ECDSA. func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey { pk := new(PrivateKey) + // In general, the public Keys should be used as pointers. We still + // type-switch on the values, for backwards-compatibility. switch pubkey := signer.Public().(type) { + case *rsa.PublicKey: + pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey) case rsa.PublicKey: pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) - pk.PubKeyAlgo = PubKeyAlgoRSASignOnly + case *ecdsa.PublicKey: + pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey) case ecdsa.PublicKey: pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) default: diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature.go b/vendor/golang.org/x/crypto/openpgp/packet/signature.go index 6ce0cbedb..b2a24a532 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/signature.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/signature.go @@ -542,7 +542,7 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e r, s, err = ecdsa.Sign(config.Random(), pk, digest) } else { var b []byte - b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, nil) + b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) if err == nil { r, s, err = unwrapECDSASig(b) } diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go index 96a2b382a..d19ffbc78 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go @@ -80,7 +80,7 @@ func (uat *UserAttribute) Serialize(w io.Writer) (err error) { // ImageData returns zero or more byte slices, each containing // JPEG File Interchange Format (JFIF), for each photo in the -// the user attribute packet. +// user attribute packet. func (uat *UserAttribute) ImageData() (imageData [][]byte) { for _, sp := range uat.Contents { if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { diff --git a/vendor/golang.org/x/crypto/pkcs12/bmp-string.go b/vendor/golang.org/x/crypto/pkcs12/bmp-string.go new file mode 100644 index 000000000..233b8b62c --- /dev/null +++ b/vendor/golang.org/x/crypto/pkcs12/bmp-string.go @@ -0,0 +1,50 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pkcs12 + +import ( + "errors" + "unicode/utf16" +) + +// bmpString returns s encoded in UCS-2 with a zero terminator. +func bmpString(s string) ([]byte, error) { + // References: + // https://tools.ietf.org/html/rfc7292#appendix-B.1 + // https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane + // - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes + // EncodeRune returns 0xfffd if the rune does not need special encoding + // - the above RFC provides the info that BMPStrings are NULL terminated. + + ret := make([]byte, 0, 2*len(s)+2) + + for _, r := range s { + if t, _ := utf16.EncodeRune(r); t != 0xfffd { + return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2") + } + ret = append(ret, byte(r/256), byte(r%256)) + } + + return append(ret, 0, 0), nil +} + +func decodeBMPString(bmpString []byte) (string, error) { + if len(bmpString)%2 != 0 { + return "", errors.New("pkcs12: odd-length BMP string") + } + + // strip terminator if present + if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 { + bmpString = bmpString[:l-2] + } + + s := make([]uint16, 0, len(bmpString)/2) + for len(bmpString) > 0 { + s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1])) + bmpString = bmpString[2:] + } + + return string(utf16.Decode(s)), nil +} diff --git a/vendor/golang.org/x/crypto/pkcs12/crypto.go b/vendor/golang.org/x/crypto/pkcs12/crypto.go new file mode 100644 index 000000000..484ca51b7 --- /dev/null +++ b/vendor/golang.org/x/crypto/pkcs12/crypto.go @@ -0,0 +1,131 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pkcs12 + +import ( + "bytes" + "crypto/cipher" + "crypto/des" + "crypto/x509/pkix" + "encoding/asn1" + "errors" + + "golang.org/x/crypto/pkcs12/internal/rc2" +) + +var ( + oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}) + oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6}) +) + +// pbeCipher is an abstraction of a PKCS#12 cipher. +type pbeCipher interface { + // create returns a cipher.Block given a key. + create(key []byte) (cipher.Block, error) + // deriveKey returns a key derived from the given password and salt. + deriveKey(salt, password []byte, iterations int) []byte + // deriveKey returns an IV derived from the given password and salt. + deriveIV(salt, password []byte, iterations int) []byte +} + +type shaWithTripleDESCBC struct{} + +func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) { + return des.NewTripleDESCipher(key) +} + +func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte { + return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24) +} + +func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte { + return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) +} + +type shaWith40BitRC2CBC struct{} + +func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) { + return rc2.New(key, len(key)*8) +} + +func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte { + return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5) +} + +func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte { + return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) +} + +type pbeParams struct { + Salt []byte + Iterations int +} + +func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) { + var cipherType pbeCipher + + switch { + case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC): + cipherType = shaWithTripleDESCBC{} + case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC): + cipherType = shaWith40BitRC2CBC{} + default: + return nil, 0, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported") + } + + var params pbeParams + if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil { + return nil, 0, err + } + + key := cipherType.deriveKey(params.Salt, password, params.Iterations) + iv := cipherType.deriveIV(params.Salt, password, params.Iterations) + + block, err := cipherType.create(key) + if err != nil { + return nil, 0, err + } + + return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil +} + +func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) { + cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password) + if err != nil { + return nil, err + } + + encrypted := info.Data() + if len(encrypted) == 0 { + return nil, errors.New("pkcs12: empty encrypted data") + } + if len(encrypted)%blockSize != 0 { + return nil, errors.New("pkcs12: input is not a multiple of the block size") + } + decrypted = make([]byte, len(encrypted)) + cbc.CryptBlocks(decrypted, encrypted) + + psLen := int(decrypted[len(decrypted)-1]) + if psLen == 0 || psLen > blockSize { + return nil, ErrDecryption + } + + if len(decrypted) < psLen { + return nil, ErrDecryption + } + ps := decrypted[len(decrypted)-psLen:] + decrypted = decrypted[:len(decrypted)-psLen] + if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 { + return nil, ErrDecryption + } + + return +} + +// decryptable abstracts an object that contains ciphertext. +type decryptable interface { + Algorithm() pkix.AlgorithmIdentifier + Data() []byte +} diff --git a/vendor/golang.org/x/crypto/pkcs12/errors.go b/vendor/golang.org/x/crypto/pkcs12/errors.go new file mode 100644 index 000000000..7377ce6fb --- /dev/null +++ b/vendor/golang.org/x/crypto/pkcs12/errors.go @@ -0,0 +1,23 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pkcs12 + +import "errors" + +var ( + // ErrDecryption represents a failure to decrypt the input. + ErrDecryption = errors.New("pkcs12: decryption error, incorrect padding") + + // ErrIncorrectPassword is returned when an incorrect password is detected. + // Usually, P12/PFX data is signed to be able to verify the password. + ErrIncorrectPassword = errors.New("pkcs12: decryption password incorrect") +) + +// NotImplementedError indicates that the input is not currently supported. +type NotImplementedError string + +func (e NotImplementedError) Error() string { + return "pkcs12: " + string(e) +} diff --git a/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go new file mode 100644 index 000000000..7499e3fb6 --- /dev/null +++ b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go @@ -0,0 +1,271 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package rc2 implements the RC2 cipher +/* +https://www.ietf.org/rfc/rfc2268.txt +http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf + +This code is licensed under the MIT license. +*/ +package rc2 + +import ( + "crypto/cipher" + "encoding/binary" +) + +// The rc2 block size in bytes +const BlockSize = 8 + +type rc2Cipher struct { + k [64]uint16 +} + +// New returns a new rc2 cipher with the given key and effective key length t1 +func New(key []byte, t1 int) (cipher.Block, error) { + // TODO(dgryski): error checking for key length + return &rc2Cipher{ + k: expandKey(key, t1), + }, nil +} + +func (*rc2Cipher) BlockSize() int { return BlockSize } + +var piTable = [256]byte{ + 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, + 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, + 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, + 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, + 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, + 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, + 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, + 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, + 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, + 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, + 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, + 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, + 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, + 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, + 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, + 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad, +} + +func expandKey(key []byte, t1 int) [64]uint16 { + + l := make([]byte, 128) + copy(l, key) + + var t = len(key) + var t8 = (t1 + 7) / 8 + var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8)))) + + for i := len(key); i < 128; i++ { + l[i] = piTable[l[i-1]+l[uint8(i-t)]] + } + + l[128-t8] = piTable[l[128-t8]&tm] + + for i := 127 - t8; i >= 0; i-- { + l[i] = piTable[l[i+1]^l[i+t8]] + } + + var k [64]uint16 + + for i := range k { + k[i] = uint16(l[2*i]) + uint16(l[2*i+1])*256 + } + + return k +} + +func rotl16(x uint16, b uint) uint16 { + return (x >> (16 - b)) | (x << b) +} + +func (c *rc2Cipher) Encrypt(dst, src []byte) { + + r0 := binary.LittleEndian.Uint16(src[0:]) + r1 := binary.LittleEndian.Uint16(src[2:]) + r2 := binary.LittleEndian.Uint16(src[4:]) + r3 := binary.LittleEndian.Uint16(src[6:]) + + var j int + + for j <= 16 { + // mix r0 + r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) + r0 = rotl16(r0, 1) + j++ + + // mix r1 + r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) + r1 = rotl16(r1, 2) + j++ + + // mix r2 + r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) + r2 = rotl16(r2, 3) + j++ + + // mix r3 + r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) + r3 = rotl16(r3, 5) + j++ + + } + + r0 = r0 + c.k[r3&63] + r1 = r1 + c.k[r0&63] + r2 = r2 + c.k[r1&63] + r3 = r3 + c.k[r2&63] + + for j <= 40 { + // mix r0 + r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) + r0 = rotl16(r0, 1) + j++ + + // mix r1 + r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) + r1 = rotl16(r1, 2) + j++ + + // mix r2 + r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) + r2 = rotl16(r2, 3) + j++ + + // mix r3 + r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) + r3 = rotl16(r3, 5) + j++ + + } + + r0 = r0 + c.k[r3&63] + r1 = r1 + c.k[r0&63] + r2 = r2 + c.k[r1&63] + r3 = r3 + c.k[r2&63] + + for j <= 60 { + // mix r0 + r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) + r0 = rotl16(r0, 1) + j++ + + // mix r1 + r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) + r1 = rotl16(r1, 2) + j++ + + // mix r2 + r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) + r2 = rotl16(r2, 3) + j++ + + // mix r3 + r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) + r3 = rotl16(r3, 5) + j++ + } + + binary.LittleEndian.PutUint16(dst[0:], r0) + binary.LittleEndian.PutUint16(dst[2:], r1) + binary.LittleEndian.PutUint16(dst[4:], r2) + binary.LittleEndian.PutUint16(dst[6:], r3) +} + +func (c *rc2Cipher) Decrypt(dst, src []byte) { + + r0 := binary.LittleEndian.Uint16(src[0:]) + r1 := binary.LittleEndian.Uint16(src[2:]) + r2 := binary.LittleEndian.Uint16(src[4:]) + r3 := binary.LittleEndian.Uint16(src[6:]) + + j := 63 + + for j >= 44 { + // unmix r3 + r3 = rotl16(r3, 16-5) + r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) + j-- + + // unmix r2 + r2 = rotl16(r2, 16-3) + r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) + j-- + + // unmix r1 + r1 = rotl16(r1, 16-2) + r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) + j-- + + // unmix r0 + r0 = rotl16(r0, 16-1) + r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) + j-- + } + + r3 = r3 - c.k[r2&63] + r2 = r2 - c.k[r1&63] + r1 = r1 - c.k[r0&63] + r0 = r0 - c.k[r3&63] + + for j >= 20 { + // unmix r3 + r3 = rotl16(r3, 16-5) + r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) + j-- + + // unmix r2 + r2 = rotl16(r2, 16-3) + r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) + j-- + + // unmix r1 + r1 = rotl16(r1, 16-2) + r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) + j-- + + // unmix r0 + r0 = rotl16(r0, 16-1) + r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) + j-- + + } + + r3 = r3 - c.k[r2&63] + r2 = r2 - c.k[r1&63] + r1 = r1 - c.k[r0&63] + r0 = r0 - c.k[r3&63] + + for j >= 0 { + // unmix r3 + r3 = rotl16(r3, 16-5) + r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) + j-- + + // unmix r2 + r2 = rotl16(r2, 16-3) + r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) + j-- + + // unmix r1 + r1 = rotl16(r1, 16-2) + r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) + j-- + + // unmix r0 + r0 = rotl16(r0, 16-1) + r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) + j-- + + } + + binary.LittleEndian.PutUint16(dst[0:], r0) + binary.LittleEndian.PutUint16(dst[2:], r1) + binary.LittleEndian.PutUint16(dst[4:], r2) + binary.LittleEndian.PutUint16(dst[6:], r3) +} diff --git a/vendor/golang.org/x/crypto/pkcs12/mac.go b/vendor/golang.org/x/crypto/pkcs12/mac.go new file mode 100644 index 000000000..5f38aa7de --- /dev/null +++ b/vendor/golang.org/x/crypto/pkcs12/mac.go @@ -0,0 +1,45 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pkcs12 + +import ( + "crypto/hmac" + "crypto/sha1" + "crypto/x509/pkix" + "encoding/asn1" +) + +type macData struct { + Mac digestInfo + MacSalt []byte + Iterations int `asn1:"optional,default:1"` +} + +// from PKCS#7: +type digestInfo struct { + Algorithm pkix.AlgorithmIdentifier + Digest []byte +} + +var ( + oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}) +) + +func verifyMac(macData *macData, message, password []byte) error { + if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) { + return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String()) + } + + key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20) + + mac := hmac.New(sha1.New, key) + mac.Write(message) + expectedMAC := mac.Sum(nil) + + if !hmac.Equal(macData.Mac.Digest, expectedMAC) { + return ErrIncorrectPassword + } + return nil +} diff --git a/vendor/golang.org/x/crypto/pkcs12/pbkdf.go b/vendor/golang.org/x/crypto/pkcs12/pbkdf.go new file mode 100644 index 000000000..5c419d41e --- /dev/null +++ b/vendor/golang.org/x/crypto/pkcs12/pbkdf.go @@ -0,0 +1,170 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pkcs12 + +import ( + "bytes" + "crypto/sha1" + "math/big" +) + +var ( + one = big.NewInt(1) +) + +// sha1Sum returns the SHA-1 hash of in. +func sha1Sum(in []byte) []byte { + sum := sha1.Sum(in) + return sum[:] +} + +// fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of +// repeats of pattern. +func fillWithRepeats(pattern []byte, v int) []byte { + if len(pattern) == 0 { + return nil + } + outputLen := v * ((len(pattern) + v - 1) / v) + return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen] +} + +func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) { + // implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments + + // Let H be a hash function built around a compression function f: + + // Z_2^u x Z_2^v -> Z_2^u + + // (that is, H has a chaining variable and output of length u bits, and + // the message input to the compression function of H is v bits). The + // values for u and v are as follows: + + // HASH FUNCTION VALUE u VALUE v + // MD2, MD5 128 512 + // SHA-1 160 512 + // SHA-224 224 512 + // SHA-256 256 512 + // SHA-384 384 1024 + // SHA-512 512 1024 + // SHA-512/224 224 1024 + // SHA-512/256 256 1024 + + // Furthermore, let r be the iteration count. + + // We assume here that u and v are both multiples of 8, as are the + // lengths of the password and salt strings (which we denote by p and s, + // respectively) and the number n of pseudorandom bits required. In + // addition, u and v are of course non-zero. + + // For information on security considerations for MD5 [19], see [25] and + // [1], and on those for MD2, see [18]. + + // The following procedure can be used to produce pseudorandom bits for + // a particular "purpose" that is identified by a byte called "ID". + // This standard specifies 3 different values for the ID byte: + + // 1. If ID=1, then the pseudorandom bits being produced are to be used + // as key material for performing encryption or decryption. + + // 2. If ID=2, then the pseudorandom bits being produced are to be used + // as an IV (Initial Value) for encryption or decryption. + + // 3. If ID=3, then the pseudorandom bits being produced are to be used + // as an integrity key for MACing. + + // 1. Construct a string, D (the "diversifier"), by concatenating v/8 + // copies of ID. + var D []byte + for i := 0; i < v; i++ { + D = append(D, ID) + } + + // 2. Concatenate copies of the salt together to create a string S of + // length v(ceiling(s/v)) bits (the final copy of the salt may be + // truncated to create S). Note that if the salt is the empty + // string, then so is S. + + S := fillWithRepeats(salt, v) + + // 3. Concatenate copies of the password together to create a string P + // of length v(ceiling(p/v)) bits (the final copy of the password + // may be truncated to create P). Note that if the password is the + // empty string, then so is P. + + P := fillWithRepeats(password, v) + + // 4. Set I=S||P to be the concatenation of S and P. + I := append(S, P...) + + // 5. Set c=ceiling(n/u). + c := (size + u - 1) / u + + // 6. For i=1, 2, ..., c, do the following: + A := make([]byte, c*20) + var IjBuf []byte + for i := 0; i < c; i++ { + // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, + // H(H(H(... H(D||I)))) + Ai := hash(append(D, I...)) + for j := 1; j < r; j++ { + Ai = hash(Ai) + } + copy(A[i*20:], Ai[:]) + + if i < c-1 { // skip on last iteration + // B. Concatenate copies of Ai to create a string B of length v + // bits (the final copy of Ai may be truncated to create B). + var B []byte + for len(B) < v { + B = append(B, Ai[:]...) + } + B = B[:v] + + // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit + // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by + // setting I_j=(I_j+B+1) mod 2^v for each j. + { + Bbi := new(big.Int).SetBytes(B) + Ij := new(big.Int) + + for j := 0; j < len(I)/v; j++ { + Ij.SetBytes(I[j*v : (j+1)*v]) + Ij.Add(Ij, Bbi) + Ij.Add(Ij, one) + Ijb := Ij.Bytes() + // We expect Ijb to be exactly v bytes, + // if it is longer or shorter we must + // adjust it accordingly. + if len(Ijb) > v { + Ijb = Ijb[len(Ijb)-v:] + } + if len(Ijb) < v { + if IjBuf == nil { + IjBuf = make([]byte, v) + } + bytesShort := v - len(Ijb) + for i := 0; i < bytesShort; i++ { + IjBuf[i] = 0 + } + copy(IjBuf[bytesShort:], Ijb) + Ijb = IjBuf + } + copy(I[j*v:(j+1)*v], Ijb) + } + } + } + } + // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom + // bit string, A. + + // 8. Use the first n bits of A as the output of this entire process. + return A[:size] + + // If the above process is being used to generate a DES key, the process + // should be used to create 64 random bits, and the key's parity bits + // should be set after the 64 bits have been produced. Similar concerns + // hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any + // similar keys with parity bits "built into them". +} diff --git a/vendor/golang.org/x/crypto/pkcs12/pkcs12.go b/vendor/golang.org/x/crypto/pkcs12/pkcs12.go new file mode 100644 index 000000000..eff9ad3a9 --- /dev/null +++ b/vendor/golang.org/x/crypto/pkcs12/pkcs12.go @@ -0,0 +1,346 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package pkcs12 implements some of PKCS#12. +// +// This implementation is distilled from https://tools.ietf.org/html/rfc7292 +// and referenced documents. It is intended for decoding P12/PFX-stored +// certificates and keys for use with the crypto/tls package. +package pkcs12 + +import ( + "crypto/ecdsa" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/hex" + "encoding/pem" + "errors" +) + +var ( + oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1}) + oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6}) + + oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20}) + oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21}) + oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1}) +) + +type pfxPdu struct { + Version int + AuthSafe contentInfo + MacData macData `asn1:"optional"` +} + +type contentInfo struct { + ContentType asn1.ObjectIdentifier + Content asn1.RawValue `asn1:"tag:0,explicit,optional"` +} + +type encryptedData struct { + Version int + EncryptedContentInfo encryptedContentInfo +} + +type encryptedContentInfo struct { + ContentType asn1.ObjectIdentifier + ContentEncryptionAlgorithm pkix.AlgorithmIdentifier + EncryptedContent []byte `asn1:"tag:0,optional"` +} + +func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier { + return i.ContentEncryptionAlgorithm +} + +func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent } + +type safeBag struct { + Id asn1.ObjectIdentifier + Value asn1.RawValue `asn1:"tag:0,explicit"` + Attributes []pkcs12Attribute `asn1:"set,optional"` +} + +type pkcs12Attribute struct { + Id asn1.ObjectIdentifier + Value asn1.RawValue `asn1:"set"` +} + +type encryptedPrivateKeyInfo struct { + AlgorithmIdentifier pkix.AlgorithmIdentifier + EncryptedData []byte +} + +func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier { + return i.AlgorithmIdentifier +} + +func (i encryptedPrivateKeyInfo) Data() []byte { + return i.EncryptedData +} + +// PEM block types +const ( + certificateType = "CERTIFICATE" + privateKeyType = "PRIVATE KEY" +) + +// unmarshal calls asn1.Unmarshal, but also returns an error if there is any +// trailing data after unmarshaling. +func unmarshal(in []byte, out interface{}) error { + trailing, err := asn1.Unmarshal(in, out) + if err != nil { + return err + } + if len(trailing) != 0 { + return errors.New("pkcs12: trailing data found") + } + return nil +} + +// ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks. +func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) { + encodedPassword, err := bmpString(password) + if err != nil { + return nil, ErrIncorrectPassword + } + + bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword) + + if err != nil { + return nil, err + } + + blocks := make([]*pem.Block, 0, len(bags)) + for _, bag := range bags { + block, err := convertBag(&bag, encodedPassword) + if err != nil { + return nil, err + } + blocks = append(blocks, block) + } + + return blocks, nil +} + +func convertBag(bag *safeBag, password []byte) (*pem.Block, error) { + block := &pem.Block{ + Headers: make(map[string]string), + } + + for _, attribute := range bag.Attributes { + k, v, err := convertAttribute(&attribute) + if err != nil { + return nil, err + } + block.Headers[k] = v + } + + switch { + case bag.Id.Equal(oidCertBag): + block.Type = certificateType + certsData, err := decodeCertBag(bag.Value.Bytes) + if err != nil { + return nil, err + } + block.Bytes = certsData + case bag.Id.Equal(oidPKCS8ShroundedKeyBag): + block.Type = privateKeyType + + key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password) + if err != nil { + return nil, err + } + + switch key := key.(type) { + case *rsa.PrivateKey: + block.Bytes = x509.MarshalPKCS1PrivateKey(key) + case *ecdsa.PrivateKey: + block.Bytes, err = x509.MarshalECPrivateKey(key) + if err != nil { + return nil, err + } + default: + return nil, errors.New("found unknown private key type in PKCS#8 wrapping") + } + default: + return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String()) + } + return block, nil +} + +func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) { + isString := false + + switch { + case attribute.Id.Equal(oidFriendlyName): + key = "friendlyName" + isString = true + case attribute.Id.Equal(oidLocalKeyID): + key = "localKeyId" + case attribute.Id.Equal(oidMicrosoftCSPName): + // This key is chosen to match OpenSSL. + key = "Microsoft CSP Name" + isString = true + default: + return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String()) + } + + if isString { + if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil { + return "", "", err + } + if value, err = decodeBMPString(attribute.Value.Bytes); err != nil { + return "", "", err + } + } else { + var id []byte + if err := unmarshal(attribute.Value.Bytes, &id); err != nil { + return "", "", err + } + value = hex.EncodeToString(id) + } + + return key, value, nil +} + +// Decode extracts a certificate and private key from pfxData. This function +// assumes that there is only one certificate and only one private key in the +// pfxData. +func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) { + encodedPassword, err := bmpString(password) + if err != nil { + return nil, nil, err + } + + bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword) + if err != nil { + return nil, nil, err + } + + if len(bags) != 2 { + err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU") + return + } + + for _, bag := range bags { + switch { + case bag.Id.Equal(oidCertBag): + if certificate != nil { + err = errors.New("pkcs12: expected exactly one certificate bag") + } + + certsData, err := decodeCertBag(bag.Value.Bytes) + if err != nil { + return nil, nil, err + } + certs, err := x509.ParseCertificates(certsData) + if err != nil { + return nil, nil, err + } + if len(certs) != 1 { + err = errors.New("pkcs12: expected exactly one certificate in the certBag") + return nil, nil, err + } + certificate = certs[0] + + case bag.Id.Equal(oidPKCS8ShroundedKeyBag): + if privateKey != nil { + err = errors.New("pkcs12: expected exactly one key bag") + } + + if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil { + return nil, nil, err + } + } + } + + if certificate == nil { + return nil, nil, errors.New("pkcs12: certificate missing") + } + if privateKey == nil { + return nil, nil, errors.New("pkcs12: private key missing") + } + + return +} + +func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) { + pfx := new(pfxPdu) + if err := unmarshal(p12Data, pfx); err != nil { + return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error()) + } + + if pfx.Version != 3 { + return nil, nil, NotImplementedError("can only decode v3 PFX PDU's") + } + + if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) { + return nil, nil, NotImplementedError("only password-protected PFX is implemented") + } + + // unmarshal the explicit bytes in the content for type 'data' + if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil { + return nil, nil, err + } + + if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 { + return nil, nil, errors.New("pkcs12: no MAC in data") + } + + if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil { + if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 { + // some implementations use an empty byte array + // for the empty string password try one more + // time with empty-empty password + password = nil + err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password) + } + if err != nil { + return nil, nil, err + } + } + + var authenticatedSafe []contentInfo + if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil { + return nil, nil, err + } + + if len(authenticatedSafe) != 2 { + return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe") + } + + for _, ci := range authenticatedSafe { + var data []byte + + switch { + case ci.ContentType.Equal(oidDataContentType): + if err := unmarshal(ci.Content.Bytes, &data); err != nil { + return nil, nil, err + } + case ci.ContentType.Equal(oidEncryptedDataContentType): + var encryptedData encryptedData + if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil { + return nil, nil, err + } + if encryptedData.Version != 0 { + return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported") + } + if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil { + return nil, nil, err + } + default: + return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe") + } + + var safeContents []safeBag + if err := unmarshal(data, &safeContents); err != nil { + return nil, nil, err + } + bags = append(bags, safeContents...) + } + + return bags, password, nil +} diff --git a/vendor/golang.org/x/crypto/pkcs12/safebags.go b/vendor/golang.org/x/crypto/pkcs12/safebags.go new file mode 100644 index 000000000..def1f7b98 --- /dev/null +++ b/vendor/golang.org/x/crypto/pkcs12/safebags.go @@ -0,0 +1,57 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pkcs12 + +import ( + "crypto/x509" + "encoding/asn1" + "errors" +) + +var ( + // see https://tools.ietf.org/html/rfc7292#appendix-D + oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1}) + oidPKCS8ShroundedKeyBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2}) + oidCertBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3}) +) + +type certBag struct { + Id asn1.ObjectIdentifier + Data []byte `asn1:"tag:0,explicit"` +} + +func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) { + pkinfo := new(encryptedPrivateKeyInfo) + if err = unmarshal(asn1Data, pkinfo); err != nil { + return nil, errors.New("pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error()) + } + + pkData, err := pbDecrypt(pkinfo, password) + if err != nil { + return nil, errors.New("pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error()) + } + + ret := new(asn1.RawValue) + if err = unmarshal(pkData, ret); err != nil { + return nil, errors.New("pkcs12: error unmarshaling decrypted private key: " + err.Error()) + } + + if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil { + return nil, errors.New("pkcs12: error parsing PKCS#8 private key: " + err.Error()) + } + + return privateKey, nil +} + +func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) { + bag := new(certBag) + if err := unmarshal(asn1Data, bag); err != nil { + return nil, errors.New("pkcs12: error decoding cert bag: " + err.Error()) + } + if !bag.Id.Equal(oidCertTypeX509Certificate) { + return nil, NotImplementedError("only X509 certificates are supported") + } + return bag.Data, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go index b1808dd26..51f740500 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/client.go +++ b/vendor/golang.org/x/crypto/ssh/agent/client.go @@ -25,10 +25,22 @@ import ( "math/big" "sync" + "crypto" "golang.org/x/crypto/ed25519" "golang.org/x/crypto/ssh" ) +// SignatureFlags represent additional flags that can be passed to the signature +// requests an defined in [PROTOCOL.agent] section 4.5.1. +type SignatureFlags uint32 + +// SignatureFlag values as defined in [PROTOCOL.agent] section 5.3. +const ( + SignatureFlagReserved SignatureFlags = 1 << iota + SignatureFlagRsaSha256 + SignatureFlagRsaSha512 +) + // Agent represents the capabilities of an ssh-agent. type Agent interface { // List returns the identities known to the agent. @@ -57,6 +69,26 @@ type Agent interface { Signers() ([]ssh.Signer, error) } +type ExtendedAgent interface { + Agent + + // SignWithFlags signs like Sign, but allows for additional flags to be sent/received + SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) + + // Extension processes a custom extension request. Standard-compliant agents are not + // required to support any extensions, but this method allows agents to implement + // vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7. + // If agent extensions are unsupported entirely this method MUST return an + // ErrExtensionUnsupported error. Similarly, if just the specific extensionType in + // the request is unsupported by the agent then ErrExtensionUnsupported MUST be + // returned. + // + // In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents + // of the response are unspecified (including the type of the message), the complete + // response will be returned as a []byte slice, including the "type" byte of the message. + Extension(extensionType string, contents []byte) ([]byte, error) +} + // ConstraintExtension describes an optional constraint defined by users. type ConstraintExtension struct { // ExtensionName consist of a UTF-8 string suffixed by the @@ -179,6 +211,23 @@ type constrainExtensionAgentMsg struct { Rest []byte `ssh:"rest"` } +// See [PROTOCOL.agent], section 4.7 +const agentExtension = 27 +const agentExtensionFailure = 28 + +// ErrExtensionUnsupported indicates that an extension defined in +// [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this +// error indicates that the agent returned a standard SSH_AGENT_FAILURE message +// as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol +// specification (and therefore this error) does not distinguish between a +// specific extension being unsupported and extensions being unsupported entirely. +var ErrExtensionUnsupported = errors.New("agent: extension unsupported") + +type extensionAgentMsg struct { + ExtensionType string `sshtype:"27"` + Contents []byte +} + // Key represents a protocol 2 public key as defined in // [PROTOCOL.agent], section 2.5.2. type Key struct { @@ -260,7 +309,7 @@ type client struct { // NewClient returns an Agent that talks to an ssh-agent process over // the given connection. -func NewClient(rw io.ReadWriter) Agent { +func NewClient(rw io.ReadWriter) ExtendedAgent { return &client{conn: rw} } @@ -268,6 +317,21 @@ func NewClient(rw io.ReadWriter) Agent { // unmarshaled into reply and replyType is set to the first byte of // the reply, which contains the type of the message. func (c *client) call(req []byte) (reply interface{}, err error) { + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + reply, err = unmarshal(buf) + if err != nil { + return nil, clientErr(err) + } + return reply, nil +} + +// callRaw sends an RPC to the agent. On success, the raw +// bytes of the response are returned; no unmarshalling is +// performed on the response. +func (c *client) callRaw(req []byte) (reply []byte, err error) { c.mu.Lock() defer c.mu.Unlock() @@ -284,18 +348,14 @@ func (c *client) call(req []byte) (reply interface{}, err error) { } respSize := binary.BigEndian.Uint32(respSizeBuf[:]) if respSize > maxAgentResponseBytes { - return nil, clientErr(err) + return nil, clientErr(errors.New("response too large")) } buf := make([]byte, respSize) if _, err = io.ReadFull(c.conn, buf); err != nil { return nil, clientErr(err) } - reply, err = unmarshal(buf) - if err != nil { - return nil, clientErr(err) - } - return reply, err + return buf, nil } func (c *client) simpleCall(req []byte) error { @@ -369,9 +429,14 @@ func (c *client) List() ([]*Key, error) { // Sign has the agent sign the data using a protocol 2 key as defined // in [PROTOCOL.agent] section 2.6.2. func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return c.SignWithFlags(key, data, 0) +} + +func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { req := ssh.Marshal(signRequestAgentMsg{ KeyBlob: key.Marshal(), Data: data, + Flags: uint32(flags), }) msg, err := c.call(req) @@ -681,3 +746,44 @@ func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, // The agent has its own entropy source, so the rand argument is ignored. return s.agent.Sign(s.pub, data) } + +func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) { + var flags SignatureFlags + if opts != nil { + switch opts.HashFunc() { + case crypto.SHA256: + flags = SignatureFlagRsaSha256 + case crypto.SHA512: + flags = SignatureFlagRsaSha512 + } + } + return s.agent.SignWithFlags(s.pub, data, flags) +} + +// Calls an extension method. It is up to the agent implementation as to whether or not +// any particular extension is supported and may always return an error. Because the +// type of the response is up to the implementation, this returns the bytes of the +// response and does not attempt any type of unmarshalling. +func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) { + req := ssh.Marshal(extensionAgentMsg{ + ExtensionType: extensionType, + Contents: contents, + }) + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + if len(buf) == 0 { + return nil, errors.New("agent: failure; empty response") + } + // [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message + // represents an agent that does not support the extension + if buf[0] == agentFailure { + return nil, ErrExtensionUnsupported + } + if buf[0] == agentExtensionFailure { + return nil, errors.New("agent: generic extension failure") + } + + return buf, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go index 1a5163270..c9d979430 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/keyring.go +++ b/vendor/golang.org/x/crypto/ssh/agent/keyring.go @@ -182,6 +182,10 @@ func (r *keyring) Add(key AddedKey) error { // Sign returns a signature for the data. func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return r.SignWithFlags(key, data, 0) +} + +func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { r.mu.Lock() defer r.mu.Unlock() if r.locked { @@ -192,7 +196,24 @@ func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { wanted := key.Marshal() for _, k := range r.keys { if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { - return k.signer.Sign(rand.Reader, data) + if flags == 0 { + return k.signer.Sign(rand.Reader, data) + } else { + if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok { + return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer) + } else { + var algorithm string + switch flags { + case SignatureFlagRsaSha256: + algorithm = ssh.SigAlgoRSASHA2256 + case SignatureFlagRsaSha512: + algorithm = ssh.SigAlgoRSASHA2512 + default: + return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) + } + return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) + } + } } } return nil, errors.New("not found") @@ -213,3 +234,8 @@ func (r *keyring) Signers() ([]ssh.Signer, error) { } return s, nil } + +// The keyring does not support any extensions +func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) { + return nil, ErrExtensionUnsupported +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go index 2e4692cbd..a19497627 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/server.go +++ b/vendor/golang.org/x/crypto/ssh/agent/server.go @@ -128,7 +128,14 @@ func (s *server) processRequest(data []byte) (interface{}, error) { Blob: req.KeyBlob, } - sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags. + var sig *ssh.Signature + var err error + if extendedAgent, ok := s.agent.(ExtendedAgent); ok { + sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags)) + } else { + sig, err = s.agent.Sign(k, req.Data) + } + if err != nil { return nil, err } @@ -150,6 +157,43 @@ func (s *server) processRequest(data []byte) (interface{}, error) { case agentAddIDConstrained, agentAddIdentity: return nil, s.insertIdentity(data) + + case agentExtension: + // Return a stub object where the whole contents of the response gets marshaled. + var responseStub struct { + Rest []byte `ssh:"rest"` + } + + if extendedAgent, ok := s.agent.(ExtendedAgent); !ok { + // If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7 + // requires that we return a standard SSH_AGENT_FAILURE message. + responseStub.Rest = []byte{agentFailure} + } else { + var req extensionAgentMsg + if err := ssh.Unmarshal(data, &req); err != nil { + return nil, err + } + res, err := extendedAgent.Extension(req.ExtensionType, req.Contents) + if err != nil { + // If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE + // message as required by [PROTOCOL.agent] section 4.7. + if err == ErrExtensionUnsupported { + responseStub.Rest = []byte{agentFailure} + } else { + // As the result of any other error processing an extension request, + // [PROTOCOL.agent] section 4.7 requires that we return a + // SSH_AGENT_EXTENSION_FAILURE code. + responseStub.Rest = []byte{agentExtensionFailure} + } + } else { + if len(res) == 0 { + return nil, nil + } + responseStub.Rest = res + } + } + + return responseStub, nil } return nil, fmt.Errorf("unknown opcode %d", data[0]) diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go index 42106f3f2..00ed9923e 100644 --- a/vendor/golang.org/x/crypto/ssh/certs.go +++ b/vendor/golang.org/x/crypto/ssh/certs.go @@ -222,6 +222,11 @@ type openSSHCertSigner struct { signer Signer } +type algorithmOpenSSHCertSigner struct { + *openSSHCertSigner + algorithmSigner AlgorithmSigner +} + // NewCertSigner returns a Signer that signs with the given Certificate, whose // private key is held by signer. It returns an error if the public key in cert // doesn't match the key used by signer. @@ -230,7 +235,12 @@ func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { return nil, errors.New("ssh: signer and cert have different public key") } - return &openSSHCertSigner{cert, signer}, nil + if algorithmSigner, ok := signer.(AlgorithmSigner); ok { + return &algorithmOpenSSHCertSigner{ + &openSSHCertSigner{cert, signer}, algorithmSigner}, nil + } else { + return &openSSHCertSigner{cert, signer}, nil + } } func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { @@ -241,6 +251,10 @@ func (s *openSSHCertSigner) PublicKey() PublicKey { return s.pub } +func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm) +} + const sourceAddressCriticalOption = "source-address" // CertChecker does the work of verifying a certificate. Its methods diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go index ae6ca775e..7b00bff1c 100644 --- a/vendor/golang.org/x/crypto/ssh/client.go +++ b/vendor/golang.org/x/crypto/ssh/client.go @@ -185,7 +185,7 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) { // keys. A HostKeyCallback must return nil if the host key is OK, or // an error to reject it. It receives the hostname as passed to Dial // or NewClientConn. The remote address is the RemoteAddr of the -// net.Conn underlying the the SSH connection. +// net.Conn underlying the SSH connection. type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error // BannerCallback is the function type used for treat the banner sent by diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go index 2261dc386..969804794 100644 --- a/vendor/golang.org/x/crypto/ssh/keys.go +++ b/vendor/golang.org/x/crypto/ssh/keys.go @@ -38,6 +38,16 @@ const ( KeyAlgoED25519 = "ssh-ed25519" ) +// These constants represent non-default signature algorithms that are supported +// as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See +// [PROTOCOL.agent] section 4.5.1 and +// https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10 +const ( + SigAlgoRSA = "ssh-rsa" + SigAlgoRSASHA2256 = "rsa-sha2-256" + SigAlgoRSASHA2512 = "rsa-sha2-512" +) + // parsePubKey parses a public key of the given algorithm. // Use ParsePublicKey for keys with prepended algorithm. func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { @@ -301,6 +311,19 @@ type Signer interface { Sign(rand io.Reader, data []byte) (*Signature, error) } +// A AlgorithmSigner is a Signer that also supports specifying a specific +// algorithm to use for signing. +type AlgorithmSigner interface { + Signer + + // SignWithAlgorithm is like Signer.Sign, but allows specification of a + // non-default signing algorithm. See the SigAlgo* constants in this + // package for signature algorithms supported by this package. Callers may + // pass an empty string for the algorithm in which case the AlgorithmSigner + // will use its default algorithm. + SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) +} + type rsaPublicKey rsa.PublicKey func (r *rsaPublicKey) Type() string { @@ -349,13 +372,21 @@ func (r *rsaPublicKey) Marshal() []byte { } func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { - if sig.Format != r.Type() { + var hash crypto.Hash + switch sig.Format { + case SigAlgoRSA: + hash = crypto.SHA1 + case SigAlgoRSASHA2256: + hash = crypto.SHA256 + case SigAlgoRSASHA2512: + hash = crypto.SHA512 + default: return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) } - h := crypto.SHA1.New() + h := hash.New() h.Write(data) digest := h.Sum(nil) - return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob) + return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob) } func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { @@ -459,6 +490,14 @@ func (k *dsaPrivateKey) PublicKey() PublicKey { } func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { + return k.SignWithAlgorithm(rand, data, "") +} + +func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + if algorithm != "" && algorithm != k.PublicKey().Type() { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + h := crypto.SHA1.New() h.Write(data) digest := h.Sum(nil) @@ -691,16 +730,42 @@ func (s *wrappedSigner) PublicKey() PublicKey { } func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + return s.SignWithAlgorithm(rand, data, "") +} + +func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { var hashFunc crypto.Hash - switch key := s.pubKey.(type) { - case *rsaPublicKey, *dsaPublicKey: - hashFunc = crypto.SHA1 - case *ecdsaPublicKey: - hashFunc = ecHash(key.Curve) - case ed25519PublicKey: - default: - return nil, fmt.Errorf("ssh: unsupported key type %T", key) + if _, ok := s.pubKey.(*rsaPublicKey); ok { + // RSA keys support a few hash functions determined by the requested signature algorithm + switch algorithm { + case "", SigAlgoRSA: + algorithm = SigAlgoRSA + hashFunc = crypto.SHA1 + case SigAlgoRSASHA2256: + hashFunc = crypto.SHA256 + case SigAlgoRSASHA2512: + hashFunc = crypto.SHA512 + default: + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + } else { + // The only supported algorithm for all other key types is the same as the type of the key + if algorithm == "" { + algorithm = s.pubKey.Type() + } else if algorithm != s.pubKey.Type() { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + + switch key := s.pubKey.(type) { + case *dsaPublicKey: + hashFunc = crypto.SHA1 + case *ecdsaPublicKey: + hashFunc = ecHash(key.Curve) + case ed25519PublicKey: + default: + return nil, fmt.Errorf("ssh: unsupported key type %T", key) + } } var digest []byte @@ -745,7 +810,7 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { } return &Signature{ - Format: s.pubKey.Type(), + Format: algorithm, Blob: signature, }, nil } diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go index d0f482531..e86e89661 100644 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -404,7 +404,7 @@ userAuthLoop: perms, authErr = config.PasswordCallback(s, password) case "keyboard-interactive": if config.KeyboardInteractiveCallback == nil { - authErr = errors.New("ssh: keyboard-interactive auth not configubred") + authErr = errors.New("ssh: keyboard-interactive auth not configured") break } @@ -484,6 +484,7 @@ userAuthLoop: // sig.Format. This is usually the same, but // for certs, the names differ. if !isAcceptableAlgo(sig.Format) { + authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) break } signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) diff --git a/vendor/modules.txt b/vendor/modules.txt index 9f29433ce..6c666dc4c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -5,17 +5,23 @@ cloud.google.com/go/internal cloud.google.com/go/internal/optional cloud.google.com/go/internal/version cloud.google.com/go/compute/metadata -# github.com/Azure/azure-sdk-for-go v10.3.0-beta+incompatible -github.com/Azure/azure-sdk-for-go/arm/storage +# github.com/Azure/azure-sdk-for-go v21.3.0+incompatible +github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources +github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/storage/mgmt/storage github.com/Azure/azure-sdk-for-go/storage -github.com/Azure/azure-sdk-for-go/arm/resources/resources -# github.com/Azure/go-autorest v8.3.1+incompatible +github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-02-01/resources +github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2016-01-01/storage +github.com/Azure/azure-sdk-for-go/version +# github.com/Azure/go-autorest v10.15.4+incompatible github.com/Azure/go-autorest/autorest github.com/Azure/go-autorest/autorest/adal github.com/Azure/go-autorest/autorest/azure +github.com/Azure/go-autorest/logger +github.com/Azure/go-autorest/version github.com/Azure/go-autorest/autorest/date -github.com/Azure/go-autorest/autorest/validation +github.com/Azure/go-autorest/autorest/azure/cli github.com/Azure/go-autorest/autorest/to +github.com/Azure/go-autorest/autorest/validation # github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006 github.com/Azure/go-ntlmssp # github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290 @@ -204,6 +210,8 @@ github.com/coreos/go-semver/semver github.com/davecgh/go-spew/spew # github.com/dgrijalva/jwt-go v0.0.0-20160617170158-f0777076321a github.com/dgrijalva/jwt-go +# github.com/dimchansky/utfbom v1.0.0 +github.com/dimchansky/utfbom # github.com/dylanmei/iso8601 v0.1.0 github.com/dylanmei/iso8601 # github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08 @@ -294,6 +302,8 @@ github.com/hashicorp/consul/lib/freeport github.com/hashicorp/consul/testutil/retry # github.com/hashicorp/errwrap v1.0.0 github.com/hashicorp/errwrap +# github.com/hashicorp/go-azure-helpers v0.0.0-20181120094008-dd1e326c8888 +github.com/hashicorp/go-azure-helpers/authentication # github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de github.com/hashicorp/go-checkpoint # github.com/hashicorp/go-cleanhttp v0.5.0 @@ -383,6 +393,8 @@ github.com/keybase/go-crypto/cast5 github.com/keybase/go-crypto/openpgp/elgamal # github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82 github.com/lusis/go-artifactory/src/artifactory.v401 +# github.com/marstr/guid v1.1.0 +github.com/marstr/guid # github.com/masterzen/azure-sdk-for-go v0.0.0-20161014135628-ee4f0065d00c github.com/masterzen/azure-sdk-for-go/core/http github.com/masterzen/azure-sdk-for-go/core/tls @@ -436,8 +448,6 @@ github.com/posener/complete/cmd github.com/posener/complete/match # github.com/satori/go.uuid v0.0.0-20160927100844-b061729afc07 github.com/satori/go.uuid -# github.com/satori/uuid v0.0.0-20160927100844-b061729afc07 -github.com/satori/uuid # github.com/spf13/afero v1.0.2 github.com/spf13/afero github.com/spf13/afero/mem @@ -484,12 +494,13 @@ go.opencensus.io/internal go.opencensus.io/trace/internal go.opencensus.io/trace/tracestate go.opencensus.io -# golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b +# golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869 golang.org/x/crypto/ssh golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/knownhosts golang.org/x/crypto/bcrypt golang.org/x/crypto/openpgp +golang.org/x/crypto/pkcs12 golang.org/x/crypto/curve25519 golang.org/x/crypto/ed25519 golang.org/x/crypto/internal/chacha20 @@ -499,6 +510,7 @@ golang.org/x/crypto/openpgp/armor golang.org/x/crypto/openpgp/errors golang.org/x/crypto/openpgp/packet golang.org/x/crypto/openpgp/s2k +golang.org/x/crypto/pkcs12/internal/rc2 golang.org/x/crypto/ed25519/internal/edwards25519 golang.org/x/crypto/internal/subtle golang.org/x/crypto/md4 diff --git a/website/docs/backends/types/azurerm.html.md b/website/docs/backends/types/azurerm.html.md index 4ecc57375..7abf40309 100644 --- a/website/docs/backends/types/azurerm.html.md +++ b/website/docs/backends/types/azurerm.html.md @@ -7,14 +7,16 @@ description: |- --- -# azurerm (formerly azure) +# azurerm **Kind: Standard (with state locking)** -Stores the state as a given key in a given blob container on [Microsoft Azure Storage](https://azure.microsoft.com/en-us/documentation/articles/storage-introduction/). This backend also supports state locking and consistency checking via native capabilities of Microsoft Azure Storage. +Stores the state as a Blob with the given Key within the Blob Container within [the Blob Storage Account](https://docs.microsoft.com/azure/storage/common/storage-introduction). This backend also supports state locking and consistency checking via native capabilities of Azure Blob Storage. ## Example Configuration +When authenticating using a Service Principal: + ```hcl terraform { backend "azurerm" { @@ -25,11 +27,28 @@ terraform { } ``` -Note that for the access credentials we recommend using a -[partial configuration](/docs/backends/config.html). +When authenticating using the Access Key associated with the Storage Account: + +```hcl +terraform { + backend "azurerm" { + storage_account_name = "abcd1234" + container_name = "tfstate" + key = "prod.terraform.tfstate" + + # rather than defining this inline, the Access Key can also be sourced + # from an Environment Variable - more information is available below. + access_key = "abcdefghijklmnopqrstuvwxyz0123456789..." + } +} +``` + +-> **NOTE:** When using a Service Principal or an Access Key - we recommend using a [Partial Configuration](/docs/backends/config.html) for the credentials. ## Example Referencing +When authenticating using a Service Principal: + ```hcl data "terraform_remote_state" "foo" { backend = "azurerm" @@ -41,24 +60,51 @@ data "terraform_remote_state" "foo" { } ``` +When authenticating using the Access Key associated with the Storage Account: + +```hcl +data "terraform_remote_state" "foo" { + backend = "azurerm" + config = { + storage_account_name = "terraform123abc" + container_name = "terraform-state" + key = "prod.terraform.tfstate" + + # rather than defining this inline, the Access Key can also be sourced + # from an Environment Variable - more information is available below. + access_key = "abcdefghijklmnopqrstuvwxyz0123456789..." + } +} +``` + ## Configuration variables The following configuration options are supported: - * `storage_account_name` - (Required) The name of the storage account - * `container_name` - (Required) The name of the container to use within the storage account - * `key` - (Required) The key where to place/look for state file inside the container - * `access_key` / `ARM_ACCESS_KEY` - (Optional) Storage account access key - * `environment` / `ARM_ENVIRONMENT` - (Optional) The cloud environment to use. Supported values are: - * `public` (default) - * `usgovernment` - * `german` - * `china` +* `storage_account_name` - (Required) The Name of [the Storage Account](https://www.terraform.io/docs/providers/azurerm/r/storage_account.html). -The following configuration options must be supplied if `access_key` is not. +* `container_name` - (Required) The Name of [the Storage Container](https://www.terraform.io/docs/providers/azurerm/r/storage_container.html) within the Storage Account. - * `resource_group_name` - The resource group which contains the storage account. - * `arm_subscription_id` / `ARM_SUBSCRIPTION_ID` - The Azure Subscription ID. - * `arm_client_id` / `ARM_CLIENT_ID` - The Azure Client ID. - * `arm_client_secret` / `ARM_CLIENT_SECRET` - The Azure Client Secret. - * `arm_tenant_id` / `ARM_TENANT_ID` - The Azure Tenant ID. +* `key` - (Required) The name of the Blob used to retrieve/store Terraform's State file inside the Storage Container. + +* `environment` - (Optional) The Azure Environment which should be used. This can also be sourced from the `ARM_ENVIRONMENT` environment variable. Possible values are `public`, `china`, `german`, `stack` and `usgovernment`. Defaults to `public`. + +--- + +When authenticating using the Storage Account's Access Key - the following fields are also supported: + +* `access_key` - (Optional) The Access Key used to access the Blob Storage Account. This can also be sourced from the `ARM_ACCESS_KEY` environment variable. + +--- + +When authenticating using a Service Principal - the following fields are also supported: + +* `resource_group_name` - (Required) The Name of the Resource Group in which the Storage Account exists. + +* `arm_client_id` - (Optional) The Client ID of the Service Principal. This can also be sourced from the `ARM_CLIENT_ID` environment variable. + +* `arm_client_secret` - (Optional) The Client Secret of the Service Principal. This can also be sourced from the `ARM_CLIENT_SECRET` environment variable. + +* `arm_subscription_id` - (Optional) The Subscription ID in which the Storage Account exists. This can also be sourced from the `ARM_SUBSCRIPTION_ID` environment variable. + +* `arm_tenant_id` - (Optional) The Tenant ID in which the Subscription exists. This can also be sourced from the `ARM_TENANT_ID` environment variable.