From 0cb75e6b829c8a8967b52a525133c4bb86d9b102 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Thu, 24 May 2018 18:21:33 -0700 Subject: [PATCH 1/6] Add 'content_type' to blob. --- azurerm/resource_arm_storage_blob.go | 61 ++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/azurerm/resource_arm_storage_blob.go b/azurerm/resource_arm_storage_blob.go index dffc59b68496..b7b498cd0249 100644 --- a/azurerm/resource_arm_storage_blob.go +++ b/azurerm/resource_arm_storage_blob.go @@ -20,6 +20,7 @@ func resourceArmStorageBlob() *schema.Resource { return &schema.Resource{ Create: resourceArmStorageBlobCreate, Read: resourceArmStorageBlobRead, + Update: resourceArmStorageBlobUpdate, Exists: resourceArmStorageBlobExists, Delete: resourceArmStorageBlobDelete, @@ -53,6 +54,12 @@ func resourceArmStorageBlob() *schema.Resource { Default: 0, ValidateFunc: validateArmStorageBlobSize, }, + "content_type": { + Type: schema.TypeString, + Optional: true, + Default: "application/octet-stream", + ConflictsWith: []string{"source_uri"}, + }, "source": { Type: schema.TypeString, Optional: true, @@ -149,6 +156,7 @@ func resourceArmStorageBlobCreate(d *schema.ResourceData, meta interface{}) erro blobType := d.Get("type").(string) cont := d.Get("storage_container_name").(string) sourceUri := d.Get("source_uri").(string) + contentType := d.Get("content_type").(string) log.Printf("[INFO] Creating blob %q in storage account %q", name, storageAccountName) if sourceUri != "" { @@ -174,7 +182,7 @@ func resourceArmStorageBlobCreate(d *schema.ResourceData, meta interface{}) erro if source != "" { parallelism := d.Get("parallelism").(int) attempts := d.Get("attempts").(int) - if err := resourceArmStorageBlobBlockUploadFromSource(cont, name, source, blobClient, parallelism, attempts); err != nil { + if err := resourceArmStorageBlobBlockUploadFromSource(cont, name, source, contentType, blobClient, parallelism, attempts); err != nil { return fmt.Errorf("Error creating storage blob on Azure: %s", err) } } @@ -183,7 +191,7 @@ func resourceArmStorageBlobCreate(d *schema.ResourceData, meta interface{}) erro if source != "" { parallelism := d.Get("parallelism").(int) attempts := d.Get("attempts").(int) - if err := resourceArmStorageBlobPageUploadFromSource(cont, name, source, blobClient, parallelism, attempts); err != nil { + if err := resourceArmStorageBlobPageUploadFromSource(cont, name, source, contentType, blobClient, parallelism, attempts); err != nil { return fmt.Errorf("Error creating storage blob on Azure: %s", err) } } else { @@ -193,6 +201,7 @@ func resourceArmStorageBlobCreate(d *schema.ResourceData, meta interface{}) erro container := blobClient.GetContainerReference(cont) blob := container.GetBlobReference(name) blob.Properties.ContentLength = size + blob.Properties.ContentType = contentType err := blob.PutPageBlob(options) if err != nil { return fmt.Errorf("Error creating storage blob on Azure: %s", err) @@ -210,7 +219,7 @@ type resourceArmStorageBlobPage struct { section *io.SectionReader } -func resourceArmStorageBlobPageUploadFromSource(container, name, source string, client *storage.BlobStorageClient, parallelism, attempts int) error { +func resourceArmStorageBlobPageUploadFromSource(container, name, source, contentType string, client *storage.BlobStorageClient, parallelism, attempts int) error { workerCount := parallelism * runtime.NumCPU() file, err := os.Open(source) @@ -228,6 +237,7 @@ func resourceArmStorageBlobPageUploadFromSource(container, name, source string, containerRef := client.GetContainerReference(container) blob := containerRef.GetBlobReference(name) blob.Properties.ContentLength = blobSize + blob.Properties.ContentType = contentType err = blob.PutPageBlob(options) if err != nil { return fmt.Errorf("Error creating storage blob on Azure: %s", err) @@ -387,7 +397,7 @@ type resourceArmStorageBlobBlock struct { id string } -func resourceArmStorageBlobBlockUploadFromSource(container, name, source string, client *storage.BlobStorageClient, parallelism, attempts int) error { +func resourceArmStorageBlobBlockUploadFromSource(container, name, source, contentType string, client *storage.BlobStorageClient, parallelism, attempts int) error { workerCount := parallelism * runtime.NumCPU() file, err := os.Open(source) @@ -432,6 +442,7 @@ func resourceArmStorageBlobBlockUploadFromSource(container, name, source string, containerReference := client.GetContainerReference(container) blobReference := containerReference.GetBlobReference(name) + blobReference.Properties.ContentType = contentType options := &storage.PutBlockListOptions{} err = blobReference.PutBlockList(blockList, options) if err != nil { @@ -524,6 +535,39 @@ func resourceArmStorageBlobBlockUploadWorker(ctx resourceArmStorageBlobBlockUplo } } +func resourceArmStorageBlobUpdate(d *schema.ResourceData, meta interface{}) error { + armClient := meta.(*ArmClient) + ctx := armClient.StopContext + + resourceGroupName := d.Get("resource_group_name").(string) + storageAccountName := d.Get("storage_account_name").(string) + + blobClient, accountExists, err := armClient.getBlobStorageClientForStorageAccount(ctx, resourceGroupName, storageAccountName) + if err != nil { + return fmt.Errorf("Error getting storage account %s: %+v", storageAccountName, err) + } + if !accountExists { + return fmt.Errorf("Storage account %s not found", storageAccountName) + } + + name := d.Get("name").(string) + storageContainerName := d.Get("storage_container_name").(string) + + container := blobClient.GetContainerReference(storageContainerName) + blob := container.GetBlobReference(name) + + if d.HasChange("content_type") { + blob.Properties.ContentType = d.Get("content_type").(string) + } + + err = blob.SetProperties(nil) + if err != nil { + return fmt.Errorf("Error setting properties of blob %s (container %s, storage account %s): %+v", name, storageContainerName, storageAccountName, err) + } + + return nil +} + func resourceArmStorageBlobRead(d *schema.ResourceData, meta interface{}) error { armClient := meta.(*ArmClient) ctx := armClient.StopContext @@ -556,6 +600,15 @@ func resourceArmStorageBlobRead(d *schema.ResourceData, meta interface{}) error container := blobClient.GetContainerReference(storageContainerName) blob := container.GetBlobReference(name) + + err = blob.GetProperties(nil) + if err != nil { + return fmt.Errorf("Error getting properties of blob %s (container %s, storage account %s): %+v", name, storageContainerName, storageAccountName, err) + } + if blob.Properties.ContentType != "" { + d.Set("content_type", blob.Properties.ContentType) + } + url := blob.GetURL() if url == "" { log.Printf("[INFO] URL for %q is empty", name) From 57cfc2e48d0c1ba51c1dac0006140b09056b29d7 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Fri, 25 May 2018 18:45:43 -0700 Subject: [PATCH 2/6] Add test case for the new content type in blob. --- azurerm/resource_arm_storage_blob_test.go | 87 +++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/azurerm/resource_arm_storage_blob_test.go b/azurerm/resource_arm_storage_blob_test.go index 2fea86ff4850..345c8fa6fc29 100644 --- a/azurerm/resource_arm_storage_blob_test.go +++ b/azurerm/resource_arm_storage_blob_test.go @@ -314,6 +314,51 @@ func TestAccAzureRMStorageBlob_source_uri(t *testing.T) { }) } +func TestAccAzureRMStorageBlobBlock_blockContentType(t *testing.T) { + resourceName := "azurerm_storage_blob.source" + ri := acctest.RandInt() + rs1 := strings.ToLower(acctest.RandString(11)) + sourceBlob, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("Failed to create local source blob file") + } + + _, err = io.CopyN(sourceBlob, rand.Reader, 25*1024*1024) + if err != nil { + t.Fatalf("Failed to write random test to source blob") + } + + err = sourceBlob.Close() + if err != nil { + t.Fatalf("Failed to close source blob") + } + + config := testAccAzureRMStorageBlobPage_blockContentType(ri, rs1, sourceBlob.Name(), testLocation(), "text/plain") + updateConfig := testAccAzureRMStorageBlobPage_blockContentType(ri, rs1, sourceBlob.Name(), testLocation(), "text/vnd.terraform.acctest.tmpfile") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMStorageBlobDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMStorageBlobExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "content_type", "text/plain"), + ), + }, + { + Config: updateConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMStorageBlobExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "content_type", "text/vnd.terraform.acctest.tmpfile"), + ), + }, + }, + }) +} + func testCheckAzureRMStorageBlobExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -666,3 +711,45 @@ resource "azurerm_storage_blob" "destination" { } `, rInt, location, rString, sourceBlobName) } + +func testAccAzureRMStorageBlobPage_blockContentType(rInt int, rString, sourceBlobName, location, contentType string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_storage_account" "source" { + name = "acctestacc%s" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" + + tags { + environment = "staging" + } +} + +resource "azurerm_storage_container" "source" { + name = "source" + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_name = "${azurerm_storage_account.source.name}" + container_access_type = "blob" +} + +resource "azurerm_storage_blob" "source" { + name = "source.vhd" + + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_name = "${azurerm_storage_account.source.name}" + storage_container_name = "${azurerm_storage_container.source.name}" + + type = "page" + source = "%s" + content_type = "%s" + parallelism = 3 + attempts = 3 +} +`, rInt, location, rString, sourceBlobName, contentType) +} From da7b3a5e1b2de8ab4838ab4f89f36ff1918dc0a6 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Fri, 25 May 2018 18:50:25 -0700 Subject: [PATCH 3/6] Remove the unneeded check. --- azurerm/resource_arm_storage_blob.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/azurerm/resource_arm_storage_blob.go b/azurerm/resource_arm_storage_blob.go index b7b498cd0249..47a7e28af916 100644 --- a/azurerm/resource_arm_storage_blob.go +++ b/azurerm/resource_arm_storage_blob.go @@ -605,9 +605,7 @@ func resourceArmStorageBlobRead(d *schema.ResourceData, meta interface{}) error if err != nil { return fmt.Errorf("Error getting properties of blob %s (container %s, storage account %s): %+v", name, storageContainerName, storageAccountName, err) } - if blob.Properties.ContentType != "" { - d.Set("content_type", blob.Properties.ContentType) - } + d.Set("content_type", blob.Properties.ContentType) url := blob.GetURL() if url == "" { From 7e6daf73dd65a4988abf42ab647abebfa7f7349a Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Fri, 1 Jun 2018 15:25:35 -0700 Subject: [PATCH 4/6] Fix coding styles according to the reviews. --- azurerm/resource_arm_storage_blob.go | 8 +++++--- azurerm/resource_arm_storage_blob_test.go | 6 +++--- website/docs/r/storage_blob.html.markdown | 2 ++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/azurerm/resource_arm_storage_blob.go b/azurerm/resource_arm_storage_blob.go index 47a7e28af916..ca40247cae1f 100644 --- a/azurerm/resource_arm_storage_blob.go +++ b/azurerm/resource_arm_storage_blob.go @@ -547,7 +547,7 @@ func resourceArmStorageBlobUpdate(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("Error getting storage account %s: %+v", storageAccountName, err) } if !accountExists { - return fmt.Errorf("Storage account %s not found", storageAccountName) + return fmt.Errorf("Storage account %s not found in resource group %s", storageAccountName, resourceGroupName) } name := d.Get("name").(string) @@ -560,7 +560,8 @@ func resourceArmStorageBlobUpdate(d *schema.ResourceData, meta interface{}) erro blob.Properties.ContentType = d.Get("content_type").(string) } - err = blob.SetProperties(nil) + options := &storage.SetBlobPropertiesOptions{} + err = blob.SetProperties(options) if err != nil { return fmt.Errorf("Error setting properties of blob %s (container %s, storage account %s): %+v", name, storageContainerName, storageAccountName, err) } @@ -601,7 +602,8 @@ func resourceArmStorageBlobRead(d *schema.ResourceData, meta interface{}) error container := blobClient.GetContainerReference(storageContainerName) blob := container.GetBlobReference(name) - err = blob.GetProperties(nil) + options := &storage.GetBlobPropertiesOptions{} + err = blob.GetProperties(options) if err != nil { return fmt.Errorf("Error getting properties of blob %s (container %s, storage account %s): %+v", name, storageContainerName, storageAccountName, err) } diff --git a/azurerm/resource_arm_storage_blob_test.go b/azurerm/resource_arm_storage_blob_test.go index 345c8fa6fc29..116a70fa7cec 100644 --- a/azurerm/resource_arm_storage_blob_test.go +++ b/azurerm/resource_arm_storage_blob_test.go @@ -333,8 +333,8 @@ func TestAccAzureRMStorageBlobBlock_blockContentType(t *testing.T) { t.Fatalf("Failed to close source blob") } - config := testAccAzureRMStorageBlobPage_blockContentType(ri, rs1, sourceBlob.Name(), testLocation(), "text/plain") - updateConfig := testAccAzureRMStorageBlobPage_blockContentType(ri, rs1, sourceBlob.Name(), testLocation(), "text/vnd.terraform.acctest.tmpfile") + config := testAccAzureRMStorageBlobPage_blockContentType(ri, rs1, testLocation(), sourceBlob.Name(), "text/plain") + updateConfig := testAccAzureRMStorageBlobPage_blockContentType(ri, rs1, testLocation(), sourceBlob.Name(), "text/vnd.terraform.acctest.tmpfile") resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -712,7 +712,7 @@ resource "azurerm_storage_blob" "destination" { `, rInt, location, rString, sourceBlobName) } -func testAccAzureRMStorageBlobPage_blockContentType(rInt int, rString, sourceBlobName, location, contentType string) string { +func testAccAzureRMStorageBlobPage_blockContentType(rInt int, rString, location string, sourceBlobName, contentType string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" diff --git a/website/docs/r/storage_blob.html.markdown b/website/docs/r/storage_blob.html.markdown index 5e6f7d382153..fcb9a16f67d8 100644 --- a/website/docs/r/storage_blob.html.markdown +++ b/website/docs/r/storage_blob.html.markdown @@ -64,6 +64,8 @@ The following arguments are supported: * `size` - (Optional) Used only for `page` blobs to specify the size in bytes of the blob to be created. Must be a multiple of 512. Defaults to 0. +* `content_type` - (Optional) The content type of the storage blob. Cannot be defined if `source_uri` is defined. Defaults to `application/octet-stream`. + * `source` - (Optional) An absolute path to a file on the local system. Cannot be defined if `source_uri` is defined. * `source_uri` - (Optional) The URI of an existing blob, or a file in the Azure File service, to use as the source contents From 86f17b74bf580bb83988e0816a68a0df51975214 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Fri, 1 Jun 2018 18:47:00 -0700 Subject: [PATCH 5/6] Move location parameter in test case. --- azurerm/resource_arm_storage_blob_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_storage_blob_test.go b/azurerm/resource_arm_storage_blob_test.go index 116a70fa7cec..81843ee4d698 100644 --- a/azurerm/resource_arm_storage_blob_test.go +++ b/azurerm/resource_arm_storage_blob_test.go @@ -203,7 +203,7 @@ func TestAccAzureRMStorageBlobBlock_source(t *testing.T) { t.Fatalf("Failed to close source blob") } - config := testAccAzureRMStorageBlobBlock_source(ri, rs1, sourceBlob.Name(), testLocation()) + config := testAccAzureRMStorageBlobBlock_source(ri, rs1, testLocation(), sourceBlob.Name()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -581,7 +581,7 @@ resource "azurerm_storage_blob" "test" { `, rInt, location, rString) } -func testAccAzureRMStorageBlobBlock_source(rInt int, rString string, sourceBlobName string, location string) string { +func testAccAzureRMStorageBlobBlock_source(rInt int, rString string, location string, sourceBlobName string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" From 96d8258733fc29a3192287f24380f1a6bf34c174 Mon Sep 17 00:00:00 2001 From: Junyi Yi Date: Fri, 1 Jun 2018 19:24:50 -0700 Subject: [PATCH 6/6] Revert "Move location parameter in test case." This reverts commit 86f17b74bf580bb83988e0816a68a0df51975214. --- azurerm/resource_arm_storage_blob_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_storage_blob_test.go b/azurerm/resource_arm_storage_blob_test.go index 81843ee4d698..116a70fa7cec 100644 --- a/azurerm/resource_arm_storage_blob_test.go +++ b/azurerm/resource_arm_storage_blob_test.go @@ -203,7 +203,7 @@ func TestAccAzureRMStorageBlobBlock_source(t *testing.T) { t.Fatalf("Failed to close source blob") } - config := testAccAzureRMStorageBlobBlock_source(ri, rs1, testLocation(), sourceBlob.Name()) + config := testAccAzureRMStorageBlobBlock_source(ri, rs1, sourceBlob.Name(), testLocation()) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -581,7 +581,7 @@ resource "azurerm_storage_blob" "test" { `, rInt, location, rString) } -func testAccAzureRMStorageBlobBlock_source(rInt int, rString string, location string, sourceBlobName string) string { +func testAccAzureRMStorageBlobBlock_source(rInt int, rString string, sourceBlobName string, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d"