Skip to content

Commit

Permalink
virtualnetwork: allow address_prefix to be null
Browse files Browse the repository at this point in the history
The azure subnet resource allows for multiple address prefixes using the
address_prefixes argument. The virtual network resource allows inline subnets,
but does not currently support this argument. When the address_prefixes argument
is used, address_prefix will be null when terraform refreshes its state causing
terraform to panic. This code updates the virtual network resource to allow
address_prefixes to be used and for address_prefix to be null.

Tests have been added to test the multiple prefixes. The magic number in the
new tests is the same magic number used in the other VNet tests. I'm not 100%
clear on this number, but it appears to be a known ID. It's origin is
documented (not very well) here:

hashicorp#1913

This fix addresses the following bugs:

https://bugzilla.redhat.com/show_bug.cgi?id=1805251
https://bugzilla.redhat.com/show_bug.cgi?id=1808973
https://bugzilla.redhat.com/show_bug.cgi?id=1805936
https://bugzilla.redhat.com/show_bug.cgi?id=1808969
  • Loading branch information
jhixson74 committed Mar 13, 2020
1 parent 4e2e024 commit 8f31940
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 7 deletions.
64 changes: 57 additions & 7 deletions azurerm/internal/services/network/resource_arm_virtual_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,15 @@ func resourceArmVirtualNetwork() *schema.Resource {
},

"address_prefix": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validate.NoEmptyStrings,
Type: schema.TypeString,
Optional: true,
Deprecated: "Use the `address_prefixes` property instead.",
},

"address_prefixes": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"security_group": {
Expand Down Expand Up @@ -307,7 +313,36 @@ func expandVirtualNetworkProperties(ctx context.Context, d *schema.ResourceData,
}
log.Printf("[INFO] Completed GET of Subnet props ")

prefix := subnet["address_prefix"].(string)
var prefixSet int = 0
properties := network.SubnetPropertiesFormat{}
if value, ok := subnet["address_prefixes"]; ok {
var addressPrefixes []string
for _, item := range value.([]interface{}) {
addressPrefixes = append(addressPrefixes, item.(string))
}
properties.AddressPrefixes = &addressPrefixes
if len(addressPrefixes) > 0 {
prefixSet += 1
}
}
if value, ok := subnet["address_prefix"]; ok {
addressPrefix := value.(string)
properties.AddressPrefix = &addressPrefix
if len(addressPrefix) > 0 {
prefixSet += 1
}
}
if properties.AddressPrefixes != nil && len(*properties.AddressPrefixes) == 1 {
properties.AddressPrefix = &(*properties.AddressPrefixes)[0]
properties.AddressPrefixes = nil
}
if prefixSet == 0 {
return nil, fmt.Errorf("[ERROR] either address_prefix or address_prefixes is required")
}
if prefixSet == 2 {
return nil, fmt.Errorf("[ERROR] either address_prefix or address_prefixes must be set, not both")
}

secGroup := subnet["security_group"].(string)

//set the props from config and leave the rest intact
Expand All @@ -316,7 +351,8 @@ func expandVirtualNetworkProperties(ctx context.Context, d *schema.ResourceData,
subnetObj.SubnetPropertiesFormat = &network.SubnetPropertiesFormat{}
}

subnetObj.SubnetPropertiesFormat.AddressPrefix = &prefix
subnetObj.SubnetPropertiesFormat.AddressPrefixes = properties.AddressPrefixes
subnetObj.SubnetPropertiesFormat.AddressPrefix = properties.AddressPrefix

if secGroup != "" {
subnetObj.SubnetPropertiesFormat.NetworkSecurityGroup = &network.SecurityGroup{
Expand Down Expand Up @@ -399,6 +435,14 @@ func flattenVirtualNetworkSubnets(input *[]network.Subnet) *schema.Set {
}

if props := subnet.SubnetPropertiesFormat; props != nil {
if prefixes := props.AddressPrefixes; prefixes != nil {
var addressPrefixes []interface{}
for _, prefix := range *prefixes {
addressPrefixes = append(addressPrefixes, prefix)
}
output["address_prefixes"] = addressPrefixes
}

if prefix := props.AddressPrefix; prefix != nil {
output["address_prefix"] = *prefix
}
Expand Down Expand Up @@ -434,8 +478,14 @@ 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_prefixes"]; ok {
for _, a := range v.([]interface{}) {
buf.WriteString(a.(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
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,29 @@ func TestAccDataSourceArmVirtualNetwork_basic(t *testing.T) {
})
}

func TestAccDataSourceArmVirtualNetwork_basic_addressPrefixes(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_virtual_network", "test")

name := fmt.Sprintf("acctestvnet-%d", data.RandomInteger)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceArmVirtualNetwork_basic_addressPrefixes(data),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(data.ResourceName, "name", name),
resource.TestCheckResourceAttr(data.ResourceName, "location", azure.NormalizeLocation(data.Locations.Primary)),
resource.TestCheckResourceAttr(data.ResourceName, "dns_servers.0", "10.0.0.4"),
resource.TestCheckResourceAttr(data.ResourceName, "address_spaces.0", "10.0.0.0/16"),
resource.TestCheckResourceAttr(data.ResourceName, "subnets.0", "subnet1"),
),
},
},
})
}

func TestAccDataSourceArmVirtualNetwork_peering(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_virtual_network", "test")

Expand Down Expand Up @@ -83,6 +106,33 @@ data "azurerm_virtual_network" "test" {
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func testAccDataSourceArmVirtualNetwork_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 = "acctestvnet-%d"
address_space = ["10.0.0.0/16"]
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
dns_servers = ["10.0.0.4"]
subnet {
name = "subnet1"
address_prefixes = ["10.0.1.0/24", "10.0.2.0/24"]
}
}
data "azurerm_virtual_network" "test" {
resource_group_name = "${azurerm_resource_group.test.name}"
name = "${azurerm_virtual_network.test.name}"
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func testAccDataSourceArmVirtualNetwork_peering(data acceptance.TestData) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,27 @@ func TestAccAzureRMVirtualNetwork_basic(t *testing.T) {
})
}

func TestAccAzureRMVirtualNetwork_basic_addressPrefixes(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_virtual_network", "test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
CheckDestroy: testCheckAzureRMVirtualNetworkDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureRMVirtualNetwork_basic_addressPrefixes(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMVirtualNetworkExists(data.ResourceName),
resource.TestCheckResourceAttr(data.ResourceName, "subnet.#", "1"),
resource.TestCheckResourceAttrSet(data.ResourceName, "subnet.1472110187.id"),
),
},
data.ImportStep(),
},
})
}

func TestAccAzureRMVirtualNetwork_basicUpdated(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_virtual_network", "test")

Expand Down Expand Up @@ -289,6 +310,27 @@ resource "azurerm_virtual_network" "test" {
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func testAccAzureRMVirtualNetwork_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}"
subnet {
name = "subnet1"
address_prefixes = ["10.0.1.0/24", "10.0.2.0/24"]
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger)
}

func testAccAzureRMVirtualNetwork_basicUpdated(data acceptance.TestData) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
Expand Down

0 comments on commit 8f31940

Please sign in to comment.