Skip to content

Commit

Permalink
azurerm_subnet: Support for multiple prefixes with address_prefixes
Browse files Browse the repository at this point in the history
  • Loading branch information
fabianofranz committed Apr 27, 2020
1 parent 8e31829 commit c1d8f52
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 18 deletions.
15 changes: 15 additions & 0 deletions azurerm/internal/services/network/data_source_subnet.go
Expand Up @@ -40,6 +40,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,
Expand Down Expand Up @@ -95,6 +101,15 @@ func dataSourceArmSubnetRead(d *schema.ResourceData, meta interface{}) error {

if props := resp.SubnetPropertiesFormat; props != 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))
}

d.Set("enforce_private_link_endpoint_network_policies", flattenSubnetPrivateLinkNetworkPolicy(props.PrivateEndpointNetworkPolicies))
d.Set("enforce_private_link_service_network_policies", flattenSubnetPrivateLinkNetworkPolicy(props.PrivateLinkServiceNetworkPolicies))
Expand Down
68 changes: 56 additions & 12 deletions azurerm/internal/services/network/resource_arm_subnet.go
Expand Up @@ -54,7 +54,22 @@ func resourceArmSubnet() *schema.Resource {

"address_prefix": {
Type: schema.TypeString,
Required: true,
Optional: true,
Computed: true,
// TODO Remove this in the next major version release
Deprecated: "Use the `address_prefixes` property instead.",
ExactlyOneOf: []string{"address_prefix", "address_prefixes"},
},

"address_prefixes": {
Type: schema.TypeList,
Optional: true,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
ExactlyOneOf: []string{"address_prefix", "address_prefixes"},
},

"service_endpoints": {
Expand Down Expand Up @@ -162,24 +177,35 @@ func resourceArmSubnetCreate(d *schema.ResourceData, meta interface{}) error {
}
}

addressPrefix := d.Get("address_prefix").(string)

locks.ByName(vnetName, VirtualNetworkResourceName)
defer locks.UnlockByName(vnetName, VirtualNetworkResourceName)

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
}
if value, ok := d.GetOk("address_prefix"); ok {
addressPrefix := value.(string)
properties.AddressPrefix = &addressPrefix
}
if properties.AddressPrefixes != nil && len(*properties.AddressPrefixes) == 1 {
properties.AddressPrefix = &(*properties.AddressPrefixes)[0]
properties.AddressPrefixes = nil
}

// To enable private endpoints you must disable the network policies for the subnet because
// Network policies like network security groups are not supported by private endpoints.
privateEndpointNetworkPolicies := d.Get("enforce_private_link_endpoint_network_policies").(bool)
privateLinkServiceNetworkPolicies := d.Get("enforce_private_link_service_network_policies").(bool)
properties.PrivateEndpointNetworkPolicies = expandSubnetPrivateLinkNetworkPolicy(privateEndpointNetworkPolicies)
properties.PrivateLinkServiceNetworkPolicies = expandSubnetPrivateLinkNetworkPolicy(privateLinkServiceNetworkPolicies)

serviceEndpointsRaw := d.Get("service_endpoints").([]interface{})
properties := network.SubnetPropertiesFormat{
AddressPrefix: &addressPrefix,
ServiceEndpoints: expandSubnetServiceEndpoints(serviceEndpointsRaw),

// To enable private endpoints you must disable the network policies for the subnet because
// Network policies like network security groups are not supported by private endpoints.
PrivateEndpointNetworkPolicies: expandSubnetPrivateLinkNetworkPolicy(privateEndpointNetworkPolicies),
PrivateLinkServiceNetworkPolicies: expandSubnetPrivateLinkNetworkPolicy(privateLinkServiceNetworkPolicies),
}
properties.ServiceEndpoints = expandSubnetServiceEndpoints(serviceEndpointsRaw)

delegationsRaw := d.Get("delegation").([]interface{})
properties.Delegations = expandSubnetDelegation(delegationsRaw)
Expand Down Expand Up @@ -241,6 +267,15 @@ func resourceArmSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
props.AddressPrefix = utils.String(d.Get("address_prefix").(string))
}

if d.HasChange("address_prefixes") {
addressPrefixesRaw := d.Get("address_prefixes").([]interface{})
props.AddressPrefixes = utils.ExpandStringSlice(addressPrefixesRaw)
if props.AddressPrefixes != nil && len(*props.AddressPrefixes) == 1 {
props.AddressPrefix = &(*props.AddressPrefixes)[0]
props.AddressPrefixes = nil
}
}

