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 }