github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/azurerm/resource_arm_virtual_network.go (about)

     1  package azurerm
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"net/http"
     7  
     8  	"github.com/Azure/azure-sdk-for-go/arm/network"
     9  	"github.com/hashicorp/terraform/helper/hashcode"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  )
    12  
    13  func resourceArmVirtualNetwork() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourceArmVirtualNetworkCreate,
    16  		Read:   resourceArmVirtualNetworkRead,
    17  		Update: resourceArmVirtualNetworkCreate,
    18  		Delete: resourceArmVirtualNetworkDelete,
    19  		Importer: &schema.ResourceImporter{
    20  			State: schema.ImportStatePassthrough,
    21  		},
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"name": {
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  
    30  			"address_space": {
    31  				Type:     schema.TypeList,
    32  				Required: true,
    33  				Elem: &schema.Schema{
    34  					Type: schema.TypeString,
    35  				},
    36  			},
    37  
    38  			"dns_servers": {
    39  				Type:     schema.TypeList,
    40  				Optional: true,
    41  				Elem: &schema.Schema{
    42  					Type: schema.TypeString,
    43  				},
    44  			},
    45  
    46  			"subnet": {
    47  				Type:     schema.TypeSet,
    48  				Optional: true,
    49  				Computed: true,
    50  				Elem: &schema.Resource{
    51  					Schema: map[string]*schema.Schema{
    52  						"name": {
    53  							Type:     schema.TypeString,
    54  							Required: true,
    55  						},
    56  						"address_prefix": {
    57  							Type:     schema.TypeString,
    58  							Required: true,
    59  						},
    60  						"security_group": {
    61  							Type:     schema.TypeString,
    62  							Optional: true,
    63  						},
    64  					},
    65  				},
    66  				Set: resourceAzureSubnetHash,
    67  			},
    68  
    69  			"location": locationSchema(),
    70  
    71  			"resource_group_name": {
    72  				Type:     schema.TypeString,
    73  				Required: true,
    74  				ForceNew: true,
    75  			},
    76  
    77  			"tags": tagsSchema(),
    78  		},
    79  	}
    80  }
    81  
    82  func resourceArmVirtualNetworkCreate(d *schema.ResourceData, meta interface{}) error {
    83  	client := meta.(*ArmClient)
    84  	vnetClient := client.vnetClient
    85  
    86  	log.Printf("[INFO] preparing arguments for Azure ARM virtual network creation.")
    87  
    88  	name := d.Get("name").(string)
    89  	location := d.Get("location").(string)
    90  	resGroup := d.Get("resource_group_name").(string)
    91  	tags := d.Get("tags").(map[string]interface{})
    92  
    93  	vnet := network.VirtualNetwork{
    94  		Name:                           &name,
    95  		Location:                       &location,
    96  		VirtualNetworkPropertiesFormat: getVirtualNetworkProperties(d),
    97  		Tags: expandTags(tags),
    98  	}
    99  
   100  	networkSecurityGroupNames := make([]string, 0)
   101  	for _, subnet := range *vnet.VirtualNetworkPropertiesFormat.Subnets {
   102  		if subnet.NetworkSecurityGroup != nil {
   103  			nsgName, err := parseNetworkSecurityGroupName(*subnet.NetworkSecurityGroup.ID)
   104  			if err != nil {
   105  				return err
   106  			}
   107  
   108  			networkSecurityGroupNames = append(networkSecurityGroupNames, nsgName)
   109  		}
   110  	}
   111  
   112  	azureRMVirtualNetworkLockNetworkSecurityGroups(&networkSecurityGroupNames)
   113  	defer azureRMVirtualNetworkUnlockNetworkSecurityGroups(&networkSecurityGroupNames)
   114  
   115  	_, err := vnetClient.CreateOrUpdate(resGroup, name, vnet, make(chan struct{}))
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	read, err := vnetClient.Get(resGroup, name, "")
   121  	if err != nil {
   122  		return err
   123  	}
   124  	if read.ID == nil {
   125  		return fmt.Errorf("Cannot read Virtual Network %s (resource group %s) ID", name, resGroup)
   126  	}
   127  
   128  	d.SetId(*read.ID)
   129  
   130  	return resourceArmVirtualNetworkRead(d, meta)
   131  }
   132  
   133  func resourceArmVirtualNetworkRead(d *schema.ResourceData, meta interface{}) error {
   134  	vnetClient := meta.(*ArmClient).vnetClient
   135  
   136  	id, err := parseAzureResourceID(d.Id())
   137  	if err != nil {
   138  		return err
   139  	}
   140  	resGroup := id.ResourceGroup
   141  	name := id.Path["virtualNetworks"]
   142  
   143  	resp, err := vnetClient.Get(resGroup, name, "")
   144  	if err != nil {
   145  		if resp.StatusCode == http.StatusNotFound {
   146  			d.SetId("")
   147  			return nil
   148  		}
   149  		return fmt.Errorf("Error making Read request on Azure virtual network %s: %s", name, err)
   150  	}
   151  
   152  	vnet := *resp.VirtualNetworkPropertiesFormat
   153  
   154  	// update appropriate values
   155  	d.Set("resource_group_name", resGroup)
   156  	d.Set("name", resp.Name)
   157  	d.Set("location", resp.Location)
   158  	d.Set("address_space", vnet.AddressSpace.AddressPrefixes)
   159  
   160  	subnets := &schema.Set{
   161  		F: resourceAzureSubnetHash,
   162  	}
   163  
   164  	for _, subnet := range *vnet.Subnets {
   165  		s := map[string]interface{}{}
   166  
   167  		s["name"] = *subnet.Name
   168  		s["address_prefix"] = *subnet.SubnetPropertiesFormat.AddressPrefix
   169  		if subnet.SubnetPropertiesFormat.NetworkSecurityGroup != nil {
   170  			s["security_group"] = *subnet.SubnetPropertiesFormat.NetworkSecurityGroup.ID
   171  		}
   172  
   173  		subnets.Add(s)
   174  	}
   175  	d.Set("subnet", subnets)
   176  
   177  	if vnet.DhcpOptions != nil && vnet.DhcpOptions.DNSServers != nil {
   178  		dnses := []string{}
   179  		for _, dns := range *vnet.DhcpOptions.DNSServers {
   180  			dnses = append(dnses, dns)
   181  		}
   182  		d.Set("dns_servers", dnses)
   183  	}
   184  
   185  	flattenAndSetTags(d, resp.Tags)
   186  
   187  	return nil
   188  }
   189  
   190  func resourceArmVirtualNetworkDelete(d *schema.ResourceData, meta interface{}) error {
   191  	vnetClient := meta.(*ArmClient).vnetClient
   192  
   193  	id, err := parseAzureResourceID(d.Id())
   194  	if err != nil {
   195  		return err
   196  	}
   197  	resGroup := id.ResourceGroup
   198  	name := id.Path["virtualNetworks"]
   199  
   200  	nsgNames, err := expandAzureRmVirtualNetworkVirtualNetworkSecurityGroupNames(d)
   201  	if err != nil {
   202  		return fmt.Errorf("[ERROR] Error parsing Network Security Group ID's: %+v", err)
   203  	}
   204  
   205  	azureRMVirtualNetworkLockNetworkSecurityGroups(&nsgNames)
   206  	defer azureRMVirtualNetworkUnlockNetworkSecurityGroups(&nsgNames)
   207  
   208  	_, err = vnetClient.Delete(resGroup, name, make(chan struct{}))
   209  
   210  	return err
   211  }
   212  
   213  func getVirtualNetworkProperties(d *schema.ResourceData) *network.VirtualNetworkPropertiesFormat {
   214  	// first; get address space prefixes:
   215  	prefixes := []string{}
   216  	for _, prefix := range d.Get("address_space").([]interface{}) {
   217  		prefixes = append(prefixes, prefix.(string))
   218  	}
   219  
   220  	// then; the dns servers:
   221  	dnses := []string{}
   222  	for _, dns := range d.Get("dns_servers").([]interface{}) {
   223  		dnses = append(dnses, dns.(string))
   224  	}
   225  
   226  	// then; the subnets:
   227  	subnets := []network.Subnet{}
   228  	if subs := d.Get("subnet").(*schema.Set); subs.Len() > 0 {
   229  		for _, subnet := range subs.List() {
   230  			subnet := subnet.(map[string]interface{})
   231  
   232  			name := subnet["name"].(string)
   233  			prefix := subnet["address_prefix"].(string)
   234  			secGroup := subnet["security_group"].(string)
   235  
   236  			var subnetObj network.Subnet
   237  			subnetObj.Name = &name
   238  			subnetObj.SubnetPropertiesFormat = &network.SubnetPropertiesFormat{}
   239  			subnetObj.SubnetPropertiesFormat.AddressPrefix = &prefix
   240  
   241  			if secGroup != "" {
   242  				subnetObj.SubnetPropertiesFormat.NetworkSecurityGroup = &network.SecurityGroup{
   243  					ID: &secGroup,
   244  				}
   245  			}
   246  
   247  			subnets = append(subnets, subnetObj)
   248  		}
   249  	}
   250  
   251  	// finally; return the struct:
   252  	return &network.VirtualNetworkPropertiesFormat{
   253  		AddressSpace: &network.AddressSpace{
   254  			AddressPrefixes: &prefixes,
   255  		},
   256  		DhcpOptions: &network.DhcpOptions{
   257  			DNSServers: &dnses,
   258  		},
   259  		Subnets: &subnets,
   260  	}
   261  }
   262  
   263  func resourceAzureSubnetHash(v interface{}) int {
   264  	m := v.(map[string]interface{})
   265  	subnet := m["name"].(string) + m["address_prefix"].(string)
   266  	if securityGroup, present := m["security_group"]; present {
   267  		subnet = subnet + securityGroup.(string)
   268  	}
   269  	return hashcode.String(subnet)
   270  }
   271  
   272  func expandAzureRmVirtualNetworkVirtualNetworkSecurityGroupNames(d *schema.ResourceData) ([]string, error) {
   273  	nsgNames := make([]string, 0)
   274  
   275  	if v, ok := d.GetOk("subnet"); ok {
   276  		subnets := v.(*schema.Set).List()
   277  		for _, subnet := range subnets {
   278  			subnet, ok := subnet.(map[string]interface{})
   279  			if !ok {
   280  				return nil, fmt.Errorf("[ERROR] Subnet should be a Hash - was '%+v'", subnet)
   281  			}
   282  
   283  			networkSecurityGroupId := subnet["security_group"].(string)
   284  			if networkSecurityGroupId != "" {
   285  				nsgName, err := parseNetworkSecurityGroupName(networkSecurityGroupId)
   286  				if err != nil {
   287  					return nil, err
   288  				}
   289  
   290  				nsgNames = append(nsgNames, nsgName)
   291  			}
   292  		}
   293  	}
   294  
   295  	return nsgNames, nil
   296  }
   297  
   298  func azureRMVirtualNetworkUnlockNetworkSecurityGroups(networkSecurityGroupNames *[]string) {
   299  	for _, networkSecurityGroupName := range *networkSecurityGroupNames {
   300  		armMutexKV.Unlock(networkSecurityGroupName)
   301  	}
   302  }
   303  func azureRMVirtualNetworkLockNetworkSecurityGroups(networkSecurityGroupNames *[]string) {
   304  	for _, networkSecurityGroupName := range *networkSecurityGroupNames {
   305  		armMutexKV.Lock(networkSecurityGroupName)
   306  	}
   307  }