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