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