Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Resources: azurerm_network_interface_(backend_address_pool|nat_rule)_association #2079

Merged
merged 8 commits into from
Oct 16, 2018
42 changes: 42 additions & 0 deletions azurerm/helpers/azure/network_interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package azure

import "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-04-01/network"

func FindNetworkInterfaceIPConfiguration(input *[]network.InterfaceIPConfiguration, name string) *network.InterfaceIPConfiguration {
if input == nil {
return nil
}

for _, v := range *input {
if v.Name == nil {
continue
}

if *v.Name == name {
return &v
}
}

return nil
}

func UpdateNetworkInterfaceIPConfiguration(config network.InterfaceIPConfiguration, configs *[]network.InterfaceIPConfiguration) *[]network.InterfaceIPConfiguration {
output := make([]network.InterfaceIPConfiguration, 0)
if configs == nil {
return &output
}

for _, v := range *configs {
if v.Name == nil {
continue
}

if *v.Name != *config.Name {
output = append(output, v)
} else {
output = append(output, config)
}
}

return &output
}
326 changes: 164 additions & 162 deletions azurerm/provider.go

Large diffs are not rendered by default.

22 changes: 16 additions & 6 deletions azurerm/resource_arm_network_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

var networkInterfaceResourceName = "azurerm_network_interface"

func resourceArmNetworkInterface() *schema.Resource {
return &schema.Resource{
Create: resourceArmNetworkInterfaceCreateUpdate,
Expand Down Expand Up @@ -108,9 +110,10 @@ func resourceArmNetworkInterface() *schema.Resource {
},

"load_balancer_backend_address_pools_ids": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
Type: schema.TypeSet,
Optional: true,
Computed: true,
Deprecated: "This field has been deprecated in favour of the `azurerm_network_interface_backend_address_pool_association` resource.",
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: azure.ValidateResourceID,
Expand All @@ -119,9 +122,10 @@ func resourceArmNetworkInterface() *schema.Resource {
},

"load_balancer_inbound_nat_rules_ids": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
Type: schema.TypeSet,
Optional: true,
Computed: true,
Deprecated: "This field has been deprecated in favour of the `azurerm_network_interface_nat_rule_association` resource.",
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: azure.ValidateResourceID,
Expand Down Expand Up @@ -241,6 +245,9 @@ func resourceArmNetworkInterfaceCreateUpdate(d *schema.ResourceData, meta interf
EnableAcceleratedNetworking: &enableAcceleratedNetworking,
}

azureRMLockByName(name, networkInterfaceResourceName)
defer azureRMUnlockByName(name, networkInterfaceResourceName)

if v, ok := d.GetOk("network_security_group_id"); ok {
nsgId := v.(string)
properties.NetworkSecurityGroup = &network.SecurityGroup{
Expand Down Expand Up @@ -430,6 +437,9 @@ func resourceArmNetworkInterfaceDelete(d *schema.ResourceData, meta interface{})
resGroup := id.ResourceGroup
name := id.Path["networkInterfaces"]

azureRMLockByName(name, networkInterfaceResourceName)
defer azureRMUnlockByName(name, networkInterfaceResourceName)

if v, ok := d.GetOk("network_security_group_id"); ok {
networkSecurityGroupId := v.(string)
networkSecurityGroupName, err := parseNetworkSecurityGroupName(networkSecurityGroupId)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
package azurerm

import (
"fmt"
"log"
"strings"

"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-04-01/network"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func resourceArmNetworkInterfaceBackendAddressPoolAssociation() *schema.Resource {
return &schema.Resource{
Create: resourceArmNetworkInterfaceBackendAddressPoolAssociationCreate,
Read: resourceArmNetworkInterfaceBackendAddressPoolAssociationRead,
Delete: resourceArmNetworkInterfaceBackendAddressPoolAssociationDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"network_interface_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: azure.ValidateResourceID,
},

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

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

func resourceArmNetworkInterfaceBackendAddressPoolAssociationCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).ifaceClient
ctx := meta.(*ArmClient).StopContext

log.Printf("[INFO] preparing arguments for Network Interface <-> Load Balancer Backend Address Pool Association creation.")

networkInterfaceId := d.Get("network_interface_id").(string)
ipConfigurationName := d.Get("ip_configuration_name").(string)
backendAddressPoolId := d.Get("backend_address_pool_id").(string)

id, err := parseAzureResourceID(networkInterfaceId)
if err != nil {
return err
}

networkInterfaceName := id.Path["networkInterfaces"]
resourceGroup := id.ResourceGroup

azureRMLockByName(networkInterfaceName, networkInterfaceResourceName)
defer azureRMUnlockByName(networkInterfaceName, networkInterfaceResourceName)

read, err := client.Get(ctx, resourceGroup, networkInterfaceName, "")
if err != nil {
if utils.ResponseWasNotFound(read.Response) {
return fmt.Errorf("Network Interface %q (Resource Group %q) was not found!", networkInterfaceName, resourceGroup)
}

return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err)
}

props := read.InterfacePropertiesFormat
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)
}

pools := make([]network.BackendAddressPool, 0)

// first double-check it doesn't exist
if p.LoadBalancerBackendAddressPools != nil {
for _, existingPool := range *p.LoadBalancerBackendAddressPools {
if id := existingPool.ID; id != nil {
if *id == backendAddressPoolId {
// TODO: switch to using the common error once https://github.com/terraform-providers/terraform-provider-azurerm/pull/1746 is merged
return fmt.Errorf("A Network Interface <-> Load Balancer Backend Address Pool association exists between %q and %q - please import it!", networkInterfaceId, backendAddressPoolId)
}

pools = append(pools, existingPool)
}
}
}

pool := network.BackendAddressPool{
ID: utils.String(backendAddressPoolId),
}
pools = append(pools, pool)
p.LoadBalancerBackendAddressPools = &pools

props.IPConfigurations = azure.UpdateNetworkInterfaceIPConfiguration(config, props.IPConfigurations)

future, err := client.CreateOrUpdate(ctx, resourceGroup, networkInterfaceName, read)
if err != nil {
return fmt.Errorf("Error updating Backend Address Pool Association for Network Interface %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err)
}

err = future.WaitForCompletionRef(ctx, client.Client)
if err != nil {
return fmt.Errorf("Error waiting for completion of Backend Address Pool Association for NIC %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err)
}

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

return resourceArmNetworkInterfaceBackendAddressPoolAssociationRead(d, meta)
}

func resourceArmNetworkInterfaceBackendAddressPoolAssociationRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).ifaceClient
ctx := meta.(*ArmClient).StopContext

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

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

ipConfigurationName := nicID.Path["ipConfigurations"]
networkInterfaceName := nicID.Path["networkInterfaces"]
resourceGroup := nicID.ResourceGroup
backendAddressPoolId := splitId[1]

read, err := client.Get(ctx, resourceGroup, networkInterfaceName, "")
if err != nil {
if utils.ResponseWasNotFound(read.Response) {
return fmt.Errorf("Network Interface %q (Resource Group %q) was not found!", networkInterfaceName, resourceGroup)
}

return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err)
}

nicProps := read.InterfacePropertiesFormat
if nicProps == 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 {
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 backendPools := props.LoadBalancerBackendAddressPools; backendPools != nil {
for _, pool := range *backendPools {
if pool.ID == nil {
continue
}

if *pool.ID == backendAddressPoolId {
found = true
break
}
}
}
}

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

d.Set("backend_address_pool_id", backendAddressPoolId)
d.Set("ip_configuration_name", ipConfigurationName)
if id := read.ID; id != nil {
d.Set("network_interface_id", *id)
}

return nil
}

func resourceArmNetworkInterfaceBackendAddressPoolAssociationDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).ifaceClient
ctx := meta.(*ArmClient).StopContext

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

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

