github.com/bendemaree/terraform@v0.5.4-0.20150613200311-f50d97d6eee6/builtin/providers/azure/resource_azure_virtual_network.go (about)

     1  package azure
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  
     8  	"github.com/Azure/azure-sdk-for-go/management"
     9  	"github.com/Azure/azure-sdk-for-go/management/networksecuritygroup"
    10  	"github.com/Azure/azure-sdk-for-go/management/virtualnetwork"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  const (
    16  	virtualNetworkRetrievalError = "Error retrieving Virtual Network Configuration: %s"
    17  )
    18  
    19  func resourceAzureVirtualNetwork() *schema.Resource {
    20  	return &schema.Resource{
    21  		Create: resourceAzureVirtualNetworkCreate,
    22  		Read:   resourceAzureVirtualNetworkRead,
    23  		Update: resourceAzureVirtualNetworkUpdate,
    24  		Delete: resourceAzureVirtualNetworkDelete,
    25  
    26  		Schema: map[string]*schema.Schema{
    27  			"name": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Required: true,
    30  				ForceNew: true,
    31  			},
    32  
    33  			"address_space": &schema.Schema{
    34  				Type:     schema.TypeList,
    35  				Required: true,
    36  				Elem:     &schema.Schema{Type: schema.TypeString},
    37  			},
    38  
    39  			"dns_servers_names": &schema.Schema{
    40  				Type:     schema.TypeList,
    41  				Optional: true,
    42  				Elem: &schema.Schema{
    43  					Type: schema.TypeString,
    44  				},
    45  			},
    46  
    47  			"subnet": &schema.Schema{
    48  				Type:     schema.TypeSet,
    49  				Required: true,
    50  				Elem: &schema.Resource{
    51  					Schema: map[string]*schema.Schema{
    52  						"name": &schema.Schema{
    53  							Type:     schema.TypeString,
    54  							Required: true,
    55  						},
    56  						"address_prefix": &schema.Schema{
    57  							Type:     schema.TypeString,
    58  							Required: true,
    59  						},
    60  						"security_group": &schema.Schema{
    61  							Type:     schema.TypeString,
    62  							Optional: true,
    63  						},
    64  					},
    65  				},
    66  				Set: resourceAzureSubnetHash,
    67  			},
    68  
    69  			"location": &schema.Schema{
    70  				Type:     schema.TypeString,
    71  				Required: true,
    72  				ForceNew: true,
    73  			},
    74  		},
    75  	}
    76  }
    77  
    78  func resourceAzureVirtualNetworkCreate(d *schema.ResourceData, meta interface{}) error {
    79  	ac := meta.(*Client)
    80  	mc := ac.mgmtClient
    81  
    82  	name := d.Get("name").(string)
    83  
    84  	// Lock the client just before we get the virtual network configuration and immediately
    85  	// set an defer to unlock the client again whenever this function exits
    86  	ac.mutex.Lock()
    87  	defer ac.mutex.Unlock()
    88  
    89  	nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration()
    90  	if err != nil {
    91  		if strings.Contains(err.Error(), "ResourceNotFound") {
    92  			nc = virtualnetwork.NetworkConfiguration{}
    93  		} else {
    94  			return fmt.Errorf(virtualNetworkRetrievalError, err)
    95  		}
    96  	}
    97  
    98  	for _, n := range nc.Configuration.VirtualNetworkSites {
    99  		if n.Name == name {
   100  			return fmt.Errorf("Virtual Network %s already exists!", name)
   101  		}
   102  	}
   103  
   104  	network := createVirtualNetwork(d)
   105  	nc.Configuration.VirtualNetworkSites = append(nc.Configuration.VirtualNetworkSites, network)
   106  
   107  	req, err := virtualnetwork.NewClient(mc).SetVirtualNetworkConfiguration(nc)
   108  	if err != nil {
   109  		return fmt.Errorf("Error creating Virtual Network %s: %s", name, err)
   110  	}
   111  
   112  	// Wait until the virtual network is created
   113  	if err := mc.WaitForOperation(req, nil); err != nil {
   114  		return fmt.Errorf("Error waiting for Virtual Network %s to be created: %s", name, err)
   115  	}
   116  
   117  	d.SetId(name)
   118  
   119  	if err := associateSecurityGroups(d, meta); err != nil {
   120  		return err
   121  	}
   122  
   123  	return resourceAzureVirtualNetworkRead(d, meta)
   124  }
   125  
   126  func resourceAzureVirtualNetworkRead(d *schema.ResourceData, meta interface{}) error {
   127  	mc := meta.(*Client).mgmtClient
   128  
   129  	nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration()
   130  	if err != nil {
   131  		return fmt.Errorf(virtualNetworkRetrievalError, err)
   132  	}
   133  
   134  	for _, n := range nc.Configuration.VirtualNetworkSites {
   135  		if n.Name == d.Id() {
   136  			d.Set("address_space", n.AddressSpace.AddressPrefix)
   137  			d.Set("location", n.Location)
   138  
   139  			// Create a new set to hold all configured subnets
   140  			subnets := &schema.Set{
   141  				F: resourceAzureSubnetHash,
   142  			}
   143  
   144  			// Loop through all endpoints
   145  			for _, s := range n.Subnets {
   146  				subnet := map[string]interface{}{}
   147  
   148  				// Get the associated (if any) security group
   149  				sg, err := networksecuritygroup.NewClient(mc).
   150  					GetNetworkSecurityGroupForSubnet(s.Name, d.Id())
   151  				if err != nil && !management.IsResourceNotFoundError(err) {
   152  					return fmt.Errorf(
   153  						"Error retrieving Network Security Group associations of subnet %s: %s", s.Name, err)
   154  				}
   155  
   156  				// Update the values
   157  				subnet["name"] = s.Name
   158  				subnet["address_prefix"] = s.AddressPrefix
   159  				subnet["security_group"] = sg.Name
   160  
   161  				subnets.Add(subnet)
   162  			}
   163  
   164  			d.Set("subnet", subnets)
   165  
   166  			return nil
   167  		}
   168  	}
   169  
   170  	log.Printf("[DEBUG] Virtual Network %s does no longer exist", d.Id())
   171  	d.SetId("")
   172  
   173  	return nil
   174  }
   175  
   176  func resourceAzureVirtualNetworkUpdate(d *schema.ResourceData, meta interface{}) error {
   177  	ac := meta.(*Client)
   178  	mc := ac.mgmtClient
   179  
   180  	// Lock the client just before we get the virtual network configuration and immediately
   181  	// set an defer to unlock the client again whenever this function exits
   182  	ac.mutex.Lock()
   183  	defer ac.mutex.Unlock()
   184  
   185  	nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration()
   186  	if err != nil {
   187  		return fmt.Errorf(virtualNetworkRetrievalError, err)
   188  	}
   189  
   190  	found := false
   191  	for i, n := range nc.Configuration.VirtualNetworkSites {
   192  		if n.Name == d.Id() {
   193  			network := createVirtualNetwork(d)
   194  			nc.Configuration.VirtualNetworkSites[i] = network
   195  
   196  			found = true
   197  		}
   198  	}
   199  
   200  	if !found {
   201  		return fmt.Errorf("Virtual Network %s does not exists!", d.Id())
   202  	}
   203  
   204  	req, err := virtualnetwork.NewClient(mc).SetVirtualNetworkConfiguration(nc)
   205  	if err != nil {
   206  		return fmt.Errorf("Error updating Virtual Network %s: %s", d.Id(), err)
   207  	}
   208  
   209  	// Wait until the virtual network is updated
   210  	if err := mc.WaitForOperation(req, nil); err != nil {
   211  		return fmt.Errorf("Error waiting for Virtual Network %s to be updated: %s", d.Id(), err)
   212  	}
   213  
   214  	if err := associateSecurityGroups(d, meta); err != nil {
   215  		return err
   216  	}
   217  
   218  	return resourceAzureVirtualNetworkRead(d, meta)
   219  }
   220  
   221  func resourceAzureVirtualNetworkDelete(d *schema.ResourceData, meta interface{}) error {
   222  	ac := meta.(*Client)
   223  	mc := ac.mgmtClient
   224  
   225  	// Lock the client just before we get the virtual network configuration and immediately
   226  	// set an defer to unlock the client again whenever this function exits
   227  	ac.mutex.Lock()
   228  	defer ac.mutex.Unlock()
   229  
   230  	nc, err := virtualnetwork.NewClient(mc).GetVirtualNetworkConfiguration()
   231  	if err != nil {
   232  		return fmt.Errorf(virtualNetworkRetrievalError, err)
   233  	}
   234  
   235  	filtered := nc.Configuration.VirtualNetworkSites[:0]
   236  	for _, n := range nc.Configuration.VirtualNetworkSites {
   237  		if n.Name != d.Id() {
   238  			filtered = append(filtered, n)
   239  		}
   240  	}
   241  
   242  	nc.Configuration.VirtualNetworkSites = filtered
   243  
   244  	req, err := virtualnetwork.NewClient(mc).SetVirtualNetworkConfiguration(nc)
   245  	if err != nil {
   246  		return fmt.Errorf("Error deleting Virtual Network %s: %s", d.Id(), err)
   247  	}
   248  
   249  	// Wait until the virtual network is deleted
   250  	if err := mc.WaitForOperation(req, nil); err != nil {
   251  		return fmt.Errorf("Error waiting for Virtual Network %s to be deleted: %s", d.Id(), err)
   252  	}
   253  
   254  	d.SetId("")
   255  
   256  	return nil
   257  }
   258  
   259  func resourceAzureSubnetHash(v interface{}) int {
   260  	m := v.(map[string]interface{})
   261  	subnet := m["name"].(string) + m["address_prefix"].(string) + m["security_group"].(string)
   262  	return hashcode.String(subnet)
   263  }
   264  
   265  func createVirtualNetwork(d *schema.ResourceData) virtualnetwork.VirtualNetworkSite {
   266  	// fetch address spaces:
   267  	var prefixes []string
   268  	for _, prefix := range d.Get("address_space").([]interface{}) {
   269  		prefixes = append(prefixes, prefix.(string))
   270  	}
   271  
   272  	// fetch DNS references:
   273  	var dnsRefs []virtualnetwork.DNSServerRef
   274  	for _, dns := range d.Get("dns_servers_names").([]interface{}) {
   275  		dnsRefs = append(dnsRefs, virtualnetwork.DNSServerRef{
   276  			Name: dns.(string),
   277  		})
   278  	}
   279  
   280  	// Add all subnets that are configured
   281  	var subnets []virtualnetwork.Subnet
   282  	if rs := d.Get("subnet").(*schema.Set); rs.Len() > 0 {
   283  		for _, subnet := range rs.List() {
   284  			subnet := subnet.(map[string]interface{})
   285  			subnets = append(subnets, virtualnetwork.Subnet{
   286  				Name:          subnet["name"].(string),
   287  				AddressPrefix: subnet["address_prefix"].(string),
   288  			})
   289  		}
   290  	}
   291  
   292  	return virtualnetwork.VirtualNetworkSite{
   293  		Name:     d.Get("name").(string),
   294  		Location: d.Get("location").(string),
   295  		AddressSpace: virtualnetwork.AddressSpace{
   296  			AddressPrefix: prefixes,
   297  		},
   298  		DNSServersRef: dnsRefs,
   299  		Subnets:       subnets,
   300  	}
   301  }
   302  
   303  func associateSecurityGroups(d *schema.ResourceData, meta interface{}) error {
   304  	mc := meta.(*Client).mgmtClient
   305  	nsgClient := networksecuritygroup.NewClient(mc)
   306  
   307  	virtualNetwork := d.Get("name").(string)
   308  
   309  	if rs := d.Get("subnet").(*schema.Set); rs.Len() > 0 {
   310  		for _, subnet := range rs.List() {
   311  			subnet := subnet.(map[string]interface{})
   312  			securityGroup := subnet["security_group"].(string)
   313  			subnetName := subnet["name"].(string)
   314  
   315  			// Get the associated (if any) security group
   316  			sg, err := nsgClient.GetNetworkSecurityGroupForSubnet(subnetName, d.Id())
   317  			if err != nil && !management.IsResourceNotFoundError(err) {
   318  				return fmt.Errorf(
   319  					"Error retrieving Network Security Group associations of subnet %s: %s", subnetName, err)
   320  			}
   321  
   322  			// If the desired and actual security group are the same, were done so can just continue
   323  			if sg.Name == securityGroup {
   324  				continue
   325  			}
   326  
   327  			// If there is an associated security group, make sure we first remove it from the subnet
   328  			if sg.Name != "" {
   329  				req, err := nsgClient.RemoveNetworkSecurityGroupFromSubnet(sg.Name, subnetName, virtualNetwork)
   330  				if err != nil {
   331  					return fmt.Errorf("Error removing Network Security Group %s from subnet %s: %s",
   332  						securityGroup, subnetName, err)
   333  				}
   334  
   335  				// Wait until the security group is associated
   336  				if err := mc.WaitForOperation(req, nil); err != nil {
   337  					return fmt.Errorf(
   338  						"Error waiting for Network Security Group %s to be removed from subnet %s: %s",
   339  						securityGroup, subnetName, err)
   340  				}
   341  			}
   342  
   343  			// If the desired security group is not empty, assign the security group to the subnet
   344  			if securityGroup != "" {
   345  				req, err := nsgClient.AddNetworkSecurityToSubnet(securityGroup, subnetName, virtualNetwork)
   346  				if err != nil {
   347  					return fmt.Errorf("Error associating Network Security Group %s to subnet %s: %s",
   348  						securityGroup, subnetName, err)
   349  				}
   350  
   351  				// Wait until the security group is associated
   352  				if err := mc.WaitForOperation(req, nil); err != nil {
   353  					return fmt.Errorf(
   354  						"Error waiting for Network Security Group %s to be associated with subnet %s: %s",
   355  						securityGroup, subnetName, err)
   356  				}
   357  			}
   358  
   359  		}
   360  	}
   361  
   362  	return nil
   363  }