Skip to content

Commit

Permalink
r/network_interface_application_security_group_association: removing …
Browse files Browse the repository at this point in the history
…`ip_configuration_name`
  • Loading branch information
tombuildsstuff committed Feb 19, 2020
1 parent ec44fe6 commit 82c7e70
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package network

import (
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
)

func resourceNetworkInterfaceApplicationSecurityGroupAssociationUpgradeV0Schema() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"network_interface_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: azure.ValidateResourceID,
},

"application_security_group_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: azure.ValidateResourceID,
},
},
}
}

func resourceNetworkInterfaceApplicationSecurityGroupAssociationUpgradeV0ToV1(rawState map[string]interface{}, _ interface{}) (map[string]interface{}, error) {
// after shipping support for this Resource Azure's since changed the behaviour to require that all IP Configurations
// are connected to the same Application Security Group
applicationSecurityGroupId := rawState["application_security_group_id"].(string)
networkInterfaceId := rawState["network_interface_id"].(string)

oldID := rawState["id"].(string)
newID := fmt.Sprintf("%s|%s", networkInterfaceId, applicationSecurityGroupId)
log.Printf("[DEBUG] Updating ID from %q to %q", oldID, newID)

rawState["id"] = newID
return rawState, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ import (
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-09-01/network"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
Expand All @@ -27,6 +24,15 @@ func resourceArmNetworkInterfaceApplicationSecurityGroupAssociation() *schema.Re
State: schema.ImportStatePassthrough,
},

SchemaVersion: 1,
StateUpgraders: []schema.StateUpgrader{
{
Type: resourceNetworkInterfaceApplicationSecurityGroupAssociationUpgradeV0Schema().CoreConfigSchema().ImpliedType(),
Upgrade: resourceNetworkInterfaceApplicationSecurityGroupAssociationUpgradeV0ToV1,
Version: 0,
},
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(30 * time.Minute),
Read: schema.DefaultTimeout(5 * time.Minute),
Expand All @@ -42,13 +48,6 @@ func resourceArmNetworkInterfaceApplicationSecurityGroupAssociation() *schema.Re
ValidateFunc: azure.ValidateResourceID,
},

"ip_configuration_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringIsNotEmpty,
},

