diff --git a/azurerm/data_source_image.go b/azurerm/data_source_image.go index 3c2f7e2c9640..77ade9ea65cf 100644 --- a/azurerm/data_source_image.go +++ b/azurerm/data_source_image.go @@ -40,6 +40,11 @@ func dataSourceArmImage() *schema.Resource { "location": locationForDataSourceSchema(), + "zone_resilient": { + Type: schema.TypeBool, + Computed: true, + }, + "os_disk": { Type: schema.TypeList, Computed: true, @@ -191,6 +196,8 @@ func dataSourceArmImageRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("[DEBUG] Error setting AzureRM Image Data Disks error: %+v", err) } } + + d.Set("zone_resilient", profile.ZoneResilient) } flattenAndSetTags(d, img.Tags) diff --git a/azurerm/resource_arm_image.go b/azurerm/resource_arm_image.go index 9d923e211133..07b3d1f02194 100644 --- a/azurerm/resource_arm_image.go +++ b/azurerm/resource_arm_image.go @@ -35,6 +35,13 @@ func resourceArmImage() *schema.Resource { "resource_group_name": resourceGroupNameSchema(), + "zone_resilient": { + Type: schema.TypeBool, + Optional: true, + Default: false, + ForceNew: true, + }, + "source_virtual_machine_id": { Type: schema.TypeString, Optional: true, @@ -166,6 +173,7 @@ func resourceArmImageCreateUpdate(d *schema.ResourceData, meta interface{}) erro name := d.Get("name").(string) resGroup := d.Get("resource_group_name").(string) + zoneResilient := d.Get("zone_resilient").(bool) if requireResourcesToBeImported && d.IsNewResource() { existing, err := client.Get(ctx, resGroup, name, "") @@ -196,8 +204,9 @@ func resourceArmImageCreateUpdate(d *schema.ResourceData, meta interface{}) erro } storageProfile := compute.ImageStorageProfile{ - OsDisk: osDisk, - DataDisks: &dataDisks, + OsDisk: osDisk, + DataDisks: &dataDisks, + ZoneResilient: utils.Bool(zoneResilient), } sourceVM := compute.SubResource{} @@ -295,6 +304,7 @@ func resourceArmImageRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("[DEBUG] Error setting AzureRM Image Data Disks error: %+v", err) } } + d.Set("zone_resilient", resp.StorageProfile.ZoneResilient) } flattenAndSetTags(d, resp.Tags) diff --git a/azurerm/resource_arm_image_test.go b/azurerm/resource_arm_image_test.go index f356b3f5c7f2..4f3b457093d3 100644 --- a/azurerm/resource_arm_image_test.go +++ b/azurerm/resource_arm_image_test.go @@ -22,8 +22,48 @@ func TestAccAzureRMImage_standaloneImage(t *testing.T) { hostName := fmt.Sprintf("tftestcustomimagesrc%d", ri) sshPort := "22" location := testLocation() - preConfig := testAccAzureRMImage_standaloneImage_setup(ri, userName, password, hostName, location) - postConfig := testAccAzureRMImage_standaloneImage_provision(ri, userName, password, hostName, location) + preConfig := testAccAzureRMImage_standaloneImage_setup(ri, userName, password, hostName, location, "LRS") + postConfig := testAccAzureRMImage_standaloneImage_provision(ri, userName, password, hostName, location, "LRS") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMImageDestroy, + Steps: []resource.TestStep{ + { + //need to create a vm and then reference it in the image creation + Config: preConfig, + Destroy: false, + Check: resource.ComposeTestCheckFunc( + testCheckAzureVMExists("azurerm_virtual_machine.testsource", true), + testGeneralizeVMImage(resourceGroup, "testsource", userName, password, hostName, sshPort, location), + ), + }, + { + Config: postConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMImageExists("azurerm_image.test", true), + ), + }, + { + ResourceName: "azurerm_image.test", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMImage_standaloneImageZoneRedundant(t *testing.T) { + ri := tf.AccRandTimeInt() + resourceGroup := fmt.Sprintf("acctestRG-%d", ri) + userName := "testadmin" + password := "Password1234!" + hostName := fmt.Sprintf("tftestcustomimagesrc%d", ri) + sshPort := "22" + location := testLocation() + preConfig := testAccAzureRMImage_standaloneImage_setup(ri, userName, password, hostName, location, "ZRS") + postConfig := testAccAzureRMImage_standaloneImage_provision(ri, userName, password, hostName, location, "ZRS") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -75,7 +115,7 @@ func TestAccAzureRMImage_requiresImport(t *testing.T) { Steps: []resource.TestStep{ { //need to create a vm and then reference it in the image creation - Config: testAccAzureRMImage_standaloneImage_setup(ri, userName, password, hostName, location), + Config: testAccAzureRMImage_standaloneImage_setup(ri, userName, password, hostName, location, "LRS"), Destroy: false, Check: resource.ComposeTestCheckFunc( testCheckAzureVMExists("azurerm_virtual_machine.testsource", true), @@ -83,7 +123,7 @@ func TestAccAzureRMImage_requiresImport(t *testing.T) { ), }, { - Config: testAccAzureRMImage_standaloneImage_provision(ri, userName, password, hostName, location), + Config: testAccAzureRMImage_standaloneImage_provision(ri, userName, password, hostName, location, "LRS"), Check: resource.ComposeTestCheckFunc( testCheckAzureRMImageExists("azurerm_image.test", true), ), @@ -397,7 +437,7 @@ func testCheckAzureRMImageDestroy(s *terraform.State) error { return nil } -func testAccAzureRMImage_standaloneImage_setup(rInt int, userName string, password string, hostName string, location string) string { +func testAccAzureRMImage_standaloneImage_setup(rInt int, userName string, password string, hostName string, location string, storageType string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" @@ -444,7 +484,7 @@ resource "azurerm_storage_account" "test" { resource_group_name = "${azurerm_resource_group.test.name}" location = "${azurerm_resource_group.test.location}" account_tier = "Standard" - account_replication_type = "LRS" + account_replication_type = "%s" tags = { environment = "Dev" @@ -495,10 +535,10 @@ resource "azurerm_virtual_machine" "testsource" { cost-center = "Ops" } } -`, rInt, location, rInt, rInt, rInt, hostName, rInt, rInt, userName, password) +`, rInt, location, rInt, rInt, rInt, hostName, rInt, rInt, storageType, userName, password) } -func testAccAzureRMImage_standaloneImage_provision(rInt int, userName string, password string, hostName string, location string) string { +func testAccAzureRMImage_standaloneImage_provision(rInt int, userName string, password string, hostName string, location string, storageType string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" @@ -545,7 +585,7 @@ resource "azurerm_storage_account" "test" { resource_group_name = "${azurerm_resource_group.test.name}" location = "${azurerm_resource_group.test.location}" account_tier = "Standard" - account_replication_type = "LRS" + account_replication_type = "%s" tags = { environment = "Dev" @@ -601,6 +641,7 @@ resource "azurerm_image" "test" { name = "accteste" location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" + zone_resilient = %t os_disk { os_type = "Linux" @@ -615,11 +656,11 @@ resource "azurerm_image" "test" { cost-center = "Ops" } } -`, rInt, location, rInt, rInt, rInt, hostName, rInt, rInt, userName, password) +`, rInt, location, rInt, rInt, rInt, hostName, rInt, rInt, storageType, userName, password, storageType == "ZRS") } func testAccAzureRMImage_standaloneImage_requiresImport(rInt int, userName string, password string, hostName string, location string) string { - template := testAccAzureRMImage_standaloneImage_provision(rInt, userName, password, hostName, location) + template := testAccAzureRMImage_standaloneImage_provision(rInt, userName, password, hostName, location, "LRS") return fmt.Sprintf(` %s diff --git a/azurerm/resource_arm_shared_image_version_test.go b/azurerm/resource_arm_shared_image_version_test.go index 6d577cfef795..9af480b23ea4 100644 --- a/azurerm/resource_arm_shared_image_version_test.go +++ b/azurerm/resource_arm_shared_image_version_test.go @@ -166,11 +166,11 @@ func testCheckAzureRMSharedImageVersionExists(resourceName string) resource.Test } func testAccAzureRMSharedImageVersion_setup(rInt int, location, username, password, hostname string) string { - return testAccAzureRMImage_standaloneImage_setup(rInt, username, password, hostname, location) + return testAccAzureRMImage_standaloneImage_setup(rInt, username, password, hostname, location, "LRS") } func testAccAzureRMSharedImageVersion_provision(rInt int, location, username, password, hostname string) string { - template := testAccAzureRMImage_standaloneImage_provision(rInt, username, password, hostname, location) + template := testAccAzureRMImage_standaloneImage_provision(rInt, username, password, hostname, location, "LRS") return fmt.Sprintf(` %s diff --git a/azurerm/resource_arm_virtual_machine_scale_set_test.go b/azurerm/resource_arm_virtual_machine_scale_set_test.go index 9b6c551219df..7ada56a837b2 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set_test.go +++ b/azurerm/resource_arm_virtual_machine_scale_set_test.go @@ -507,7 +507,7 @@ func TestAccAzureRMVirtualMachineScaleSet_customImage(t *testing.T) { hostName := fmt.Sprintf("tftestcustomimagesrc%d", ri) sshPort := "22" config := testAccAzureRMVirtualMachineScaleSet_customImage(ri, testLocation(), userName, password, hostName) - preConfig := testAccAzureRMImage_standaloneImage_setup(ri, userName, password, hostName, testLocation()) + preConfig := testAccAzureRMImage_standaloneImage_setup(ri, userName, password, hostName, testLocation(), "LRS") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, diff --git a/website/docs/d/image.html.markdown b/website/docs/d/image.html.markdown index 609a25d0a634..0b8f43c89981 100644 --- a/website/docs/d/image.html.markdown +++ b/website/docs/d/image.html.markdown @@ -33,11 +33,12 @@ output "image_id" { ## Attributes Reference +* `data_disk` - a collection of `data_disk` blocks as defined below. * `name` - the name of the Image. * `location` - the Azure Location where this Image exists. * `os_disk` - a `os_disk` block as defined below. -* `data_disk` - a collection of `data_disk` blocks as defined below. * `tags` - a mapping of tags to assigned to the resource. +* `zone_resilient` - is zone resiliency enabled? `os_disk` supports the following: diff --git a/website/docs/r/image.html.markdown b/website/docs/r/image.html.markdown index 799802930c25..a14f3b451ed1 100644 --- a/website/docs/r/image.html.markdown +++ b/website/docs/r/image.html.markdown @@ -62,6 +62,9 @@ The following arguments are supported: * `os_disk` - (Optional) One or more `os_disk` elements as defined below. * `data_disk` - (Optional) One or more `data_disk` elements as defined below. * `tags` - (Optional) A mapping of tags to assign to the resource. +* `zone_resilient` - (Optional) Is zone resiliency enabled? Defaults to `false`. Changing this forces a new resource to be created. + +~> **Note**: `zone_resilient` can only be set to `true` if the image is stored in a region that supports availability zones. `os_disk` supports the following: