diff --git a/azurerm/config.go b/azurerm/config.go index 6ab38ebcf185..4aa9845b9259 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -1237,25 +1237,6 @@ func (c *ArmClient) getBlobStorageClientForStorageAccount(ctx context.Context, r return &blobClient, true, nil } -func (c *ArmClient) getFileServiceClientForStorageAccount(ctx context.Context, resourceGroupName, storageAccountName string) (*mainStorage.FileServiceClient, bool, error) { - key, accountExists, err := c.getKeyForStorageAccount(ctx, resourceGroupName, storageAccountName) - if err != nil { - return nil, accountExists, err - } - if !accountExists { - return nil, false, nil - } - - storageClient, err := mainStorage.NewClient(storageAccountName, key, c.environment.StorageEndpointSuffix, - mainStorage.DefaultAPIVersion, true) - if err != nil { - return nil, true, fmt.Errorf("Error creating storage client for storage storeAccount %q: %s", storageAccountName, err) - } - - fileClient := storageClient.GetFileService() - return &fileClient, true, nil -} - func (c *ArmClient) getTableServiceClientForStorageAccount(ctx context.Context, resourceGroupName, storageAccountName string) (*mainStorage.TableServiceClient, bool, error) { key, accountExists, err := c.getKeyForStorageAccount(ctx, resourceGroupName, storageAccountName) if err != nil { diff --git a/azurerm/helpers/azure/resource_group.go b/azurerm/helpers/azure/resource_group.go index 2a782c129f10..f59a1b272bd5 100644 --- a/azurerm/helpers/azure/resource_group.go +++ b/azurerm/helpers/azure/resource_group.go @@ -18,6 +18,15 @@ func SchemaResourceGroupName() *schema.Schema { } } +func SchemaResourceGroupNameDeprecated() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + Deprecated: "This field has been deprecated and is no longer used - will be removed in 2.0 of the Azure Provider", + } +} + func SchemaResourceGroupNameDiffSuppress() *schema.Schema { return &schema.Schema{ Type: schema.TypeString, diff --git a/azurerm/internal/services/storage/client.go b/azurerm/internal/services/storage/client.go index a34c42b78954..ad2985f0aeb0 100644 --- a/azurerm/internal/services/storage/client.go +++ b/azurerm/internal/services/storage/client.go @@ -9,6 +9,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/authorizers" "github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/directories" + "github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares" ) type Client struct { @@ -56,7 +57,7 @@ func (client Client) FindResourceGroup(ctx context.Context, accountName string) return resourceGroup, nil } -func (client Client) FileShareClient(ctx context.Context, resourceGroup, accountName string) (*directories.Client, error) { +func (client Client) FileShareDirectoriesClient(ctx context.Context, resourceGroup, accountName string) (*directories.Client, error) { accountKey, err := client.findAccountKey(ctx, resourceGroup, accountName) if err != nil { return nil, fmt.Errorf("Error retrieving Account Key: %s", err) @@ -68,6 +69,18 @@ func (client Client) FileShareClient(ctx context.Context, resourceGroup, account return &directoriesClient, nil } +func (client Client) FileSharesClient(ctx context.Context, resourceGroup, accountName string) (*shares.Client, error) { + accountKey, err := client.findAccountKey(ctx, resourceGroup, accountName) + if err != nil { + return nil, fmt.Errorf("Error retrieving Account Key: %s", err) + } + + storageAuth := authorizers.NewSharedKeyLiteAuthorizer(accountName, *accountKey) + directoriesClient := shares.New() + directoriesClient.Client.Authorizer = storageAuth + return &directoriesClient, nil +} + func (client Client) findAccountKey(ctx context.Context, resourceGroup, accountName string) (*string, error) { props, err := client.accountsClient.ListKeys(ctx, resourceGroup, accountName) if err != nil { diff --git a/azurerm/resource_arm_storage_share.go b/azurerm/resource_arm_storage_share.go index e2cf9365127d..fcb58736045d 100644 --- a/azurerm/resource_arm_storage_share.go +++ b/azurerm/resource_arm_storage_share.go @@ -4,14 +4,13 @@ import ( "fmt" "log" "regexp" - "strings" + "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" - - "github.com/Azure/azure-sdk-for-go/storage" - "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + "github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares" ) func resourceArmStorageShare() *schema.Resource { @@ -23,7 +22,7 @@ func resourceArmStorageShare() *schema.Resource { Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, - SchemaVersion: 1, + SchemaVersion: 2, MigrateState: resourceStorageShareMigrateState, Schema: map[string]*schema.Schema{ @@ -33,18 +32,25 @@ func resourceArmStorageShare() *schema.Resource { ForceNew: true, ValidateFunc: validateArmStorageShareName, }, - "resource_group_name": azure.SchemaResourceGroupName(), + + // TODO: deprecate the Resource Group Name + "resource_group_name": azure.SchemaResourceGroupNameDeprecated(), + "storage_account_name": { Type: schema.TypeString, Required: true, ForceNew: true, }, + "quota": { Type: schema.TypeInt, Optional: true, Default: 5120, ValidateFunc: validation.IntBetween(1, 5120), }, + + // TODO: support for MetaData and ACL's + "url": { Type: schema.TypeString, Computed: true, @@ -53,56 +59,47 @@ func resourceArmStorageShare() *schema.Resource { } } func resourceArmStorageShareCreate(d *schema.ResourceData, meta interface{}) error { - armClient := meta.(*ArmClient) - ctx := armClient.StopContext + ctx := meta.(*ArmClient).StopContext + storageClient := meta.(*ArmClient).storage + + accountName := d.Get("storage_account_name").(string) + shareName := d.Get("name").(string) + quota := d.Get("quota").(int) - resourceGroupName := d.Get("resource_group_name").(string) - storageAccountName := d.Get("storage_account_name").(string) + metaData := make(map[string]string) - fileClient, accountExists, err := armClient.getFileServiceClientForStorageAccount(ctx, resourceGroupName, storageAccountName) + resourceGroup, err := storageClient.FindResourceGroup(ctx, accountName) if err != nil { - return err - } - if !accountExists { - return fmt.Errorf("Storage Account %q Not Found", storageAccountName) + return fmt.Errorf("Error locating Resource Group: %s", err) } - name := d.Get("name").(string) - metaData := make(map[string]string) // TODO: support MetaData - options := &storage.FileRequestOptions{} + client, err := storageClient.FileSharesClient(ctx, *resourceGroup, accountName) + if err != nil { + return fmt.Errorf("Error building File Share Client: %s", err) + } - log.Printf("[INFO] Creating share %q in storage account %q", name, storageAccountName) - reference := fileClient.GetShareReference(name) + id := client.GetResourceID(accountName, shareName) - id := fmt.Sprintf("%s/%s/%s", name, resourceGroupName, storageAccountName) if requireResourcesToBeImported { - exists, e := reference.Exists() - if e != nil { - return fmt.Errorf("Error checking if Share %q exists (Account %q / Resource Group %q): %s", name, storageAccountName, resourceGroupName, e) + existing, err := client.GetProperties(ctx, *resourceGroup, shareName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for existence of existing Storage Share %q (Account %q / Resource Group %q): %+v", shareName, accountName, *resourceGroup, err) + } } - if exists { + if !utils.ResponseWasNotFound(existing.Response) { return tf.ImportAsExistsError("azurerm_storage_share", id) } } - err = reference.Create(options) - if err != nil { - return fmt.Errorf("Error creating Storage Share %q reference (storage account: %q) : %+v", name, storageAccountName, err) + log.Printf("[INFO] Creating Share %q in Storage Account %q", shareName, accountName) + input := shares.CreateInput{ + QuotaInGB: quota, + MetaData: metaData, } - - log.Printf("[INFO] Setting share %q metadata in storage account %q", name, storageAccountName) - reference.Metadata = metaData - if err := reference.SetMetadata(options); err != nil { - return fmt.Errorf("Error setting metadata on Storage Share %q: %+v", name, err) - } - - log.Printf("[INFO] Setting share %q properties in storage account %q", name, storageAccountName) - reference.Properties = storage.ShareProperties{ - Quota: d.Get("quota").(int), - } - if err := reference.SetProperties(options); err != nil { - return fmt.Errorf("Error setting properties on Storage Share %q: %+v", name, err) + if _, err := client.Create(ctx, accountName, shareName, input); err != nil { + return fmt.Errorf("Error creating Share %q (Account %q / Resource Group %q): %+v", shareName, accountName, *resourceGroup, err) } d.SetId(id) @@ -110,124 +107,121 @@ func resourceArmStorageShareCreate(d *schema.ResourceData, meta interface{}) err } func resourceArmStorageShareRead(d *schema.ResourceData, meta interface{}) error { - armClient := meta.(*ArmClient) - ctx := armClient.StopContext + ctx := meta.(*ArmClient).StopContext + storageClient := meta.(*ArmClient).storage - id := strings.Split(d.Id(), "/") - if len(id) != 3 { - return fmt.Errorf("ID was not in the expected format - expected `{name}/{resourceGroup}/{storageAccountName}` got %q", id) + id, err := shares.ParseResourceID(d.Id()) + if err != nil { + return err } - name := id[0] - resourceGroupName := id[1] - storageAccountName := id[2] - fileClient, accountExists, err := armClient.getFileServiceClientForStorageAccount(ctx, resourceGroupName, storageAccountName) + resourceGroup, err := storageClient.FindResourceGroup(ctx, id.AccountName) if err != nil { - return err + return fmt.Errorf("Error locating Resource Group for Storage Account %q: %s", id.AccountName, err) } - if !accountExists { - log.Printf("[DEBUG] Storage account %q not found, removing file %q from state", storageAccountName, d.Id()) + if resourceGroup == nil { + log.Printf("[DEBUG] Unable to locate Resource Group for Storage Account %q - assuming removed & removing from state", id.AccountName) d.SetId("") return nil } - reference := fileClient.GetShareReference(name) - exists, err := reference.Exists() + client, err := storageClient.FileSharesClient(ctx, *resourceGroup, id.AccountName) if err != nil { - return fmt.Errorf("Error testing existence of share %q: %s", name, err) + return fmt.Errorf("Error building File Share Client for Storage Account %q (Resource Group %q): %s", id.AccountName, *resourceGroup, err) } - if !exists { - log.Printf("[INFO] Share %q no longer exists, removing from state...", name) - d.SetId("") - return nil - } + props, err := client.GetProperties(ctx, id.AccountName, id.ShareName) + if err != nil { + if utils.ResponseWasNotFound(props.Response) { + log.Printf("[DEBUG] File Share %q was not found in Account %q / Resource Group %q - assuming removed & removing from state", id.ShareName, id.AccountName, *resourceGroup) + d.SetId("") + return nil + } - url := reference.URL() - if url == "" { - log.Printf("[INFO] URL for %q is empty", name) + return fmt.Errorf("Error retrieving File Share %q (Account %q / Resource Group %q): %s", id.ShareName, id.AccountName, *resourceGroup, err) } - d.Set("name", name) - d.Set("resource_group_name", resourceGroupName) - d.Set("storage_account_name", storageAccountName) - d.Set("url", url) - if err := reference.FetchAttributes(nil); err != nil { - return fmt.Errorf("Error fetching properties on Storage Share %q: %+v", name, err) - } - d.Set("quota", reference.Properties.Quota) + d.Set("name", id.ShareName) + d.Set("storage_account_name", id.AccountName) + d.Set("url", client.GetResourceID(id.AccountName, id.ShareName)) + d.Set("quota", props.ShareQuota) + + // Deprecated: remove in 2.0 + d.Set("resource_group_name", resourceGroup) return nil } func resourceArmStorageShareUpdate(d *schema.ResourceData, meta interface{}) error { - armClient := meta.(*ArmClient) - ctx := armClient.StopContext + ctx := meta.(*ArmClient).StopContext + storageClient := meta.(*ArmClient).storage - id := strings.Split(d.Id(), "/") - if len(id) != 3 { - return fmt.Errorf("ID was not in the expected format - expected `{name}/{resourceGroup}/{storageAccountName}` got %q", id) + id, err := shares.ParseResourceID(d.Id()) + if err != nil { + return err } - name := id[0] - resourceGroupName := id[1] - storageAccountName := id[2] - fileClient, accountExists, err := armClient.getFileServiceClientForStorageAccount(ctx, resourceGroupName, storageAccountName) + resourceGroup, err := storageClient.FindResourceGroup(ctx, id.AccountName) if err != nil { - return err + return fmt.Errorf("Error locating Resource Group for Storage Account %q: %s", id.AccountName, err) } - if !accountExists { - return fmt.Errorf("Storage Account %q Not Found", storageAccountName) + if resourceGroup == nil { + log.Printf("[DEBUG] Unable to locate Resource Group for Storage Account %q - assuming removed & removing from state", id.AccountName) + d.SetId("") + return nil } - options := &storage.FileRequestOptions{} + client, err := storageClient.FileSharesClient(ctx, *resourceGroup, id.AccountName) + if err != nil { + return fmt.Errorf("Error building File Share Client for Storage Account %q (Resource Group %q): %s", id.AccountName, *resourceGroup, err) + } - reference := fileClient.GetShareReference(name) + if d.HasChange("quota") { + log.Printf("[DEBUG] Updating the Quota for File Share %q (Storage Account %q)", id.ShareName, id.AccountName) + quota := d.Get("quota").(int) + if _, err := client.SetProperties(ctx, id.AccountName, id.ShareName, quota); err != nil { + return fmt.Errorf("Error updating Quota for File Share %q (Storage Account %q): %s", id.ShareName, id.AccountName, err) + } - log.Printf("[INFO] Setting share %q properties in storage account %q", name, storageAccountName) - reference.Properties = storage.ShareProperties{ - Quota: d.Get("quota").(int), - } - if err := reference.SetProperties(options); err != nil { - return fmt.Errorf("Error setting properties on Storage Share %q: %+v", name, err) + log.Printf("[DEBUG] Updated the Quota for File Share %q (Storage Account %q)", id.ShareName, id.AccountName) } return resourceArmStorageShareRead(d, meta) } func resourceArmStorageShareDelete(d *schema.ResourceData, meta interface{}) error { - armClient := meta.(*ArmClient) - ctx := armClient.StopContext + ctx := meta.(*ArmClient).StopContext + storageClient := meta.(*ArmClient).storage - id := strings.Split(d.Id(), "/") - if len(id) != 3 { - return fmt.Errorf("ID was not in the expected format - expected `{name}/{resourceGroup}/{storageAccountName}` got %q", id) + id, err := shares.ParseResourceID(d.Id()) + if err != nil { + return err } - name := id[0] - resourceGroupName := id[1] - storageAccountName := id[2] - fileClient, accountExists, err := armClient.getFileServiceClientForStorageAccount(ctx, resourceGroupName, storageAccountName) + resourceGroup, err := storageClient.FindResourceGroup(ctx, id.AccountName) if err != nil { - return err + return fmt.Errorf("Error locating Resource Group for Storage Account %q: %s", id.AccountName, err) } - if !accountExists { - log.Printf("[INFO]Storage Account %q doesn't exist so the file won't exist", storageAccountName) + if resourceGroup == nil { + log.Printf("[DEBUG] Unable to locate Resource Group for Storage Account %q - assuming removed & removing from state", id.AccountName) + d.SetId("") return nil } - reference := fileClient.GetShareReference(name) - options := &storage.FileRequestOptions{} + client, err := storageClient.FileSharesClient(ctx, *resourceGroup, id.AccountName) + if err != nil { + return fmt.Errorf("Error building File Share Client for Storage Account %q (Resource Group %q): %s", id.AccountName, *resourceGroup, err) + } - if _, err = reference.DeleteIfExists(options); err != nil { - return fmt.Errorf("Error deleting storage file %q: %s", name, err) + deleteSnapshots := true + if _, err := client.Delete(ctx, id.AccountName, id.ShareName, deleteSnapshots); err != nil { + return fmt.Errorf("Error deleting File Share %q (Storage Account %q / Resource Group %q): %s", id.ShareName, id.AccountName, *resourceGroup, err) } - d.SetId("") return nil } -//Following the naming convention as laid out in the docs https://msdn.microsoft.com/library/azure/dn167011.aspx +// Following the naming convention as laid out in the docs https://msdn.microsoft.com/library/azure/dn167011.aspx func validateArmStorageShareName(v interface{}, k string) (warnings []string, errors []error) { value := v.(string) if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { diff --git a/azurerm/resource_arm_storage_share_directory.go b/azurerm/resource_arm_storage_share_directory.go index 606dd9895145..974a7898d60a 100644 --- a/azurerm/resource_arm_storage_share_directory.go +++ b/azurerm/resource_arm_storage_share_directory.go @@ -63,7 +63,7 @@ func resourceArmStorageShareDirectoryCreate(d *schema.ResourceData, meta interfa return fmt.Errorf("Error locating Resource Group: %s", err) } - client, err := storageClient.FileShareClient(ctx, *resourceGroup, accountName) + client, err := storageClient.FileShareDirectoriesClient(ctx, *resourceGroup, accountName) if err != nil { return fmt.Errorf("Error building File Share Client: %s", err) } @@ -109,7 +109,7 @@ func resourceArmStorageShareDirectoryUpdate(d *schema.ResourceData, meta interfa return fmt.Errorf("Error locating Resource Group: %s", err) } - client, err := storageClient.FileShareClient(ctx, *resourceGroup, id.AccountName) + client, err := storageClient.FileShareDirectoriesClient(ctx, *resourceGroup, id.AccountName) if err != nil { return fmt.Errorf("Error building File Share Client: %s", err) } @@ -140,7 +140,7 @@ func resourceArmStorageShareDirectoryRead(d *schema.ResourceData, meta interface return nil } - client, err := storageClient.FileShareClient(ctx, *resourceGroup, id.AccountName) + client, err := storageClient.FileShareDirectoriesClient(ctx, *resourceGroup, id.AccountName) if err != nil { return fmt.Errorf("Error building File Share Client for Storage Account %q (Resource Group %q): %s", id.AccountName, *resourceGroup, err) } @@ -180,7 +180,7 @@ func resourceArmStorageShareDirectoryDelete(d *schema.ResourceData, meta interfa return nil } - client, err := storageClient.FileShareClient(ctx, *resourceGroup, id.AccountName) + client, err := storageClient.FileShareDirectoriesClient(ctx, *resourceGroup, id.AccountName) if err != nil { return fmt.Errorf("Error building File Share Client for Storage Account %q (Resource Group %q): %s", id.AccountName, *resourceGroup, err) } diff --git a/azurerm/resource_arm_storage_share_directory_test.go b/azurerm/resource_arm_storage_share_directory_test.go index ed0e4e8f648e..1173bf03e042 100644 --- a/azurerm/resource_arm_storage_share_directory_test.go +++ b/azurerm/resource_arm_storage_share_directory_test.go @@ -171,14 +171,14 @@ func testCheckAzureRMStorageShareDirectoryExists(resourceName string) resource.T return fmt.Errorf("Error finding Resource Group: %s", err) } - client, err := storageClient.FileShareClient(ctx, *resourceGroup, accountName) + client, err := storageClient.FileShareDirectoriesClient(ctx, *resourceGroup, accountName) if err != nil { return fmt.Errorf("Error building FileShare Client: %s", err) } resp, err := client.Get(ctx, accountName, shareName, name) if err != nil { - return fmt.Errorf("Bad: Get on FileShareClient: %+v", err) + return fmt.Errorf("Bad: Get on FileShareDirectoriesClient: %+v", err) } if resp.StatusCode == http.StatusNotFound { @@ -212,14 +212,14 @@ func testCheckAzureRMStorageShareDirectoryDestroy(s *terraform.State) error { return nil } - client, err := storageClient.FileShareClient(ctx, *resourceGroup, accountName) + client, err := storageClient.FileShareDirectoriesClient(ctx, *resourceGroup, accountName) if err != nil { return fmt.Errorf("Error building FileShare Client: %s", err) } resp, err := client.Get(ctx, accountName, shareName, name) if err != nil { - return fmt.Errorf("Bad: Get on FileShareClient: %+v", err) + return fmt.Errorf("Bad: Get on FileShareDirectoriesClient: %+v", err) } if resp.StatusCode != http.StatusNotFound { @@ -327,7 +327,6 @@ resource "azurerm_storage_account" "test" { resource "azurerm_storage_share" "test" { name = "fileshare" - resource_group_name = "${azurerm_resource_group.test.name}" storage_account_name = "${azurerm_storage_account.test.name}" quota = 50 } diff --git a/azurerm/resource_arm_storage_share_migration.go b/azurerm/resource_arm_storage_share_migration.go index f2bd6deccc46..115331f6752f 100644 --- a/azurerm/resource_arm_storage_share_migration.go +++ b/azurerm/resource_arm_storage_share_migration.go @@ -5,14 +5,17 @@ import ( "log" "github.com/hashicorp/terraform/terraform" + "github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares" ) -func resourceStorageShareMigrateState( - v int, is *terraform.InstanceState, _ interface{}) (*terraform.InstanceState, error) { +func resourceStorageShareMigrateState(v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { switch v { case 0: log.Println("[INFO] Found AzureRM Storage Share State v0; migrating to v1") return migrateStorageShareStateV0toV1(is) + case 1: + log.Println("[INFO] Found AzureRM Storage Share State v1; migrating to v2") + return migrateStorageShareStateV1toV2(is, meta) default: return is, fmt.Errorf("Unexpected schema version: %d", v) } @@ -37,3 +40,25 @@ func migrateStorageShareStateV0toV1(is *terraform.InstanceState) (*terraform.Ins return is, nil } + +func migrateStorageShareStateV1toV2(is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) { + if is.Empty() { + log.Println("[DEBUG] Empty InstanceState; nothing to migrate.") + return is, nil + } + + log.Printf("[DEBUG] ARM Storage Share Attributes before Migration: %#v", is.Attributes) + + environment := meta.(*ArmClient).environment + client := shares.NewWithEnvironment(environment) + + shareName := is.Attributes["name"] + storageAccountName := is.Attributes["storage_account_name"] + newID := client.GetResourceID(storageAccountName, shareName) + is.Attributes["id"] = newID + is.ID = newID + + log.Printf("[DEBUG] ARM Storage Share Attributes after State Migration: %#v", is.Attributes) + + return is, nil +} diff --git a/azurerm/resource_arm_storage_share_migration_test.go b/azurerm/resource_arm_storage_share_migration_test.go index 378ba12030b4..f6c1878450db 100644 --- a/azurerm/resource_arm_storage_share_migration_test.go +++ b/azurerm/resource_arm_storage_share_migration_test.go @@ -3,6 +3,7 @@ package azurerm import ( "testing" + "github.com/Azure/go-autorest/autorest/azure" "github.com/hashicorp/terraform/terraform" ) @@ -26,6 +27,36 @@ func TestAzureRMStorageShareMigrateState(t *testing.T) { "id": "some_id/some_rgn/some_sgn", }, }, + "v1_2_public": { + StateVersion: 1, + ID: "some_id", + InputAttributes: map[string]string{ + "name": "some_id", + "resource_group_name": "some_rgn", + "storage_account_name": "some_sgn", + }, + ExpectedAttributes: map[string]string{ + "id": "https://some_sgn.file.core.windows.net/some_id", + }, + Meta: &ArmClient{ + environment: azure.PublicCloud, + }, + }, + "v1_2_germany": { + StateVersion: 1, + ID: "some_id", + InputAttributes: map[string]string{ + "name": "some_id", + "resource_group_name": "some_rgn", + "storage_account_name": "some_sgn", + }, + ExpectedAttributes: map[string]string{ + "id": "https://some_sgn.file.core.cloudapi.de/some_id", + }, + Meta: &ArmClient{ + environment: azure.GermanCloud, + }, + }, } for tn, tc := range cases { diff --git a/azurerm/resource_arm_storage_share_test.go b/azurerm/resource_arm_storage_share_test.go index 4dc3a50879a7..fc309bc973a1 100644 --- a/azurerm/resource_arm_storage_share_test.go +++ b/azurerm/resource_arm_storage_share_test.go @@ -2,23 +2,20 @@ package azurerm import ( "fmt" - "log" "strings" "testing" - "github.com/Azure/azure-sdk-for-go/storage" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) func TestAccAzureRMStorageShare_basic(t *testing.T) { - var sS storage.Share - ri := tf.AccRandTimeInt() rs := strings.ToLower(acctest.RandString(11)) - config := testAccAzureRMStorageShare_basic(ri, rs, testLocation()) + location := testLocation() resourceName := "azurerm_storage_share.test" resource.ParallelTest(t, resource.TestCase{ @@ -27,9 +24,9 @@ func TestAccAzureRMStorageShare_basic(t *testing.T) { CheckDestroy: testCheckAzureRMStorageShareDestroy, Steps: []resource.TestStep{ { - Config: config, + Config: testAccAzureRMStorageShare_basic(ri, rs, location), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMStorageShareExists(resourceName, &sS), + testCheckAzureRMStorageShareExists(resourceName), ), }, { @@ -47,8 +44,6 @@ func TestAccAzureRMStorageShare_requiresImport(t *testing.T) { return } - var sS storage.Share - ri := tf.AccRandTimeInt() rs := strings.ToLower(acctest.RandString(11)) location := testLocation() @@ -62,7 +57,7 @@ func TestAccAzureRMStorageShare_requiresImport(t *testing.T) { { Config: testAccAzureRMStorageShare_basic(ri, rs, location), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMStorageShareExists(resourceName, &sS), + testCheckAzureRMStorageShareExists(resourceName), ), }, { @@ -74,11 +69,9 @@ func TestAccAzureRMStorageShare_requiresImport(t *testing.T) { } func TestAccAzureRMStorageShare_disappears(t *testing.T) { - var sS storage.Share - ri := tf.AccRandTimeInt() rs := strings.ToLower(acctest.RandString(11)) - config := testAccAzureRMStorageShare_basic(ri, rs, testLocation()) + location := testLocation() resourceName := "azurerm_storage_share.test" resource.ParallelTest(t, resource.TestCase{ @@ -87,10 +80,10 @@ func TestAccAzureRMStorageShare_disappears(t *testing.T) { CheckDestroy: testCheckAzureRMStorageShareDestroy, Steps: []resource.TestStep{ { - Config: config, + Config: testAccAzureRMStorageShare_basic(ri, rs, location), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMStorageShareExists(resourceName, &sS), - testAccARMStorageShareDisappears(resourceName, &sS), + testCheckAzureRMStorageShareExists(resourceName), + testCheckAzureRMStorageShareDisappears(resourceName), ), ExpectNonEmptyPlan: true, }, @@ -99,12 +92,9 @@ func TestAccAzureRMStorageShare_disappears(t *testing.T) { } func TestAccAzureRMStorageShare_updateQuota(t *testing.T) { - var sS storage.Share - ri := tf.AccRandTimeInt() rs := strings.ToLower(acctest.RandString(11)) - config := testAccAzureRMStorageShare_basic(ri, rs, testLocation()) - config2 := testAccAzureRMStorageShare_updateQuota(ri, rs, testLocation()) + location := testLocation() resourceName := "azurerm_storage_share.test" resource.ParallelTest(t, resource.TestCase{ @@ -113,15 +103,15 @@ func TestAccAzureRMStorageShare_updateQuota(t *testing.T) { CheckDestroy: testCheckAzureRMStorageShareDestroy, Steps: []resource.TestStep{ { - Config: config, + Config: testAccAzureRMStorageShare_basic(ri, rs, location), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMStorageShareExists(resourceName, &sS), + testCheckAzureRMStorageShareExists(resourceName), ), }, { - Config: config2, + Config: testAccAzureRMStorageShare_updateQuota(ri, rs, location), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMStorageShareExists(resourceName, &sS), + testCheckAzureRMStorageShareExists(resourceName), resource.TestCheckResourceAttr(resourceName, "quota", "5"), ), }, @@ -129,89 +119,63 @@ func TestAccAzureRMStorageShare_updateQuota(t *testing.T) { }) } -func testCheckAzureRMStorageShareExists(resourceName string, sS *storage.Share) resource.TestCheckFunc { +func testCheckAzureRMStorageShareExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[resourceName] if !ok { return fmt.Errorf("Not found: %s", resourceName) } - name := rs.Primary.Attributes["name"] - storageAccountName := rs.Primary.Attributes["storage_account_name"] - resourceGroupName, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] - if !hasResourceGroup { - return fmt.Errorf("Bad: no resource group found in state for share: %s", name) - } + shareName := rs.Primary.Attributes["name"] + accountName := rs.Primary.Attributes["storage_account_name"] - armClient := testAccProvider.Meta().(*ArmClient) - ctx := armClient.StopContext - fileClient, accountExists, err := armClient.getFileServiceClientForStorageAccount(ctx, resourceGroupName, storageAccountName) - if err != nil { - return err - } - if !accountExists { - return fmt.Errorf("Bad: Storage Account %q does not exist", storageAccountName) - } + storageClient := testAccProvider.Meta().(*ArmClient).storage + ctx := testAccProvider.Meta().(*ArmClient).StopContext - shares, err := fileClient.ListShares(storage.ListSharesParameters{ - Prefix: name, - Timeout: 90, - }) + resourceGroup, err := storageClient.FindResourceGroup(ctx, accountName) if err != nil { - return fmt.Errorf("Error listing Storage Share %q shares (storage account: %q) : %+v", name, storageAccountName, err) - } - - if len(shares.Shares) == 0 { - return fmt.Errorf("Bad: Share %q (storage account: %q) does not exist", name, storageAccountName) + return fmt.Errorf("Error finding Resource Group: %s", err) } - var found bool - for _, share := range shares.Shares { - if share.Name == name { - found = true - *sS = share - } + client, err := storageClient.FileSharesClient(ctx, *resourceGroup, accountName) + if err != nil { + return fmt.Errorf("Error building FileShare Client: %s", err) } - if !found { - return fmt.Errorf("Bad: Share %q (storage account: %q) does not exist", name, storageAccountName) + _, err = client.GetProperties(ctx, accountName, shareName) + if err != nil { + return fmt.Errorf("Bad: Share %q (Storage Account: %q) does not exist", shareName, accountName) } return nil } } -func testAccARMStorageShareDisappears(resourceName string, sS *storage.Share) resource.TestCheckFunc { +func testCheckAzureRMStorageShareDisappears(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] if !ok { return fmt.Errorf("Not found: %s", resourceName) } - armClient := testAccProvider.Meta().(*ArmClient) - ctx := armClient.StopContext + shareName := rs.Primary.Attributes["name"] + accountName := rs.Primary.Attributes["storage_account_name"] - storageAccountName := rs.Primary.Attributes["storage_account_name"] - resourceGroupName, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] - if !hasResourceGroup { - return fmt.Errorf("Bad: no resource group found in state for storage share: %s", sS.Name) - } + storageClient := testAccProvider.Meta().(*ArmClient).storage + ctx := testAccProvider.Meta().(*ArmClient).StopContext - fileClient, accountExists, err := armClient.getFileServiceClientForStorageAccount(ctx, resourceGroupName, storageAccountName) + resourceGroup, err := storageClient.FindResourceGroup(ctx, accountName) if err != nil { - return err - } - if !accountExists { - log.Printf("[INFO]Storage Account %q doesn't exist so the share won't exist", storageAccountName) - return nil + return fmt.Errorf("Error finding Resource Group: %s", err) } - reference := fileClient.GetShareReference(sS.Name) - options := &storage.FileRequestOptions{} + client, err := storageClient.FileSharesClient(ctx, *resourceGroup, accountName) + if err != nil { + return fmt.Errorf("Error building FileShare Client: %s", err) + } - if _, err = reference.DeleteIfExists(options); err != nil { - return fmt.Errorf("Error deleting storage Share %q: %s", sS.Name, err) + if _, err := client.Delete(ctx, accountName, shareName, true); err != nil { + return fmt.Errorf("Error deleting Share %q (Account %q): %v", shareName, accountName, err) } return nil @@ -224,43 +188,35 @@ func testCheckAzureRMStorageShareDestroy(s *terraform.State) error { continue } - name := rs.Primary.Attributes["name"] - storageAccountName := rs.Primary.Attributes["storage_account_name"] - resourceGroupName, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] - if !hasResourceGroup { - return fmt.Errorf("Bad: no resource group found in state for share: %s", name) - } + shareName := rs.Primary.Attributes["name"] + accountName := rs.Primary.Attributes["storage_account_name"] + + storageClient := testAccProvider.Meta().(*ArmClient).storage + ctx := testAccProvider.Meta().(*ArmClient).StopContext - armClient := testAccProvider.Meta().(*ArmClient) - ctx := armClient.StopContext - fileClient, accountExists, err := armClient.getFileServiceClientForStorageAccount(ctx, resourceGroupName, storageAccountName) + resourceGroup, err := storageClient.FindResourceGroup(ctx, accountName) if err != nil { - //If we can't get keys then the blob can't exist - return nil + return fmt.Errorf("Error finding Resource Group: %s", err) } - if !accountExists { + if resourceGroup == nil { return nil } - shares, err := fileClient.ListShares(storage.ListSharesParameters{ - Prefix: name, - Timeout: 90, - }) - + client, err := storageClient.FileSharesClient(ctx, *resourceGroup, accountName) if err != nil { - return nil + return fmt.Errorf("Error building FileShare Client: %s", err) } - var found bool - for _, share := range shares.Shares { - if share.Name == name { - found = true + props, err := client.GetProperties(ctx, accountName, shareName) + if err != nil { + if utils.ResponseWasNotFound(props.Response) { + return nil } - } - if found { - return fmt.Errorf("Bad: Share %q (storage account: %q) still exists", name, storageAccountName) + return fmt.Errorf("Error retrieving Share %q: %s", shareName, accountName) } + + return fmt.Errorf("Bad: Share %q (storage account: %q) still exists", shareName, accountName) } return nil diff --git a/go.mod b/go.mod index 065e8734cd6d..a972047b3d37 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/satori/go.uuid v1.2.0 github.com/satori/uuid v0.0.0-20160927100844-b061729afc07 github.com/terraform-providers/terraform-provider-azuread v0.4.1-0.20190610202312-5a179146b9f9 - github.com/tombuildsstuff/giovanni v0.2.0 + github.com/tombuildsstuff/giovanni v0.2.1 golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 golang.org/x/net v0.0.0-20190502183928-7f726cade0ab gopkg.in/yaml.v2 v2.2.2 diff --git a/go.sum b/go.sum index b4c3607f7ed5..feac33a8b471 100644 --- a/go.sum +++ b/go.sum @@ -432,6 +432,8 @@ github.com/terraform-providers/terraform-provider-openstack v1.15.0/go.mod h1:2a github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tombuildsstuff/giovanni v0.2.0 h1:ga5qVSU7rKtoGk83Y7ar4LNgAChYy/GKi31cR8DqK/c= github.com/tombuildsstuff/giovanni v0.2.0/go.mod h1:3UHcoRZCvWTjXMWCJ0epD1VROlPMwZeeof3vfP6NiWM= +github.com/tombuildsstuff/giovanni v0.2.1 h1:m9M5EQgz4NmhwtU8dO2nLuW4/8j4lbrOt1jooNv22kc= +github.com/tombuildsstuff/giovanni v0.2.1/go.mod h1:3UHcoRZCvWTjXMWCJ0epD1VROlPMwZeeof3vfP6NiWM= github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5 h1:cMjKdf4PxEBN9K5HaD9UMW8gkTbM0kMzkTa9SJe0WNQ= github.com/ugorji/go v0.0.0-20180813092308-00b869d2f4a5/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/README.md b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/README.md new file mode 100644 index 000000000000..94b3bdb49c55 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/README.md @@ -0,0 +1,43 @@ +## File Storage Shares SDK for API version 2018-11-09 + +This package allows you to interact with the Shares File Storage API + +### Supported Authorizers + +* Azure Active Directory (for the Resource Endpoint `https://storage.azure.com`) +* SharedKeyLite (Blob, File & Queue) + +### Example Usage + +```go +package main + +import ( + "context" + "fmt" + "time" + + "github.com/Azure/go-autorest/autorest" + "github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares" +) + +func Example() error { + accountName := "storageaccount1" + storageAccountKey := "ABC123...." + shareName := "myshare" + + storageAuth := autorest.NewSharedKeyLiteAuthorizer(accountName, storageAccountKey) + sharesClient := shares.New() + sharesClient.Client.Authorizer = storageAuth + + ctx := context.TODO() + input := shares.CreateInput{ + QuotaInGB: 2, + } + if _, err := sharesClient.Create(ctx, accountName, shareName, input); err != nil { + return fmt.Errorf("Error creating Share: %s", err) + } + + return nil +} +``` \ No newline at end of file diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/acl_get.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/acl_get.go new file mode 100644 index 000000000000..ea6ff4c2dd26 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/acl_get.go @@ -0,0 +1,98 @@ +package shares + +import ( + "context" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" +) + +type GetACLResult struct { + autorest.Response + + SignedIdentifiers []SignedIdentifier `xml:"SignedIdentifier"` +} + +// GetACL get the Access Control List for the specified Storage Share +func (client Client) GetACL(ctx context.Context, accountName, shareName string) (result GetACLResult, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "GetACL", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "GetACL", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "GetACL", "`shareName` must be a lower-cased string.") + } + + req, err := client.GetACLPreparer(ctx, accountName, shareName) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetACL", nil, "Failure preparing request") + return + } + + resp, err := client.GetACLSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "GetACL", resp, "Failure sending request") + return + } + + result, err = client.GetACLResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetACL", resp, "Failure responding to request") + return + } + + return +} + +// GetACLPreparer prepares the GetACL request. +func (client Client) GetACLPreparer(ctx context.Context, accountName, shareName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("query", "share"), + "comp": autorest.Encode("query", "acl"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsGet(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// GetACLSender sends the GetACL request. The method will close the +// http.Response Body if it receives an error. +func (client Client) GetACLSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// GetACLResponder handles the response to the GetACL request. The method always +// closes the http.Response Body. +func (client Client) GetACLResponder(resp *http.Response) (result GetACLResult, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingXML(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/acl_set.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/acl_set.go new file mode 100644 index 000000000000..18d1788a2ee4 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/acl_set.go @@ -0,0 +1,103 @@ +package shares + +import ( + "context" + "encoding/xml" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" +) + +type setAcl struct { + SignedIdentifiers []SignedIdentifier `xml:"SignedIdentifier"` + + XMLName xml.Name `xml:"SignedIdentifiers"` +} + +// SetACL sets the specified Access Control List on the specified Storage Share +func (client Client) SetACL(ctx context.Context, accountName, shareName string, acls []SignedIdentifier) (result autorest.Response, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "SetACL", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "SetACL", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "SetACL", "`shareName` must be a lower-cased string.") + } + + req, err := client.SetACLPreparer(ctx, accountName, shareName, acls) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "SetACL", nil, "Failure preparing request") + return + } + + resp, err := client.SetACLSender(req) + if err != nil { + result = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "SetACL", resp, "Failure sending request") + return + } + + result, err = client.SetACLResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "SetACL", resp, "Failure responding to request") + return + } + + return +} + +// SetACLPreparer prepares the SetACL request. +func (client Client) SetACLPreparer(ctx context.Context, accountName, shareName string, acls []SignedIdentifier) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("query", "share"), + "comp": autorest.Encode("query", "acl"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + + input := setAcl{ + SignedIdentifiers: acls, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsPut(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers), + autorest.WithXML(&input)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// SetACLSender sends the SetACL request. The method will close the +// http.Response Body if it receives an error. +func (client Client) SetACLSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// SetACLResponder handles the response to the SetACL request. The method always +// closes the http.Response Body. +func (client Client) SetACLResponder(resp *http.Response) (result autorest.Response, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + result = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/client.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/client.go new file mode 100644 index 000000000000..4f3a6f9f99d0 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/client.go @@ -0,0 +1,25 @@ +package shares + +import ( + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" +) + +// Client is the base client for File Storage Shares. +type Client struct { + autorest.Client + BaseURI string +} + +// New creates an instance of the Client client. +func New() Client { + return NewWithEnvironment(azure.PublicCloud) +} + +// NewWithEnvironment creates an instance of the Client client. +func NewWithEnvironment(environment azure.Environment) Client { + return Client{ + Client: autorest.NewClientWithUserAgent(UserAgent()), + BaseURI: environment.StorageEndpointSuffix, + } +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/create.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/create.go new file mode 100644 index 000000000000..84fd40d3cf38 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/create.go @@ -0,0 +1,109 @@ +package shares + +import ( + "context" + "fmt" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" + "github.com/tombuildsstuff/giovanni/storage/internal/metadata" +) + +type CreateInput struct { + // Specifies the maximum size of the share, in gigabytes. + // Must be greater than 0, and less than or equal to 5TB (5120). + QuotaInGB int + + MetaData map[string]string +} + +// Create creates the specified Storage Share within the specified Storage Account +func (client Client) Create(ctx context.Context, accountName, shareName string, input CreateInput) (result autorest.Response, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "Create", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "Create", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "Create", "`shareName` must be a lower-cased string.") + } + if input.QuotaInGB <= 0 || input.QuotaInGB > 5120 { + return result, validation.NewError("shares.Client", "Create", "`input.QuotaInGB` must be greater than 0, and less than/equal to 5TB (5120 GB)") + } + if err := metadata.Validate(input.MetaData); err != nil { + return result, validation.NewError("shares.Client", "Create", fmt.Sprintf("`input.MetaData` is not valid: %s.", err)) + } + + req, err := client.CreatePreparer(ctx, accountName, shareName, input) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "Create", nil, "Failure preparing request") + return + } + + resp, err := client.CreateSender(req) + if err != nil { + result = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "Create", resp, "Failure sending request") + return + } + + result, err = client.CreateResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "Create", resp, "Failure responding to request") + return + } + + return +} + +// CreatePreparer prepares the Create request. +func (client Client) CreatePreparer(ctx context.Context, accountName, shareName string, input CreateInput) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("path", "share"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + "x-ms-share-quota": input.QuotaInGB, + } + + headers = metadata.SetIntoHeaders(headers, input.MetaData) + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsPut(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + 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 Client) CreateSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// CreateResponder handles the response to the Create request. The method always +// closes the http.Response Body. +func (client Client) CreateResponder(resp *http.Response) (result autorest.Response, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusCreated), + autorest.ByClosing()) + result = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/delete.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/delete.go new file mode 100644 index 000000000000..70ef985d23bb --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/delete.go @@ -0,0 +1,94 @@ +package shares + +import ( + "context" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" +) + +// Delete deletes the specified Storage Share from within a Storage Account +func (client Client) Delete(ctx context.Context, accountName, shareName string, deleteSnapshots bool) (result autorest.Response, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "Delete", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "Delete", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "Delete", "`shareName` must be a lower-cased string.") + } + + req, err := client.DeletePreparer(ctx, accountName, shareName, deleteSnapshots) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "Delete", nil, "Failure preparing request") + return + } + + resp, err := client.DeleteSender(req) + if err != nil { + result = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "Delete", resp, "Failure sending request") + return + } + + result, err = client.DeleteResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "Delete", resp, "Failure responding to request") + return + } + + return +} + +// DeletePreparer prepares the Delete request. +func (client Client) DeletePreparer(ctx context.Context, accountName, shareName string, deleteSnapshots bool) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("path", "share"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + + if deleteSnapshots { + headers["x-ms-delete-snapshots"] = "include" + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsDelete(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + 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.StatusAccepted), + autorest.ByClosing()) + result = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/metadata_get.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/metadata_get.go new file mode 100644 index 000000000000..9fa4d9f07ed8 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/metadata_get.go @@ -0,0 +1,102 @@ +package shares + +import ( + "context" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" + "github.com/tombuildsstuff/giovanni/storage/internal/metadata" +) + +type GetMetaDataResult struct { + autorest.Response + + MetaData map[string]string +} + +// GetMetaData returns the MetaData associated with the specified Storage Share +func (client Client) GetMetaData(ctx context.Context, accountName, shareName string) (result GetMetaDataResult, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "GetMetaData", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "GetMetaData", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "GetMetaData", "`shareName` must be a lower-cased string.") + } + + req, err := client.GetMetaDataPreparer(ctx, accountName, shareName) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetMetaData", nil, "Failure preparing request") + return + } + + resp, err := client.GetMetaDataSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "GetMetaData", resp, "Failure sending request") + return + } + + result, err = client.GetMetaDataResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetMetaData", resp, "Failure responding to request") + return + } + + return +} + +// GetMetaDataPreparer prepares the GetMetaData request. +func (client Client) GetMetaDataPreparer(ctx context.Context, accountName, shareName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("query", "share"), + "comp": autorest.Encode("query", "metadata"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsGet(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// GetMetaDataSender sends the GetMetaData request. The method will close the +// http.Response Body if it receives an error. +func (client Client) GetMetaDataSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// GetMetaDataResponder handles the response to the GetMetaData request. The method always +// closes the http.Response Body. +func (client Client) GetMetaDataResponder(resp *http.Response) (result GetMetaDataResult, err error) { + if resp.Header != nil { + result.MetaData = metadata.ParseFromHeaders(resp.Header) + } + + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/metadata_set.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/metadata_set.go new file mode 100644 index 000000000000..7e64e60aca15 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/metadata_set.go @@ -0,0 +1,97 @@ +package shares + +import ( + "context" + "fmt" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" + "github.com/tombuildsstuff/giovanni/storage/internal/metadata" +) + +// SetMetaData sets the MetaData on the specified Storage Share +func (client Client) SetMetaData(ctx context.Context, accountName, shareName string, metaData map[string]string) (result autorest.Response, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "SetMetaData", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "SetMetaData", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "SetMetaData", "`shareName` must be a lower-cased string.") + } + if err := metadata.Validate(metaData); err != nil { + return result, validation.NewError("shares.Client", "SetMetaData", fmt.Sprintf("`metadata` is not valid: %s.", err)) + } + + req, err := client.SetMetaDataPreparer(ctx, accountName, shareName, metaData) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "SetMetaData", nil, "Failure preparing request") + return + } + + resp, err := client.SetMetaDataSender(req) + if err != nil { + result = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "SetMetaData", resp, "Failure sending request") + return + } + + result, err = client.SetMetaDataResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "SetMetaData", resp, "Failure responding to request") + return + } + + return +} + +// SetMetaDataPreparer prepares the SetMetaData request. +func (client Client) SetMetaDataPreparer(ctx context.Context, accountName, shareName string, metaData map[string]string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("query", "share"), + "comp": autorest.Encode("query", "metadata"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + headers = metadata.SetIntoHeaders(headers, metaData) + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsPut(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// SetPropertiesSetMetaDataSender sends the SetMetaData request. The method will close the +// http.Response Body if it receives an error. +func (client Client) SetMetaDataSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// SetMetaDataResponder handles the response to the SetMetaData request. The method always +// closes the http.Response Body. +func (client Client) SetMetaDataResponder(resp *http.Response) (result autorest.Response, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + result = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/models.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/models.go new file mode 100644 index 000000000000..31ef7c204703 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/models.go @@ -0,0 +1,12 @@ +package shares + +type SignedIdentifier struct { + Id string `xml:"Id"` + AccessPolicy AccessPolicy `xml:"AccessPolicy"` +} + +type AccessPolicy struct { + Start string `xml:"Start"` + Expiry string `xml:"Expiry"` + Permission string `xml:"Permission"` +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/properties_get.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/properties_get.go new file mode 100644 index 000000000000..95fa58de2c8c --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/properties_get.go @@ -0,0 +1,113 @@ +package shares + +import ( + "context" + "fmt" + "net/http" + "strconv" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" + "github.com/tombuildsstuff/giovanni/storage/internal/metadata" +) + +type GetPropertiesResult struct { + autorest.Response + + MetaData map[string]string + ShareQuota int +} + +// GetProperties returns the properties about the specified Storage Share +func (client Client) GetProperties(ctx context.Context, accountName, shareName string) (result GetPropertiesResult, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "GetProperties", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "GetProperties", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "GetProperties", "`shareName` must be a lower-cased string.") + } + + req, err := client.GetPropertiesPreparer(ctx, accountName, shareName) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetProperties", nil, "Failure preparing request") + return + } + + resp, err := client.GetPropertiesSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "GetProperties", resp, "Failure sending request") + return + } + + result, err = client.GetPropertiesResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetProperties", resp, "Failure responding to request") + return + } + + return +} + +// GetPropertiesPreparer prepares the GetProperties request. +func (client Client) GetPropertiesPreparer(ctx context.Context, accountName, shareName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("query", "share"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsGet(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + 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 Client) GetPropertiesSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// GetPropertiesResponder handles the response to the GetProperties request. The method always +// closes the http.Response Body. +func (client Client) GetPropertiesResponder(resp *http.Response) (result GetPropertiesResult, err error) { + if resp.Header != nil { + result.MetaData = metadata.ParseFromHeaders(resp.Header) + + quotaRaw := resp.Header.Get("x-ms-share-quota") + if quotaRaw != "" { + quota, e := strconv.Atoi(quotaRaw) + if e != nil { + return result, fmt.Errorf("Error converting %q to an integer: %s", quotaRaw, err) + } + result.ShareQuota = quota + } + } + + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/properties_set.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/properties_set.go new file mode 100644 index 000000000000..4553e5ede777 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/properties_set.go @@ -0,0 +1,95 @@ +package shares + +import ( + "context" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" +) + +// SetProperties lets you update the Quota for the specified Storage Share +func (client Client) SetProperties(ctx context.Context, accountName, shareName string, newQuotaGB int) (result autorest.Response, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "SetProperties", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "SetProperties", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "SetProperties", "`shareName` must be a lower-cased string.") + } + if newQuotaGB <= 0 || newQuotaGB > 5120 { + return result, validation.NewError("shares.Client", "SetProperties", "`newQuotaGB` must be greater than 0, and less than/equal to 5TB (5120 GB)") + } + + req, err := client.SetPropertiesPreparer(ctx, accountName, shareName, newQuotaGB) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "SetProperties", nil, "Failure preparing request") + return + } + + resp, err := client.SetPropertiesSender(req) + if err != nil { + result = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "SetProperties", resp, "Failure sending request") + return + } + + result, err = client.SetPropertiesResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "SetProperties", resp, "Failure responding to request") + return + } + + return +} + +// SetPropertiesPreparer prepares the SetProperties request. +func (client Client) SetPropertiesPreparer(ctx context.Context, accountName, shareName string, quotaGB int) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("query", "share"), + "comp": autorest.Encode("query", "properties"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + "x-ms-share-quota": quotaGB, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsPut(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// SetPropertiesSender sends the SetProperties request. The method will close the +// http.Response Body if it receives an error. +func (client Client) SetPropertiesSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// SetPropertiesResponder handles the response to the SetProperties request. The method always +// closes the http.Response Body. +func (client Client) SetPropertiesResponder(resp *http.Response) (result autorest.Response, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + result = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/resource_id.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/resource_id.go new file mode 100644 index 000000000000..b6a83442abd2 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/resource_id.go @@ -0,0 +1,46 @@ +package shares + +import ( + "fmt" + "net/url" + "strings" + + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" +) + +// GetResourceID returns the Resource ID for the given File Share +// This can be useful when, for example, you're using this as a unique identifier +func (client Client) GetResourceID(accountName, shareName string) string { + domain := endpoints.GetFileEndpoint(client.BaseURI, accountName) + return fmt.Sprintf("%s/%s", domain, shareName) +} + +type ResourceID struct { + AccountName string + ShareName string +} + +// ParseResourceID parses the specified Resource ID and returns an object +// which can be used to interact with the Storage Shares SDK +func ParseResourceID(id string) (*ResourceID, error) { + // example: https://foo.file.core.windows.net/Bar + if id == "" { + return nil, fmt.Errorf("`id` was empty") + } + + uri, err := url.Parse(id) + if err != nil { + return nil, fmt.Errorf("Error parsing ID as a URL: %s", err) + } + + accountName, err := endpoints.GetAccountNameFromEndpoint(uri.Host) + if err != nil { + return nil, fmt.Errorf("Error parsing Account Name: %s", err) + } + + shareName := strings.TrimPrefix(uri.Path, "/") + return &ResourceID{ + AccountName: *accountName, + ShareName: shareName, + }, nil +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/snapshot_create.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/snapshot_create.go new file mode 100644 index 000000000000..0ded38b1975a --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/snapshot_create.go @@ -0,0 +1,115 @@ +package shares + +import ( + "context" + "fmt" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" + "github.com/tombuildsstuff/giovanni/storage/internal/metadata" +) + +type CreateSnapshotInput struct { + MetaData map[string]string +} + +type CreateSnapshotResult struct { + autorest.Response + + // This header is a DateTime value that uniquely identifies the share snapshot. + // The value of this header may be used in subsequent requests to access the share snapshot. + // This value is opaque. + SnapshotDateTime string +} + +// CreateSnapshot creates a read-only snapshot of the share +// A share can support creation of 200 share snapshots. Attempting to create more than 200 share snapshots fails with 409 (Conflict). +// Attempting to create a share snapshot while a previous Snapshot Share operation is in progress fails with 409 (Conflict). +func (client Client) CreateSnapshot(ctx context.Context, accountName, shareName string, input CreateSnapshotInput) (result CreateSnapshotResult, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "CreateSnapshot", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "CreateSnapshot", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "CreateSnapshot", "`shareName` must be a lower-cased string.") + } + if err := metadata.Validate(input.MetaData); err != nil { + return result, validation.NewError("shares.Client", "CreateSnapshot", fmt.Sprintf("`input.MetaData` is not valid: %s.", err)) + } + + req, err := client.CreateSnapshotPreparer(ctx, accountName, shareName, input) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "CreateSnapshot", nil, "Failure preparing request") + return + } + + resp, err := client.CreateSnapshotSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "CreateSnapshot", resp, "Failure sending request") + return + } + + result, err = client.CreateSnapshotResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "CreateSnapshot", resp, "Failure responding to request") + return + } + + return +} + +// CreateSnapshotPreparer prepares the CreateSnapshot request. +func (client Client) CreateSnapshotPreparer(ctx context.Context, accountName, shareName string, input CreateSnapshotInput) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "comp": autorest.Encode("query", "snapshot"), + "restype": autorest.Encode("query", "share"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + + headers = metadata.SetIntoHeaders(headers, input.MetaData) + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsPut(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// CreateSnapshotSender sends the CreateSnapshot request. The method will close the +// http.Response Body if it receives an error. +func (client Client) CreateSnapshotSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// CreateSnapshotResponder handles the response to the CreateSnapshot request. The method always +// closes the http.Response Body. +func (client Client) CreateSnapshotResponder(resp *http.Response) (result CreateSnapshotResult, err error) { + result.SnapshotDateTime = resp.Header.Get("x-ms-snapshot") + + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusCreated), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/snapshot_delete.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/snapshot_delete.go new file mode 100644 index 000000000000..1f5d665cb104 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/snapshot_delete.go @@ -0,0 +1,94 @@ +package shares + +import ( + "context" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" +) + +// DeleteSnapshot deletes the specified Snapshot of a Storage Share +func (client Client) DeleteSnapshot(ctx context.Context, accountName, shareName string, shareSnapshot string) (result autorest.Response, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "DeleteSnapshot", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "DeleteSnapshot", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "DeleteSnapshot", "`shareName` must be a lower-cased string.") + } + if shareSnapshot == "" { + return result, validation.NewError("shares.Client", "DeleteSnapshot", "`shareSnapshot` cannot be an empty string.") + } + + req, err := client.DeleteSnapshotPreparer(ctx, accountName, shareName, shareSnapshot) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "DeleteSnapshot", nil, "Failure preparing request") + return + } + + resp, err := client.DeleteSnapshotSender(req) + if err != nil { + result = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "DeleteSnapshot", resp, "Failure sending request") + return + } + + result, err = client.DeleteSnapshotResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "DeleteSnapshot", resp, "Failure responding to request") + return + } + + return +} + +// DeleteSnapshotPreparer prepares the DeleteSnapshot request. +func (client Client) DeleteSnapshotPreparer(ctx context.Context, accountName, shareName string, shareSnapshot string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("path", "share"), + "sharesnapshot": autorest.Encode("query", shareSnapshot), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsDelete(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// DeleteSnapshotSender sends the DeleteSnapshot request. The method will close the +// http.Response Body if it receives an error. +func (client Client) DeleteSnapshotSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// DeleteSnapshotResponder handles the response to the DeleteSnapshot request. The method always +// closes the http.Response Body. +func (client Client) DeleteSnapshotResponder(resp *http.Response) (result autorest.Response, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusAccepted), + autorest.ByClosing()) + result = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/snapshot_get.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/snapshot_get.go new file mode 100644 index 000000000000..2cf5f16f618e --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/snapshot_get.go @@ -0,0 +1,105 @@ +package shares + +import ( + "context" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" + "github.com/tombuildsstuff/giovanni/storage/internal/metadata" +) + +type GetSnapshotPropertiesResult struct { + autorest.Response + + MetaData map[string]string +} + +// GetSnapshot gets information about the specified Snapshot of the specified Storage Share +func (client Client) GetSnapshot(ctx context.Context, accountName, shareName, snapshotShare string) (result GetSnapshotPropertiesResult, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "GetSnapshot", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "GetSnapshot", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "GetSnapshot", "`shareName` must be a lower-cased string.") + } + if snapshotShare == "" { + return result, validation.NewError("shares.Client", "GetSnapshot", "`snapshotShare` cannot be an empty string.") + } + + req, err := client.GetSnapshotPreparer(ctx, accountName, shareName, snapshotShare) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetSnapshot", nil, "Failure preparing request") + return + } + + resp, err := client.GetSnapshotSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "GetSnapshot", resp, "Failure sending request") + return + } + + result, err = client.GetSnapshotResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetSnapshot", resp, "Failure responding to request") + return + } + + return +} + +// GetSnapshotPreparer prepares the GetSnapshot request. +func (client Client) GetSnapshotPreparer(ctx context.Context, accountName, shareName, snapshotShare string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("query", "share"), + "snapshot": autorest.Encode("query", snapshotShare), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsGet(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// GetSnapshotSender sends the GetSnapshot request. The method will close the +// http.Response Body if it receives an error. +func (client Client) GetSnapshotSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// GetSnapshotResponder handles the response to the GetSnapshot request. The method always +// closes the http.Response Body. +func (client Client) GetSnapshotResponder(resp *http.Response) (result GetSnapshotPropertiesResult, err error) { + if resp.Header != nil { + result.MetaData = metadata.ParseFromHeaders(resp.Header) + } + + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/stats.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/stats.go new file mode 100644 index 000000000000..3539eccbcd0e --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/stats.go @@ -0,0 +1,100 @@ +package shares + +import ( + "context" + "net/http" + "strings" + + "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/validation" + "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" +) + +type GetStatsResult struct { + autorest.Response + + // The approximate size of the data stored on the share. + // Note that this value may not include all recently created or recently resized files. + ShareUsageBytes int64 `xml:"ShareUsageBytes"` +} + +// GetStats returns information about the specified Storage Share +func (client Client) GetStats(ctx context.Context, accountName, shareName string) (result GetStatsResult, err error) { + if accountName == "" { + return result, validation.NewError("shares.Client", "GetStats", "`accountName` cannot be an empty string.") + } + if shareName == "" { + return result, validation.NewError("shares.Client", "GetStats", "`shareName` cannot be an empty string.") + } + if strings.ToLower(shareName) != shareName { + return result, validation.NewError("shares.Client", "GetStats", "`shareName` must be a lower-cased string.") + } + + req, err := client.GetStatsPreparer(ctx, accountName, shareName) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetStats", nil, "Failure preparing request") + return + } + + resp, err := client.GetStatsSender(req) + if err != nil { + result.Response = autorest.Response{Response: resp} + err = autorest.NewErrorWithError(err, "shares.Client", "GetStats", resp, "Failure sending request") + return + } + + result, err = client.GetStatsResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "shares.Client", "GetStats", resp, "Failure responding to request") + return + } + + return +} + +// GetStatsPreparer prepares the GetStats request. +func (client Client) GetStatsPreparer(ctx context.Context, accountName, shareName string) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "shareName": autorest.Encode("path", shareName), + } + + queryParameters := map[string]interface{}{ + "restype": autorest.Encode("query", "share"), + "comp": autorest.Encode("query", "stats"), + } + + headers := map[string]interface{}{ + "x-ms-version": APIVersion, + } + + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/xml; charset=utf-8"), + autorest.AsGet(), + autorest.WithBaseURL(endpoints.GetFileEndpoint(client.BaseURI, accountName)), + autorest.WithPathParameters("/{shareName}", pathParameters), + autorest.WithQueryParameters(queryParameters), + autorest.WithHeaders(headers)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +// GetStatsSender sends the GetStats request. The method will close the +// http.Response Body if it receives an error. +func (client Client) GetStatsSender(req *http.Request) (*http.Response, error) { + return autorest.SendWithSender(client, req, + azure.DoRetryWithRegistration(client.Client)) +} + +// GetStatsResponder handles the response to the GetStats request. The method always +// closes the http.Response Body. +func (client Client) GetStatsResponder(resp *http.Response) (result GetStatsResult, err error) { + err = autorest.Respond( + resp, + client.ByInspecting(), + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingXML(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + + return +} diff --git a/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/version.go b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/version.go new file mode 100644 index 000000000000..9249149998c2 --- /dev/null +++ b/vendor/github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares/version.go @@ -0,0 +1,14 @@ +package shares + +import ( + "fmt" + + "github.com/tombuildsstuff/giovanni/version" +) + +// APIVersion is the version of the API used for all Storage API Operations +const APIVersion = "2018-11-09" + +func UserAgent() string { + return fmt.Sprintf("tombuildsstuff/giovanni/%s storage/%s", version.Number, APIVersion) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 0939952904c2..cea64d40967f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -338,8 +338,9 @@ github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/p github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/tf github.com/terraform-providers/terraform-provider-azuread/azuread/helpers/validate github.com/terraform-providers/terraform-provider-azuread/version -# github.com/tombuildsstuff/giovanni v0.2.0 +# github.com/tombuildsstuff/giovanni v0.2.1 github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/directories +github.com/tombuildsstuff/giovanni/storage/2018-11-09/file/shares github.com/tombuildsstuff/giovanni/storage/internal/endpoints github.com/tombuildsstuff/giovanni/storage/internal/metadata github.com/tombuildsstuff/giovanni/version diff --git a/website/docs/guides/2.0-upgrade-guide.html.markdown b/website/docs/guides/2.0-upgrade-guide.html.markdown index 05ce2d46324c..b6a727e3c3d3 100644 --- a/website/docs/guides/2.0-upgrade-guide.html.markdown +++ b/website/docs/guides/2.0-upgrade-guide.html.markdown @@ -339,6 +339,10 @@ The deprecated `enable_filtering_messages_before_publishing` field will be remov The deprecated `account_type` field will be removed. This has been split into the fields `account_tier` and `account_replication_type`. +### Resource: `azurerm_storage_share` + +The deprecated `resource_group_name` field will be removed as this field is no longer used. + ### Resource: `azurerm_subnet` The deprecated field `network_security_group_id` will be removed. This has been replaced by the `azurerm_subnet_network_security_group_association` resource. diff --git a/website/docs/r/storage_share.html.markdown b/website/docs/r/storage_share.html.markdown index c13c8b328b3b..2c33ad83764d 100644 --- a/website/docs/r/storage_share.html.markdown +++ b/website/docs/r/storage_share.html.markdown @@ -3,12 +3,12 @@ layout: "azurerm" page_title: "Azure Resource Manager: azurerm_storage_share" sidebar_current: "docs-azurerm-resource-storage-share-x" description: |- - Manages an Azure Storage Share. + Manages a File Share within Azure Storage. --- # azurerm_storage_share -Manage an Azure Storage File Share. +Manages a File Share within Azure Storage. ## Example Usage @@ -27,12 +27,9 @@ resource "azurerm_storage_account" "test" { } resource "azurerm_storage_share" "testshare" { - name = "sharename" - - resource_group_name = "${azurerm_resource_group.test.name}" + name = "sharename" storage_account_name = "${azurerm_storage_account.test.name}" - - quota = 50 + quota = 50 } ``` @@ -42,12 +39,12 @@ The following arguments are supported: * `name` - (Required) The name of the share. Must be unique within the storage account where the share is located. -* `resource_group_name` - (Required) The name of the resource group in which to - create the share. Changing this forces a new resource to be created. - * `storage_account_name` - (Required) Specifies the storage account in which to create the share. Changing this forces a new resource to be created. +* `resource_group_name` - (Optional / **Deprecated**) The name of the resource group in which to + create the share. Changing this forces a new resource to be created. + * `quota` - (Optional) The maximum size of the share, in gigabytes. Must be greater than 0, and less than or equal to 5 TB (5120 GB). Default is 5120. @@ -55,15 +52,13 @@ The following arguments are supported: The following attributes are exported in addition to the arguments listed above: -* `id` - The storage share Resource ID. -* `url` - The URL of the share +* `id` - The ID of the File Share. +* `url` - The URL of the File Share ## Import Storage Shares can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_storage_share.testShare storageShareName/resourceGroupName/storageAccoutName +terraform import azurerm_storage_share.testShare https://account1.file.core.windows.net/share1 ``` - --> **NOTE:** This identifier is unique to Terraform diff --git a/website/docs/r/storage_share_directory.html.markdown b/website/docs/r/storage_share_directory.html.markdown index 7647661cbf39..89c62913dfc0 100644 --- a/website/docs/r/storage_share_directory.html.markdown +++ b/website/docs/r/storage_share_directory.html.markdown @@ -28,10 +28,15 @@ resource "azurerm_storage_account" "test" { resource "azurerm_storage_share" "test" { name = "sharename" - resource_group_name = "${azurerm_resource_group.test.name}" storage_account_name = "${azurerm_storage_account.test.name}" quota = 50 } + +resource "azurerm_storage_share_directory" "test" { + name = "example-" + share_name = "${azurerm_storage_share.test.name}" + storage_account_name = "${azurerm_storage_account.test.name}" +} ``` ## Argument Reference