diff --git a/azurerm/internal/services/network/data_source_subnet.go b/azurerm/internal/services/network/data_source_subnet.go index f5c33e264caf..29b9ede88319 100644 --- a/azurerm/internal/services/network/data_source_subnet.go +++ b/azurerm/internal/services/network/data_source_subnet.go @@ -41,6 +41,12 @@ func dataSourceArmSubnet() *schema.Resource { Computed: true, }, + "address_prefixes": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + "network_security_group_id": { Type: schema.TypeString, Computed: true, @@ -102,7 +108,18 @@ func dataSourceArmSubnetRead(d *schema.ResourceData, meta interface{}) error { d.Set("virtual_network_name", virtualNetworkName) if props := resp.SubnetPropertiesFormat; props != nil { - d.Set("address_prefix", props.AddressPrefix) + if props.AddressPrefix != nil { + d.Set("address_prefix", props.AddressPrefix) + } + if props.AddressPrefixes == nil { + if props.AddressPrefix != nil && len(*props.AddressPrefix) > 0 { + d.Set("address_prefixes", []string{*props.AddressPrefix}) + } else { + d.Set("address_prefixes", []string{}) + } + } else { + d.Set("address_prefixes", utils.FlattenStringSlice(props.AddressPrefixes)) + } if pe := props.PrivateEndpointNetworkPolicies; pe != nil { d.Set("enforce_private_link_endpoint_network_policies", strings.EqualFold("Disabled", *pe)) diff --git a/azurerm/internal/services/network/resource_arm_subnet.go b/azurerm/internal/services/network/resource_arm_subnet.go index 0445168cd54e..039d2f85aece 100644 --- a/azurerm/internal/services/network/resource_arm_subnet.go +++ b/azurerm/internal/services/network/resource_arm_subnet.go @@ -53,8 +53,17 @@ func resourceArmSubnet() *schema.Resource { }, "address_prefix": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Optional: true, + Deprecated: "Use the `address_prefixes` property instead.", + ConflictsWith: []string{"address_prefixes"}, + }, + + "address_prefixes": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + ConflictsWith: []string{"address_prefix"}, }, "network_security_group_id": { @@ -179,13 +188,27 @@ func resourceArmSubnetCreateUpdate(d *schema.ResourceData, meta interface{}) err } } - addressPrefix := d.Get("address_prefix").(string) - - locks.ByName(vnetName, VirtualNetworkResourceName) - defer locks.UnlockByName(vnetName, VirtualNetworkResourceName) - - properties := network.SubnetPropertiesFormat{ - AddressPrefix: &addressPrefix, + var prefixSet bool + properties := network.SubnetPropertiesFormat{} + if value, ok := d.GetOk("address_prefixes"); ok { + var addressPrefixes []string + for _, item := range value.([]interface{}) { + addressPrefixes = append(addressPrefixes, item.(string)) + } + properties.AddressPrefixes = &addressPrefixes + prefixSet = len(addressPrefixes) > 0 + } + if value, ok := d.GetOk("address_prefix"); ok { + addressPrefix := value.(string) + properties.AddressPrefix = &addressPrefix + prefixSet = len(addressPrefix) > 0 + } + if properties.AddressPrefixes != nil && len(*properties.AddressPrefixes) == 1 { + properties.AddressPrefix = &(*properties.AddressPrefixes)[0] + properties.AddressPrefixes = nil + } + if !prefixSet { + return fmt.Errorf("[ERROR] either address_prefix or address_prefixes is required") } if v, ok := d.GetOk("enforce_private_link_service_network_policies"); ok { @@ -305,7 +328,18 @@ func resourceArmSubnetRead(d *schema.ResourceData, meta interface{}) error { d.Set("virtual_network_name", vnetName) if props := resp.SubnetPropertiesFormat; props != nil { - d.Set("address_prefix", props.AddressPrefix) + if props.AddressPrefix != nil { + d.Set("address_prefix", props.AddressPrefix) + } + if props.AddressPrefixes == nil { + if props.AddressPrefix != nil && len(*props.AddressPrefix) > 0 { + d.Set("address_prefixes", []string{*props.AddressPrefix}) + } else { + d.Set("address_prefixes", []string{}) + } + } else { + d.Set("address_prefixes", props.AddressPrefixes) + } if p := props.PrivateLinkServiceNetworkPolicies; p != nil { // To enable private endpoints you must disable the network policies for the diff --git a/azurerm/internal/services/network/tests/data_source_subnet_test.go b/azurerm/internal/services/network/tests/data_source_subnet_test.go index 89440f431cfa..721f6818271d 100644 --- a/azurerm/internal/services/network/tests/data_source_subnet_test.go +++ b/azurerm/internal/services/network/tests/data_source_subnet_test.go @@ -30,6 +30,28 @@ func TestAccDataSourceAzureRMSubnet_basic(t *testing.T) { }) } +func TestAccDataSourceAzureRMSubnet_basic_addressPrefixes(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_subnet", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAzureRMSubnet_basic_addressPrefixes(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(data.ResourceName, "name"), + resource.TestCheckResourceAttrSet(data.ResourceName, "resource_group_name"), + resource.TestCheckResourceAttrSet(data.ResourceName, "virtual_network_name"), + resource.TestCheckResourceAttrSet(data.ResourceName, "address_prefixes"), + resource.TestCheckResourceAttr(data.ResourceName, "network_security_group_id", ""), + resource.TestCheckResourceAttr(data.ResourceName, "route_table_id", ""), + ), + }, + }, + }) +} + func TestAccDataSourceAzureRMSubnet_networkSecurityGroup(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_subnet", "test") @@ -128,6 +150,35 @@ data "azurerm_subnet" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } +func testAccDataSourceAzureRMSubnet_basic_addressPrefixes(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctest%d-rg" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest%d-vn" + address_space = ["10.0.0.0/16"] + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_subnet" "test" { + name = "acctest%d-private" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefixes = ["10.0.0.0/24", "fd00::/48""] +} + +data "azurerm_subnet" "test" { + name = "${azurerm_subnet.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + func testAccDataSourceAzureRMSubnet_networkSecurityGroup(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/azurerm/internal/services/network/tests/resource_arm_subnet_test.go b/azurerm/internal/services/network/tests/resource_arm_subnet_test.go index 34b60986a081..f18491a32548 100644 --- a/azurerm/internal/services/network/tests/resource_arm_subnet_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_subnet_test.go @@ -34,6 +34,24 @@ func TestAccAzureRMSubnet_basic(t *testing.T) { }) } +func TestAccAzureRMSubnet_basic_addressPrefixes(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_subnet", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMSubnetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMSubnet_basic_addressPrefixes(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSubnetExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} func TestAccAzureRMSubnet_requiresImport(t *testing.T) { if !features.ShouldResourcesBeImported() { t.Skip("Skipping since resources aren't required to be imported") @@ -426,6 +444,29 @@ resource "azurerm_subnet" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } +func testAccAzureRMSubnet_basic_addressPrefixes(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%d" + address_space = ["10.0.0.0/16"] + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_subnet" "test" { + name = "acctestsubnet%d" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefixes = ["10.0.2.0/24", "fd00::/48"] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + func testAccAzureRMSubnet_requiresImport(data acceptance.TestData) string { template := testAccAzureRMSubnet_basic(data) return fmt.Sprintf(`