if d.HasChange("delegation") {
delegationsRaw := d.Get("delegation").([]interface{})
props.Delegations = expandSubnetDelegation(delegationsRaw)
Expand Down Expand Up @@ -307,6 +342,15 @@ func resourceArmSubnetRead(d *schema.ResourceData, meta interface{}) error {

if props := resp.SubnetPropertiesFormat; props != 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)
}

delegation := flattenSubnetDelegation(props.Delegations)
if err := d.Set("delegation", delegation); err != nil {
Expand Down
Expand Up @@ -442,8 +442,9 @@ func resourceAzureSubnetHash(v interface{}) int {

if m, ok := v.(map[string]interface{}); ok {
buf.WriteString(m["name"].(string))
buf.WriteString(m["address_prefix"].(string))

if v, ok := m["address_prefix"]; ok {
buf.WriteString(v.(string))
}
if v, ok := m["security_group"]; ok {
buf.WriteString(v.(string))
}
Expand Down
51 changes: 51 additions & 0 deletions azurerm/internal/services/network/tests/data_source_subnet_test.go
Expand Up @@ -30,6 +30,28 @@ func TestAccDataSourceSubnet_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: testAccDataSourceSubnet_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 TestAccDataSourceSubnet_networkSecurityGroup(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_subnet", "test")

Expand Down Expand Up @@ -127,6 +149,35 @@ data "azurerm_subnet" "test" {
`, template)
}

func testAccDataSourceSubnet_basic_addressPrefixes(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
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", "ace:cab:deca::/48"]
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", "ace:cab:deca:deed::/64"]
}
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 testAccDataSourceSubnet_networkSecurityGroupDependencies(data acceptance.TestData) string {
template := testAccDataSourceSubnet_template(data)
return fmt.Sprintf(`
Expand Down
Expand Up @@ -32,6 +32,25 @@ 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) {
data := acceptance.BuildTestData(t, "azurerm_subnet", "test")

Expand Down Expand Up @@ -436,6 +455,27 @@ resource "azurerm_subnet" "test" {
`, template, enabled)
}

func testAccAzureRMSubnet_basic_addressPrefixes(data acceptance.TestData) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
name = "acctestRG-n-%d"
location = "%s"
}
resource "azurerm_virtual_network" "test" {
name = "acctestvirtnet%d"
address_space = ["10.0.0.0/16", "ace:cab:deca::/48"]
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.0.0/24", "ace:cab:deca:deed::/64"]
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger)
}

func testAccAzureRMSubnet_requiresImport(data acceptance.TestData) string {
template := testAccAzureRMSubnet_basic(data)
return fmt.Sprintf(`
Expand Down
3 changes: 2 additions & 1 deletion website/docs/d/subnet.html.markdown
Expand Up @@ -33,7 +33,8 @@ output "subnet_id" {
## Attributes Reference

* `id` - The ID of the Subnet.
* `address_prefix` - The address prefix used for the subnet.
* `address_prefix` - (Deprecated) The address prefix used for the subnet.
* `address_prefixes` - The address prefixes for the subnet.
* `enforce_private_link_service_network_policies` - Enable or Disable network policies on private link service in the subnet.
* `network_security_group_id` - The ID of the Network Security Group associated with the subnet.
* `route_table_id` - The ID of the Route Table associated with this subnet.
Expand Down
11 changes: 8 additions & 3 deletions website/docs/r/subnet.html.markdown
Expand Up @@ -34,7 +34,7 @@ resource "azurerm_subnet" "example" {
name = "testsubnet"
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
address_prefix = "10.0.1.0/24"
address_prefixes = ["10.0.1.0/24"]
delegation {
name = "acctestdelegation"
Expand All @@ -57,7 +57,11 @@ The following arguments are supported:

* `virtual_network_name` - (Required) The name of the virtual network to which to attach the subnet. Changing this forces a new resource to be created.

* `address_prefix` - (Required) The address prefix to use for the subnet.
* `address_prefix` - (Optional / **Deprecated in favour of `address_prefixes`**) The address prefix to use for the subnet.

* `address_prefixes` - (Optional) The address prefixes to use for the subnet.

-> **NOTE:** One of `address_prefix` or `address_prefixes` is required.

---

Expand Down Expand Up @@ -101,7 +105,8 @@ The following attributes are exported:
* `name` - The name of the subnet.
* `resource_group_name` - The name of the resource group in which the subnet is created in.
* `virtual_network_name` - The name of the virtual network in which the subnet is created in
* `address_prefix` - The address prefix for the subnet
* `address_prefix` - (Deprecated) The address prefix for the subnet
* `address_prefixes` - The address prefixes for the subnet

## Timeouts

Expand Down

0 comments on commit c1d8f52

Please sign in to comment.