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 }