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