github.com/sarguru/terraform@v0.6.17-0.20160525232901-8fcdfd7e3dc9/builtin/providers/azurerm/resource_arm_network_interface_card.go (about)

     1  package azurerm
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"net/http"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/Azure/azure-sdk-for-go/arm/network"
    12  	"github.com/hashicorp/terraform/helper/hashcode"
    13  	"github.com/hashicorp/terraform/helper/resource"
    14  	"github.com/hashicorp/terraform/helper/schema"
    15  )
    16  
    17  func resourceArmNetworkInterface() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceArmNetworkInterfaceCreate,
    20  		Read:   resourceArmNetworkInterfaceRead,
    21  		Update: resourceArmNetworkInterfaceCreate,
    22  		Delete: resourceArmNetworkInterfaceDelete,
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"name": &schema.Schema{
    26  				Type:     schema.TypeString,
    27  				Required: true,
    28  				ForceNew: true,
    29  			},
    30  
    31  			"location": &schema.Schema{
    32  				Type:      schema.TypeString,
    33  				Required:  true,
    34  				ForceNew:  true,
    35  				StateFunc: azureRMNormalizeLocation,
    36  			},
    37  
    38  			"resource_group_name": &schema.Schema{
    39  				Type:     schema.TypeString,
    40  				Required: true,
    41  				ForceNew: true,
    42  			},
    43  
    44  			"network_security_group_id": &schema.Schema{
    45  				Type:     schema.TypeString,
    46  				Optional: true,
    47  				Computed: true,
    48  			},
    49  
    50  			"mac_address": &schema.Schema{
    51  				Type:     schema.TypeString,
    52  				Optional: true,
    53  				Computed: true,
    54  			},
    55  
    56  			"private_ip_address": &schema.Schema{
    57  				Type:     schema.TypeString,
    58  				Computed: true,
    59  			},
    60  
    61  			"virtual_machine_id": &schema.Schema{
    62  				Type:     schema.TypeString,
    63  				Optional: true,
    64  				Computed: true,
    65  			},
    66  
    67  			"ip_configuration": &schema.Schema{
    68  				Type:     schema.TypeSet,
    69  				Required: true,
    70  				Elem: &schema.Resource{
    71  					Schema: map[string]*schema.Schema{
    72  						"name": &schema.Schema{
    73  							Type:     schema.TypeString,
    74  							Required: true,
    75  						},
    76  
    77  						"subnet_id": &schema.Schema{
    78  							Type:     schema.TypeString,
    79  							Required: true,
    80  						},
    81  
    82  						"private_ip_address": &schema.Schema{
    83  							Type:     schema.TypeString,
    84  							Optional: true,
    85  							Computed: true,
    86  						},
    87  
    88  						"private_ip_address_allocation": &schema.Schema{
    89  							Type:         schema.TypeString,
    90  							Required:     true,
    91  							ValidateFunc: validateNetworkInterfacePrivateIpAddressAllocation,
    92  						},
    93  
    94  						"public_ip_address_id": &schema.Schema{
    95  							Type:     schema.TypeString,
    96  							Optional: true,
    97  							Computed: true,
    98  						},
    99  
   100  						"load_balancer_backend_address_pools_ids": &schema.Schema{
   101  							Type:     schema.TypeSet,
   102  							Optional: true,
   103  							Computed: true,
   104  							Elem:     &schema.Schema{Type: schema.TypeString},
   105  							Set:      schema.HashString,
   106  						},
   107  
   108  						"load_balancer_inbound_nat_rules_ids": &schema.Schema{
   109  							Type:     schema.TypeSet,
   110  							Optional: true,
   111  							Computed: true,
   112  							Elem:     &schema.Schema{Type: schema.TypeString},
   113  							Set:      schema.HashString,
   114  						},
   115  					},
   116  				},
   117  				Set: resourceArmNetworkInterfaceIpConfigurationHash,
   118  			},
   119  
   120  			"dns_servers": &schema.Schema{
   121  				Type:     schema.TypeSet,
   122  				Optional: true,
   123  				Computed: true,
   124  				Elem:     &schema.Schema{Type: schema.TypeString},
   125  				Set:      schema.HashString,
   126  			},
   127  
   128  			"internal_dns_name_label": &schema.Schema{
   129  				Type:     schema.TypeString,
   130  				Optional: true,
   131  				Computed: true,
   132  			},
   133  
   134  			"applied_dns_servers": &schema.Schema{
   135  				Type:     schema.TypeSet,
   136  				Optional: true,
   137  				Computed: true,
   138  				Elem:     &schema.Schema{Type: schema.TypeString},
   139  				Set:      schema.HashString,
   140  			},
   141  
   142  			"internal_fqdn": &schema.Schema{
   143  				Type:     schema.TypeString,
   144  				Optional: true,
   145  				Computed: true,
   146  			},
   147  
   148  			"enable_ip_forwarding": &schema.Schema{
   149  				Type:     schema.TypeBool,
   150  				Optional: true,
   151  				Default:  false,
   152  			},
   153  
   154  			"tags": tagsSchema(),
   155  		},
   156  	}
   157  }
   158  
   159  func resourceArmNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) error {
   160  	client := meta.(*ArmClient)
   161  	ifaceClient := client.ifaceClient
   162  
   163  	log.Printf("[INFO] preparing arguments for Azure ARM Network Interface creation.")
   164  
   165  	name := d.Get("name").(string)
   166  	location := d.Get("location").(string)
   167  	resGroup := d.Get("resource_group_name").(string)
   168  	enableIpForwarding := d.Get("enable_ip_forwarding").(bool)
   169  	tags := d.Get("tags").(map[string]interface{})
   170  
   171  	properties := network.InterfacePropertiesFormat{
   172  		EnableIPForwarding: &enableIpForwarding,
   173  	}
   174  
   175  	if v, ok := d.GetOk("network_security_group_id"); ok {
   176  		nsgId := v.(string)
   177  		properties.NetworkSecurityGroup = &network.SecurityGroup{
   178  			ID: &nsgId,
   179  		}
   180  	}
   181  
   182  	dns, hasDns := d.GetOk("dns_servers")
   183  	nameLabel, hasNameLabel := d.GetOk("internal_dns_name_label")
   184  	if hasDns || hasNameLabel {
   185  		ifaceDnsSettings := network.InterfaceDNSSettings{}
   186  
   187  		if hasDns {
   188  			var dnsServers []string
   189  			dns := dns.(*schema.Set).List()
   190  			for _, v := range dns {
   191  				str := v.(string)
   192  				dnsServers = append(dnsServers, str)
   193  			}
   194  			ifaceDnsSettings.DNSServers = &dnsServers
   195  		}
   196  
   197  		if hasNameLabel {
   198  			name_label := nameLabel.(string)
   199  			ifaceDnsSettings.InternalDNSNameLabel = &name_label
   200  
   201  		}
   202  
   203  		properties.DNSSettings = &ifaceDnsSettings
   204  	}
   205  
   206  	ipConfigs, sgErr := expandAzureRmNetworkInterfaceIpConfigurations(d)
   207  	if sgErr != nil {
   208  		return fmt.Errorf("Error Building list of Network Interface IP Configurations: %s", sgErr)
   209  	}
   210  	if len(ipConfigs) > 0 {
   211  		properties.IPConfigurations = &ipConfigs
   212  	}
   213  
   214  	iface := network.Interface{
   215  		Name:       &name,
   216  		Location:   &location,
   217  		Properties: &properties,
   218  		Tags:       expandTags(tags),
   219  	}
   220  
   221  	resp, err := ifaceClient.CreateOrUpdate(resGroup, name, iface)
   222  	if err != nil {
   223  		return err
   224  	}
   225  
   226  	d.SetId(*resp.ID)
   227  
   228  	log.Printf("[DEBUG] Waiting for Network Interface (%s) to become available", name)
   229  	stateConf := &resource.StateChangeConf{
   230  		Pending: []string{"Accepted", "Updating"},
   231  		Target:  []string{"Succeeded"},
   232  		Refresh: networkInterfaceStateRefreshFunc(client, resGroup, name),
   233  		Timeout: 10 * time.Minute,
   234  	}
   235  	if _, err := stateConf.WaitForState(); err != nil {
   236  		return fmt.Errorf("Error waiting for Network Interface (%s) to become available: %s", name, err)
   237  	}
   238  
   239  	return resourceArmNetworkInterfaceRead(d, meta)
   240  }
   241  
   242  func resourceArmNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) error {
   243  	ifaceClient := meta.(*ArmClient).ifaceClient
   244  
   245  	id, err := parseAzureResourceID(d.Id())
   246  	if err != nil {
   247  		return err
   248  	}
   249  	resGroup := id.ResourceGroup
   250  	name := id.Path["networkInterfaces"]
   251  
   252  	resp, err := ifaceClient.Get(resGroup, name, "")
   253  	if resp.StatusCode == http.StatusNotFound {
   254  		d.SetId("")
   255  		return nil
   256  	}
   257  	if err != nil {
   258  		return fmt.Errorf("Error making Read request on Azure Network Interface %s: %s", name, err)
   259  	}
   260  
   261  	iface := *resp.Properties
   262  
   263  	if iface.MacAddress != nil {
   264  		if *iface.MacAddress != "" {
   265  			d.Set("mac_address", iface.MacAddress)
   266  		}
   267  	}
   268  
   269  	if iface.IPConfigurations != nil && len(*iface.IPConfigurations) > 0 {
   270  		var privateIPAddress *string
   271  		///TODO: Change this to a loop when https://github.com/Azure/azure-sdk-for-go/issues/259 is fixed
   272  		if (*iface.IPConfigurations)[0].Properties != nil {
   273  			privateIPAddress = (*iface.IPConfigurations)[0].Properties.PrivateIPAddress
   274  		}
   275  
   276  		if *privateIPAddress != "" {
   277  			d.Set("private_ip_address", *privateIPAddress)
   278  		}
   279  	}
   280  
   281  	if iface.VirtualMachine != nil {
   282  		if *iface.VirtualMachine.ID != "" {
   283  			d.Set("virtual_machine_id", *iface.VirtualMachine.ID)
   284  		}
   285  	}
   286  
   287  	if iface.DNSSettings != nil {
   288  		if iface.DNSSettings.AppliedDNSServers != nil && len(*iface.DNSSettings.AppliedDNSServers) > 0 {
   289  			dnsServers := make([]string, 0, len(*iface.DNSSettings.AppliedDNSServers))
   290  			for _, dns := range *iface.DNSSettings.AppliedDNSServers {
   291  				dnsServers = append(dnsServers, dns)
   292  			}
   293  
   294  			if err := d.Set("applied_dns_servers", dnsServers); err != nil {
   295  				return err
   296  			}
   297  		}
   298  
   299  		if iface.DNSSettings.InternalFqdn != nil && *iface.DNSSettings.InternalFqdn != "" {
   300  			d.Set("internal_fqdn", iface.DNSSettings.InternalFqdn)
   301  		}
   302  	}
   303  
   304  	flattenAndSetTags(d, resp.Tags)
   305  
   306  	return nil
   307  }
   308  
   309  func resourceArmNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
   310  	ifaceClient := meta.(*ArmClient).ifaceClient
   311  
   312  	id, err := parseAzureResourceID(d.Id())
   313  	if err != nil {
   314  		return err
   315  	}
   316  	resGroup := id.ResourceGroup
   317  	name := id.Path["networkInterfaces"]
   318  
   319  	_, err = ifaceClient.Delete(resGroup, name)
   320  
   321  	return err
   322  }
   323  
   324  func networkInterfaceStateRefreshFunc(client *ArmClient, resourceGroupName string, ifaceName string) resource.StateRefreshFunc {
   325  	return func() (interface{}, string, error) {
   326  		res, err := client.ifaceClient.Get(resourceGroupName, ifaceName, "")
   327  		if err != nil {
   328  			return nil, "", fmt.Errorf("Error issuing read request in networkInterfaceStateRefreshFunc to Azure ARM for network interace '%s' (RG: '%s'): %s", ifaceName, resourceGroupName, err)
   329  		}
   330  
   331  		return res, *res.Properties.ProvisioningState, nil
   332  	}
   333  }
   334  
   335  func resourceArmNetworkInterfaceIpConfigurationHash(v interface{}) int {
   336  	var buf bytes.Buffer
   337  	m := v.(map[string]interface{})
   338  	buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
   339  	buf.WriteString(fmt.Sprintf("%s-", m["subnet_id"].(string)))
   340  	if m["private_ip_address"] != nil {
   341  		buf.WriteString(fmt.Sprintf("%s-", m["private_ip_address"].(string)))
   342  	}
   343  	buf.WriteString(fmt.Sprintf("%s-", m["private_ip_address_allocation"].(string)))
   344  	if m["public_ip_address_id"] != nil {
   345  		buf.WriteString(fmt.Sprintf("%s-", m["public_ip_address_id"].(string)))
   346  	}
   347  
   348  	return hashcode.String(buf.String())
   349  }
   350  
   351  func validateNetworkInterfacePrivateIpAddressAllocation(v interface{}, k string) (ws []string, errors []error) {
   352  	value := strings.ToLower(v.(string))
   353  	allocations := map[string]bool{
   354  		"static":  true,
   355  		"dynamic": true,
   356  	}
   357  
   358  	if !allocations[value] {
   359  		errors = append(errors, fmt.Errorf("Network Interface Allocations can only be Static or Dynamic"))
   360  	}
   361  	return
   362  }
   363  
   364  func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]network.InterfaceIPConfiguration, error) {
   365  	configs := d.Get("ip_configuration").(*schema.Set).List()
   366  	ipConfigs := make([]network.InterfaceIPConfiguration, 0, len(configs))
   367  
   368  	for _, configRaw := range configs {
   369  		data := configRaw.(map[string]interface{})
   370  
   371  		subnet_id := data["subnet_id"].(string)
   372  		private_ip_allocation_method := data["private_ip_address_allocation"].(string)
   373  
   374  		properties := network.InterfaceIPConfigurationPropertiesFormat{
   375  			Subnet: &network.Subnet{
   376  				ID: &subnet_id,
   377  			},
   378  			PrivateIPAllocationMethod: &private_ip_allocation_method,
   379  		}
   380  
   381  		if v := data["private_ip_address"].(string); v != "" {
   382  			properties.PrivateIPAddress = &v
   383  		}
   384  
   385  		if v := data["public_ip_address_id"].(string); v != "" {
   386  			properties.PublicIPAddress = &network.PublicIPAddress{
   387  				ID: &v,
   388  			}
   389  		}
   390  
   391  		if v, ok := data["load_balancer_backend_address_pools_ids"]; ok {
   392  			var ids []network.BackendAddressPool
   393  			pools := v.(*schema.Set).List()
   394  			for _, p := range pools {
   395  				pool_id := p.(string)
   396  				id := network.BackendAddressPool{
   397  					ID: &pool_id,
   398  				}
   399  
   400  				ids = append(ids, id)
   401  			}
   402  
   403  			properties.LoadBalancerBackendAddressPools = &ids
   404  		}
   405  
   406  		if v, ok := data["load_balancer_inbound_nat_rules_ids"]; ok {
   407  			var natRules []network.InboundNatRule
   408  			rules := v.(*schema.Set).List()
   409  			for _, r := range rules {
   410  				rule_id := r.(string)
   411  				rule := network.InboundNatRule{
   412  					ID: &rule_id,
   413  				}
   414  
   415  				natRules = append(natRules, rule)
   416  			}
   417  
   418  			properties.LoadBalancerInboundNatRules = &natRules
   419  		}
   420  
   421  		name := data["name"].(string)
   422  		ipConfig := network.InterfaceIPConfiguration{
   423  			Name:       &name,
   424  			Properties: &properties,
   425  		}
   426  
   427  		ipConfigs = append(ipConfigs, ipConfig)
   428  	}
   429  
   430  	return ipConfigs, nil
   431  }