ipConfigurationName := nicID.Path["ipConfigurations"]
networkInterfaceName := nicID.Path["networkInterfaces"]
resourceGroup := nicID.ResourceGroup
backendAddressPoolId := splitId[1]

azureRMLockByName(networkInterfaceName, networkInterfaceResourceName)
defer azureRMUnlockByName(networkInterfaceName, networkInterfaceResourceName)

read, err := client.Get(ctx, resourceGroup, networkInterfaceName, "")
if err != nil {
if utils.ResponseWasNotFound(read.Response) {
return fmt.Errorf("Network Interface %q (Resource Group %q) was not found!", networkInterfaceName, resourceGroup)
}

return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err)
}

nicProps := read.InterfacePropertiesFormat
if nicProps == 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)
}

backendAddressPools := make([]network.BackendAddressPool, 0)
if backendPools := props.LoadBalancerBackendAddressPools; backendPools != nil {
for _, pool := range *backendPools {
if pool.ID == nil {
continue
}

if *pool.ID != backendAddressPoolId {
backendAddressPools = append(backendAddressPools, pool)
}
}
}
props.LoadBalancerBackendAddressPools = &backendAddressPools
nicProps.IPConfigurations = azure.UpdateNetworkInterfaceIPConfiguration(config, nicProps.IPConfigurations)

future, err := client.CreateOrUpdate(ctx, resourceGroup, networkInterfaceName, read)
if err != nil {
return fmt.Errorf("Error removing Backend Address Pool Association for Network Interface %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err)
}

err = future.WaitForCompletionRef(ctx, client.Client)
if err != nil {
return fmt.Errorf("Error waiting for removal of Backend Address Pool Association for NIC %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err)
}

return nil
}
Loading