diff --git a/azurerm/resource_arm_dev_test_virtual_network.go b/azurerm/resource_arm_dev_test_virtual_network.go index f9d5924ade2c..fc685a07113e 100644 --- a/azurerm/resource_arm_dev_test_virtual_network.go +++ b/azurerm/resource_arm_dev_test_virtual_network.go @@ -46,6 +46,36 @@ func resourceArmDevTestVirtualNetwork() *schema.Resource { Optional: true, }, + "subnet": { + Type: schema.TypeList, + Optional: true, + Computed: true, + // whilst the API accepts multiple, in practice only one is usable + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + + "use_in_virtual_machine_creation": { + Type: schema.TypeString, + Optional: true, + Default: string(dtl.Allow), + ValidateFunc: validateDevTestVirtualNetworkUsagePermissionType(), + }, + + "use_public_ip_address": { + Type: schema.TypeString, + Optional: true, + Default: string(dtl.Allow), + ValidateFunc: validateDevTestVirtualNetworkUsagePermissionType(), + }, + }, + }, + }, + "tags": tagsSchema(), "unique_identifier": { @@ -68,10 +98,15 @@ func resourceArmDevTestVirtualNetworkCreateUpdate(d *schema.ResourceData, meta i description := d.Get("description").(string) tags := d.Get("tags").(map[string]interface{}) + subscriptionId := meta.(*ArmClient).subscriptionId + subnetsRaw := d.Get("subnet").([]interface{}) + subnets := expandDevTestVirtualNetworkSubnets(d, subnetsRaw, subscriptionId, resourceGroup, labName, name) + parameters := dtl.VirtualNetwork{ Tags: expandTags(tags), VirtualNetworkProperties: &dtl.VirtualNetworkProperties{ - Description: utils.String(description), + Description: utils.String(description), + SubnetOverrides: subnets, }, } @@ -129,6 +164,11 @@ func resourceArmDevTestVirtualNetworkRead(d *schema.ResourceData, meta interface if props := read.VirtualNetworkProperties; props != nil { d.Set("description", props.Description) + flattenedSubnets := flattenDevTestVirtualNetworkSubnets(props.SubnetOverrides) + if err := d.Set("subnet", flattenedSubnets); err != nil { + return fmt.Errorf("Error setting `subnet`: %+v", err) + } + // Computed fields d.Set("unique_identifier", props.UniqueIdentifier) } @@ -179,3 +219,65 @@ func validateDevTestVirtualNetworkName() schema.SchemaValidateFunc { regexp.MustCompile("^[A-Za-z0-9_-]+$"), "Virtual Network Name can only include alphanumeric characters, underscores, hyphens.") } + +func expandDevTestVirtualNetworkSubnets(d *schema.ResourceData, input []interface{}, subscriptionId, resourceGroupName, labName, virtualNetworkName string) *[]dtl.SubnetOverride { + results := make([]dtl.SubnetOverride, 0) + // default found from the Portal + name := fmt.Sprintf("%sSubnet", virtualNetworkName) + idFmt := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.DevTestLab/labs/%s/virtualnetworks/%s/subnets/%s" + subnetId := fmt.Sprintf(idFmt, subscriptionId, resourceGroupName, labName, virtualNetworkName, name) + if len(input) == 0 { + result := dtl.SubnetOverride{ + ResourceID: utils.String(subnetId), + LabSubnetName: utils.String(name), + UsePublicIPAddressPermission: dtl.Allow, + UseInVMCreationPermission: dtl.Allow, + } + results = append(results, result) + return &results + } + + for _, val := range input { + v := val.(map[string]interface{}) + usePublicIPAddress := v["use_public_ip_address"].(string) + useInVirtualMachineCreation := v["use_in_virtual_machine_creation"].(string) + + subnet := dtl.SubnetOverride{ + ResourceID: utils.String(subnetId), + LabSubnetName: utils.String(name), + UsePublicIPAddressPermission: dtl.UsagePermissionType(usePublicIPAddress), + UseInVMCreationPermission: dtl.UsagePermissionType(useInVirtualMachineCreation), + } + results = append(results, subnet) + } + + return &results +} + +func flattenDevTestVirtualNetworkSubnets(input *[]dtl.SubnetOverride) []interface{} { + outputs := make([]interface{}, 0) + if input == nil { + return outputs + } + + for _, v := range *input { + output := make(map[string]interface{}, 0) + if v.LabSubnetName != nil { + output["name"] = *v.LabSubnetName + } + output["use_public_ip_address"] = string(v.UsePublicIPAddressPermission) + output["use_in_virtual_machine_creation"] = string(v.UseInVMCreationPermission) + + outputs = append(outputs, output) + } + + return outputs +} + +func validateDevTestVirtualNetworkUsagePermissionType() schema.SchemaValidateFunc { + return validation.StringInSlice([]string{ + string(dtl.Allow), + string(dtl.Default), + string(dtl.Deny), + }, false) +} diff --git a/azurerm/resource_arm_dev_test_virtual_network_test.go b/azurerm/resource_arm_dev_test_virtual_network_test.go index f53009bdd476..0eb0dcef5a54 100644 --- a/azurerm/resource_arm_dev_test_virtual_network_test.go +++ b/azurerm/resource_arm_dev_test_virtual_network_test.go @@ -64,6 +64,35 @@ func TestAccAzureRMDevTestVirtualNetwork_basic(t *testing.T) { }) } +func TestAccAzureRMDevTestVirtualNetwork_subnet(t *testing.T) { + resourceName := "azurerm_dev_test_virtual_network.test" + rInt := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMDevTestVirtualNetworkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMDevTestVirtualNetwork_subnets(rInt, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDevTestVirtualNetworkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "subnet.#", "1"), + resource.TestCheckResourceAttr(resourceName, "subnet.0.use_public_ip_address", "Allow"), + resource.TestCheckResourceAttr(resourceName, "subnet.0.use_in_virtual_machine_creation", "Allow"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testCheckAzureRMDevTestVirtualNetworkExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API @@ -141,3 +170,29 @@ resource "azurerm_dev_test_virtual_network" "test" { } `, rInt, location, rInt, rInt) } + +func testAccAzureRMDevTestVirtualNetwork_subnets(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_dev_test_lab" "test" { + name = "acctestdtl%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_dev_test_virtual_network" "test" { + name = "acctestdtvn%d" + lab_name = "${azurerm_dev_test_lab.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + + subnet { + use_public_ip_address = "Allow" + use_in_virtual_machine_creation = "Allow" + } +} +`, rInt, location, rInt, rInt) +} diff --git a/website/docs/r/dev_test_virtual_network.html.markdown b/website/docs/r/dev_test_virtual_network.html.markdown index d12f1d5e1b01..632e6accf3b8 100644 --- a/website/docs/r/dev_test_virtual_network.html.markdown +++ b/website/docs/r/dev_test_virtual_network.html.markdown @@ -51,16 +51,34 @@ The following arguments are supported: * `description` - (Optional) A description for the Virtual Network. +* `subnet` - (Optional) A `subnet` block as defined below. + * `tags` - (Optional) A mapping of tags to assign to the resource. +--- + +A `subnet` block supports the following: + +* `use_public_ip_address` - (Required) Can Virtual Machines in this Subnet use Public IP Addresses? Possible values are `Allow`, `Default` and `Deny`. + +* `use_in_virtual_machine_creation` - (Required) Can this subnet be used for creating Virtual Machines? Possible values are `Allow`, `Default` and `Deny`. + ## Attributes Reference The following attributes are exported: * `id` - The ID of the Dev Test Virtual Network. +* `subnet` - A `subnet` block as defined below. + * `unique_identifier` - The unique immutable identifier of the Dev Test Virtual Network. +--- + +A `subnet` block exports the following: + +* `name` - The name of the Subnet for this Virtual Network. + ## Import Dev Test Virtual Networks can be imported using the `resource id`, e.g.