Skip to content

Commit ec42a98

Browse files
davewalterstack72
authored andcommitted
Azure blob contents can be copied from an existing blob (hashicorp#8126)
- adds "source_uri" field - "source_uri" expects the URI to an existing blob that you have access to - it can be in a different storage account, or in the Azure File service - the docs have been updated to reflect the change Signed-off-by: Dan Wendorf <dwendorf@pivotal.io>
1 parent 598b940 commit ec42a98

3 files changed

Lines changed: 129 additions & 28 deletions

File tree

builtin/providers/azurerm/resource_arm_storage_blob.go

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func resourceArmStorageBlob() *schema.Resource {
4646
},
4747
"type": {
4848
Type: schema.TypeString,
49-
Required: true,
49+
Optional: true,
5050
ForceNew: true,
5151
ValidateFunc: validateArmStorageBlobType,
5252
},
@@ -58,9 +58,16 @@ func resourceArmStorageBlob() *schema.Resource {
5858
ValidateFunc: validateArmStorageBlobSize,
5959
},
6060
"source": {
61-
Type: schema.TypeString,
62-
Optional: true,
63-
ForceNew: true,
61+
Type: schema.TypeString,
62+
Optional: true,
63+
ForceNew: true,
64+
ConflictsWith: []string{"source_uri"},
65+
},
66+
"source_uri": {
67+
Type: schema.TypeString,
68+
Optional: true,
69+
ForceNew: true,
70+
ConflictsWith: []string{"source"},
6471
},
6572
"url": {
6673
Type: schema.TypeString,
@@ -144,34 +151,41 @@ func resourceArmStorageBlobCreate(d *schema.ResourceData, meta interface{}) erro
144151
name := d.Get("name").(string)
145152
blobType := d.Get("type").(string)
146153
cont := d.Get("storage_container_name").(string)
154+
sourceUri := d.Get("source_uri").(string)
147155

148156
log.Printf("[INFO] Creating blob %q in storage account %q", name, storageAccountName)
149-
switch strings.ToLower(blobType) {
150-
case "block":
151-
if err := blobClient.CreateBlockBlob(cont, name); err != nil {
157+
if sourceUri != "" {
158+
if err := blobClient.CopyBlob(cont, name, sourceUri); err != nil {
152159
return fmt.Errorf("Error creating storage blob on Azure: %s", err)
153160
}
154-
155-
source := d.Get("source").(string)
156-
if source != "" {
157-
parallelism := d.Get("parallelism").(int)
158-
attempts := d.Get("attempts").(int)
159-
if err := resourceArmStorageBlobBlockUploadFromSource(cont, name, source, blobClient, parallelism, attempts); err != nil {
161+
} else {
162+
switch strings.ToLower(blobType) {
163+
case "block":
164+
if err := blobClient.CreateBlockBlob(cont, name); err != nil {
160165
return fmt.Errorf("Error creating storage blob on Azure: %s", err)
161166
}
162-
}
163-
case "page":
164-
source := d.Get("source").(string)
165-
if source != "" {
166-
parallelism := d.Get("parallelism").(int)
167-
attempts := d.Get("attempts").(int)
168-
if err := resourceArmStorageBlobPageUploadFromSource(cont, name, source, blobClient, parallelism, attempts); err != nil {
169-
return fmt.Errorf("Error creating storage blob on Azure: %s", err)
167+
168+
source := d.Get("source").(string)
169+
if source != "" {
170+
parallelism := d.Get("parallelism").(int)
171+
attempts := d.Get("attempts").(int)
172+
if err := resourceArmStorageBlobBlockUploadFromSource(cont, name, source, blobClient, parallelism, attempts); err != nil {
173+
return fmt.Errorf("Error creating storage blob on Azure: %s", err)
174+
}
170175
}
171-
} else {
172-
size := int64(d.Get("size").(int))
173-
if err := blobClient.PutPageBlob(cont, name, size, map[string]string{}); err != nil {
174-
return fmt.Errorf("Error creating storage blob on Azure: %s", err)
176+
case "page":
177+
source := d.Get("source").(string)
178+
if source != "" {
179+
parallelism := d.Get("parallelism").(int)
180+
attempts := d.Get("attempts").(int)
181+
if err := resourceArmStorageBlobPageUploadFromSource(cont, name, source, blobClient, parallelism, attempts); err != nil {
182+
return fmt.Errorf("Error creating storage blob on Azure: %s", err)
183+
}
184+
} else {
185+
size := int64(d.Get("size").(int))
186+
if err := blobClient.PutPageBlob(cont, name, size, map[string]string{}); err != nil {
187+
return fmt.Errorf("Error creating storage blob on Azure: %s", err)
188+
}
175189
}
176190
}
177191
}

builtin/providers/azurerm/resource_arm_storage_blob_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,41 @@ func TestAccAzureRMStorageBlobPage_source(t *testing.T) {
257257
})
258258
}
259259

260+
func TestAccAzureRMStorageBlob_source_uri(t *testing.T) {
261+
ri := acctest.RandInt()
262+
rs1 := strings.ToLower(acctest.RandString(11))
263+
sourceBlob, err := ioutil.TempFile("", "")
264+
if err != nil {
265+
t.Fatalf("Failed to create local source blob file")
266+
}
267+
268+
_, err = io.CopyN(sourceBlob, rand.Reader, 25*1024*1024)
269+
if err != nil {
270+
t.Fatalf("Failed to write random test to source blob")
271+
}
272+
273+
err = sourceBlob.Close()
274+
if err != nil {
275+
t.Fatalf("Failed to close source blob")
276+
}
277+
278+
config := fmt.Sprintf(testAccAzureRMStorageBlob_source_uri, ri, rs1, sourceBlob.Name())
279+
280+
resource.Test(t, resource.TestCase{
281+
PreCheck: func() { testAccPreCheck(t) },
282+
Providers: testAccProviders,
283+
CheckDestroy: testCheckAzureRMStorageBlobDestroy,
284+
Steps: []resource.TestStep{
285+
resource.TestStep{
286+
Config: config,
287+
Check: resource.ComposeTestCheckFunc(
288+
testCheckAzureRMStorageBlobMatchesFile("azurerm_storage_blob.destination", storage.BlobTypeBlock, sourceBlob.Name()),
289+
),
290+
},
291+
},
292+
})
293+
}
294+
260295
func testCheckAzureRMStorageBlobExists(name string) resource.TestCheckFunc {
261296
return func(s *terraform.State) error {
262297

@@ -500,3 +535,51 @@ resource "azurerm_storage_blob" "source" {
500535
attempts = 3
501536
}
502537
`
538+
539+
var testAccAzureRMStorageBlob_source_uri = `
540+
resource "azurerm_resource_group" "test" {
541+
name = "acctestrg-%d"
542+
location = "westus"
543+
}
544+
545+
resource "azurerm_storage_account" "source" {
546+
name = "acctestacc%s"
547+
resource_group_name = "${azurerm_resource_group.test.name}"
548+
location = "westus"
549+
account_type = "Standard_LRS"
550+
551+
tags {
552+
environment = "staging"
553+
}
554+
}
555+
556+
resource "azurerm_storage_container" "source" {
557+
name = "source"
558+
resource_group_name = "${azurerm_resource_group.test.name}"
559+
storage_account_name = "${azurerm_storage_account.source.name}"
560+
container_access_type = "blob"
561+
}
562+
563+
resource "azurerm_storage_blob" "source" {
564+
name = "source.vhd"
565+
566+
resource_group_name = "${azurerm_resource_group.test.name}"
567+
storage_account_name = "${azurerm_storage_account.source.name}"
568+
storage_container_name = "${azurerm_storage_container.source.name}"
569+
570+
type = "block"
571+
source = "%s"
572+
parallelism = 4
573+
attempts = 2
574+
}
575+
576+
resource "azurerm_storage_blob" "destination" {
577+
name = "destination.vhd"
578+
579+
resource_group_name = "${azurerm_resource_group.test.name}"
580+
storage_account_name = "${azurerm_storage_account.source.name}"
581+
storage_container_name = "${azurerm_storage_container.source.name}"
582+
583+
source_uri = "${azurerm_storage_blob.source.url}"
584+
}
585+
`

website/source/docs/providers/azurerm/r/storage_blob.html.markdown

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,15 @@ The following arguments are supported:
5858

5959
* `storage_container_name` - (Required) The name of the storage container in which this blob should be created.
6060

61-
* `type` - (Required) The type of the storage blob to be created. One of either `block` or `page`.
61+
* `type` - (Optional) The type of the storage blob to be created. One of either `block` or `page`. When not copying from an existing blob,
62+
this becomes required.
6263

6364
* `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.
64-
65-
* `source` - (Optional) An absolute path to a file on the local system
65+
66+
* `source` - (Optional) An absolute path to a file on the local system. Cannot be defined if `source_uri` is defined.
67+
68+
* `source_uri` - (Optional) The URI of an existing blob, or a file in the Azure File service, to use as the source contents
69+
for the blob to be created. Changing this forces a new resource to be created. Cannot be defined if `source` is defined.
6670

6771
* `parallelism` - (Optional) The number of workers per CPU core to run for concurrent uploads. Defaults to `8`.
6872

0 commit comments

Comments
 (0)