"application_security_group_id": {
Type: schema.TypeString,
Required: true,
Expand All @@ -67,7 +66,6 @@ func resourceArmNetworkInterfaceApplicationSecurityGroupAssociationCreate(d *sch
log.Printf("[INFO] preparing arguments for Network Interface <-> Application Security Group Association creation.")

networkInterfaceId := d.Get("network_interface_id").(string)
ipConfigurationName := d.Get("ip_configuration_name").(string)
applicationSecurityGroupId := d.Get("application_security_group_id").(string)

id, err := azure.ParseAzureResourceID(networkInterfaceId)
Expand All @@ -94,49 +92,19 @@ func resourceArmNetworkInterfaceApplicationSecurityGroupAssociationCreate(d *sch
if props == nil {
return fmt.Errorf("Error: `properties` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup)
}

ipConfigs := props.IPConfigurations
if ipConfigs == nil {
return fmt.Errorf("Error: `properties.IPConfigurations` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup)
}

c := azure.FindNetworkInterfaceIPConfiguration(props.IPConfigurations, ipConfigurationName)
if c == nil {
return fmt.Errorf("Error: IP Configuration %q was not found on Network Interface %q (Resource Group %q)", ipConfigurationName, networkInterfaceName, resourceGroup)
}

config := *c
p := config.InterfaceIPConfigurationPropertiesFormat
if p == nil {
return fmt.Errorf("Error: `IPConfiguration.properties` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup)
if props.IPConfigurations == nil {
return fmt.Errorf("Error: `properties.ipConfigurations` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup)
}

applicationSecurityGroups := make([]network.ApplicationSecurityGroup, 0)

// first double-check it doesn't exist
if p.ApplicationSecurityGroups != nil {
for _, existingGroup := range *p.ApplicationSecurityGroups {
if id := existingGroup.ID; id != nil {
if *id == applicationSecurityGroupId {
if features.ShouldResourcesBeImported() {
return tf.ImportAsExistsError("azurerm_network_interface_application_security_group_association", *id)
}

continue
}

applicationSecurityGroups = append(applicationSecurityGroups, existingGroup)
}
}
info := parseFieldsFromNetworkInterface(*props)
resourceId := fmt.Sprintf("%s|%s", networkInterfaceId, applicationSecurityGroupId)
if azure.SliceContainsValue(info.applicationSecurityGroupIDs, applicationSecurityGroupId) {
return tf.ImportAsExistsError("azurerm_network_interface_application_security_group_association", resourceId)
}

group := network.ApplicationSecurityGroup{
ID: utils.String(applicationSecurityGroupId),
}
applicationSecurityGroups = append(applicationSecurityGroups, group)
p.ApplicationSecurityGroups = &applicationSecurityGroups
info.applicationSecurityGroupIDs = append(info.applicationSecurityGroupIDs, applicationSecurityGroupId)

props.IPConfigurations = azure.UpdateNetworkInterfaceIPConfiguration(config, props.IPConfigurations)
read.InterfacePropertiesFormat.IPConfigurations = mapFieldsToNetworkInterface(props.IPConfigurations, info)

future, err := client.CreateOrUpdate(ctx, resourceGroup, networkInterfaceName, read)
if err != nil {
Expand All @@ -147,7 +115,6 @@ func resourceArmNetworkInterfaceApplicationSecurityGroupAssociationCreate(d *sch
return fmt.Errorf("Error waiting for completion of Application Security Group Association for NIC %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err)
}

resourceId := fmt.Sprintf("%s/ipConfigurations/%s|%s", networkInterfaceId, ipConfigurationName, applicationSecurityGroupId)
d.SetId(resourceId)

return resourceArmNetworkInterfaceApplicationSecurityGroupAssociationRead(d, meta)
Expand All @@ -160,15 +127,14 @@ func resourceArmNetworkInterfaceApplicationSecurityGroupAssociationRead(d *schem

splitId := strings.Split(d.Id(), "|")
if len(splitId) != 2 {
return fmt.Errorf("Expected ID to be in the format {networkInterfaceId}/ipConfigurations/{ipConfigurationName}|{applicationSecurityGroupId} but got %q", d.Id())
return fmt.Errorf("Expected ID to be in the format {networkInterfaceId}|{applicationSecurityGroupId} but got %q", d.Id())
}

nicID, err := azure.ParseAzureResourceID(splitId[0])
if err != nil {
return err
}

ipConfigurationName := nicID.Path["ipConfigurations"]
networkInterfaceName := nicID.Path["networkInterfaces"]
resourceGroup := nicID.ResourceGroup
applicationSecurityGroupId := splitId[1]
Expand All @@ -187,43 +153,21 @@ func resourceArmNetworkInterfaceApplicationSecurityGroupAssociationRead(d *schem
return fmt.Errorf("Error: `properties` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup)
}

ipConfigs := nicProps.IPConfigurations
if ipConfigs == nil {
return fmt.Errorf("Error: `properties.IPConfigurations` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup)
}

c := azure.FindNetworkInterfaceIPConfiguration(nicProps.IPConfigurations, ipConfigurationName)
if c == nil {
log.Printf("IP Configuration %q was not found in Network Interface %q (Resource Group %q) - removing from state!", ipConfigurationName, networkInterfaceName, resourceGroup)
d.SetId("")
return nil
}
config := *c

found := false
if props := config.InterfaceIPConfigurationPropertiesFormat; props != nil {
if groups := props.ApplicationSecurityGroups; groups != nil {
for _, group := range *groups {
if group.ID == nil {
continue
}

if *group.ID == applicationSecurityGroupId {
found = true
break
}
}
info := parseFieldsFromNetworkInterface(*nicProps)
exists := false
for _, groupId := range info.applicationSecurityGroupIDs {
if groupId == applicationSecurityGroupId {
exists = true
}
}

if !found {
if !exists {
log.Printf("[DEBUG] Association between Network Interface %q (Resource Group %q) and Application Security Group %q was not found - removing from state!", networkInterfaceName, resourceGroup, applicationSecurityGroupId)
d.SetId("")
return nil
}

d.Set("application_security_group_id", applicationSecurityGroupId)
d.Set("ip_configuration_name", ipConfigurationName)
d.Set("network_interface_id", read.ID)

return nil
Expand All @@ -236,15 +180,14 @@ func resourceArmNetworkInterfaceApplicationSecurityGroupAssociationDelete(d *sch

splitId := strings.Split(d.Id(), "|")
if len(splitId) != 2 {
return fmt.Errorf("Expected ID to be in the format {networkInterfaceId}/ipConfigurations/{ipConfigurationName}|{applicationSecurityGroupId} but got %q", d.Id())
return fmt.Errorf("Expected ID to be in the format {networkInterfaceId}|{applicationSecurityGroupId} but got %q", d.Id())
}

nicID, err := azure.ParseAzureResourceID(splitId[0])
if err != nil {
return err
}

ipConfigurationName := nicID.Path["ipConfigurations"]
networkInterfaceName := nicID.Path["networkInterfaces"]
resourceGroup := nicID.ResourceGroup
applicationSecurityGroupId := splitId[1]
Expand All @@ -261,41 +204,25 @@ func resourceArmNetworkInterfaceApplicationSecurityGroupAssociationDelete(d *sch
return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err)
}

nicProps := read.InterfacePropertiesFormat
if nicProps == nil {
props := read.InterfacePropertiesFormat
if props == nil {
return fmt.Errorf("Error: `properties` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup)
}

ipConfigs := nicProps.IPConfigurations
if ipConfigs == nil {
return fmt.Errorf("Error: `properties.IPConfigurations` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup)
}

c := azure.FindNetworkInterfaceIPConfiguration(nicProps.IPConfigurations, ipConfigurationName)
if c == nil {
return fmt.Errorf("Error: IP Configuration %q was not found on Network Interface %q (Resource Group %q)", ipConfigurationName, networkInterfaceName, resourceGroup)
}
config := *c

props := config.InterfaceIPConfigurationPropertiesFormat
if props == nil {
return fmt.Errorf("Error: Properties for IPConfiguration %q was nil for Network Interface %q (Resource Group %q)", ipConfigurationName, networkInterfaceName, resourceGroup)
if props.IPConfigurations == nil {
return fmt.Errorf("Error: `properties.ipConfigurations` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup)
}

applicationSecurityGroups := make([]network.ApplicationSecurityGroup, 0)
if groups := props.ApplicationSecurityGroups; groups != nil {
for _, pool := range *groups {
if pool.ID == nil {
continue
}
info := parseFieldsFromNetworkInterface(*props)

if *pool.ID != applicationSecurityGroupId {
applicationSecurityGroups = append(applicationSecurityGroups, pool)
}
applicationSecurityGroupIds := make([]string, 0)
for _, v := range info.applicationSecurityGroupIDs {
if v != applicationSecurityGroupId {
applicationSecurityGroupIds = append(applicationSecurityGroupIds, v)
}
}
props.ApplicationSecurityGroups = &applicationSecurityGroups
nicProps.IPConfigurations = azure.UpdateNetworkInterfaceIPConfiguration(config, nicProps.IPConfigurations)
info.applicationSecurityGroupIDs = applicationSecurityGroupIds
read.InterfacePropertiesFormat.IPConfigurations = mapFieldsToNetworkInterface(props.IPConfigurations, info)

future, err := client.CreateOrUpdate(ctx, resourceGroup, networkInterfaceName, read)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,25 @@ func TestAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_basic(t *
})
}

func TestAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_multipleIPConfigurations(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_network_interface_application_security_group_association", "test")
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
// intentional as this is a Virtual Resource
CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy,
Steps: []resource.TestStep{
{
Config: testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_multipleIPConfigurations(data),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMNetworkInterfaceApplicationSecurityGroupAssociationExists(data.ResourceName),
),
},
data.ImportStep(),
},
})
}

func TestAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_requiresImport(t *testing.T) {
if !features.ShouldResourcesBeImported() {
t.Skip("Skipping since resources aren't required to be imported")
Expand Down Expand Up @@ -242,13 +261,43 @@ func testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_requiresI
%s
resource "azurerm_network_interface_application_security_group_association" "import" {
network_interface_id = "${azurerm_network_interface_application_security_group_association.test.network_interface_id}"
ip_configuration_name = "${azurerm_network_interface_application_security_group_association.test.ip_configuration_name}"
application_security_group_id = "${azurerm_network_interface_application_security_group_association.test.application_security_group_id}"
network_interface_id = azurerm_network_interface_application_security_group_association.test.network_interface_id
application_security_group_id = azurerm_network_interface_application_security_group_association.test.application_security_group_id
}
`, template)
}

func testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_multipleIPConfigurations(data acceptance.TestData) string {
template := testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_template(data)
return fmt.Sprintf(`
%s
resource "azurerm_network_interface" "test" {
name = "acctestni-%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
ip_configuration {
name = "testconfiguration1"
subnet_id = azurerm_subnet.test.id
private_ip_address_allocation = "Dynamic"
}
ip_configuration {
name = "testconfiguration2"
subnet_id = azurerm_subnet.test.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_network_interface_application_security_group_association" "test" {
network_interface_id = azurerm_network_interface.test.id
ip_configuration_name = "testconfiguration1"
application_security_group_id = azurerm_application_security_group.test.id
}
`, template, data.RandomInteger)
}

func testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_updateNIC(data acceptance.TestData) string {
template := testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_template(data)
return fmt.Sprintf(`
Expand Down
4 changes: 4 additions & 0 deletions website/docs/guides/2.0-upgrade-guide.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,10 @@ The `load_balancer_backend_address_pools_ids` field in the `ip_configuration` bl

The `load_balancer_inbound_nat_rules_ids` field in the `ip_configuration` block will been removed. This has been replaced by the `azurerm_network_interface_nat_rule_association` resource.

### Resource: `azurerm_network_interface_application_security_group_association`

The field `ip_configuration_name` has been removed since the same Application Security Group must now be assigned to all (IPv4) IP Configurations.

### Resource: `azurerm_notification_hub_namespace`

The deprecated `sku` block has been replaced by the `sku_name` field and will be removed.
Expand Down
Loading

0 comments on commit 82c7e70

Please sign in to comment.