github.com/joshgarnett/terraform@v0.5.4-0.20160219181435-92dc20bb3594/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go (about) 1 package openstack 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/hashicorp/terraform/helper/resource" 9 "github.com/hashicorp/terraform/helper/schema" 10 11 "github.com/rackspace/gophercloud" 12 "github.com/rackspace/gophercloud/openstack/networking/v2/subnets" 13 ) 14 15 func resourceNetworkingSubnetV2() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceNetworkingSubnetV2Create, 18 Read: resourceNetworkingSubnetV2Read, 19 Update: resourceNetworkingSubnetV2Update, 20 Delete: resourceNetworkingSubnetV2Delete, 21 22 Schema: map[string]*schema.Schema{ 23 "region": &schema.Schema{ 24 Type: schema.TypeString, 25 Required: true, 26 ForceNew: true, 27 DefaultFunc: envDefaultFuncAllowMissing("OS_REGION_NAME"), 28 }, 29 "network_id": &schema.Schema{ 30 Type: schema.TypeString, 31 Required: true, 32 ForceNew: true, 33 }, 34 "cidr": &schema.Schema{ 35 Type: schema.TypeString, 36 Required: true, 37 ForceNew: true, 38 }, 39 "name": &schema.Schema{ 40 Type: schema.TypeString, 41 Optional: true, 42 ForceNew: false, 43 }, 44 "tenant_id": &schema.Schema{ 45 Type: schema.TypeString, 46 Optional: true, 47 ForceNew: true, 48 Computed: true, 49 }, 50 "allocation_pools": &schema.Schema{ 51 Type: schema.TypeList, 52 Optional: true, 53 ForceNew: true, 54 Elem: &schema.Resource{ 55 Schema: map[string]*schema.Schema{ 56 "start": &schema.Schema{ 57 Type: schema.TypeString, 58 Required: true, 59 }, 60 "end": &schema.Schema{ 61 Type: schema.TypeString, 62 Required: true, 63 }, 64 }, 65 }, 66 }, 67 "gateway_ip": &schema.Schema{ 68 Type: schema.TypeString, 69 Optional: true, 70 ForceNew: false, 71 Computed: true, 72 }, 73 "ip_version": &schema.Schema{ 74 Type: schema.TypeInt, 75 Optional: true, 76 Default: 4, 77 ForceNew: true, 78 }, 79 "enable_dhcp": &schema.Schema{ 80 Type: schema.TypeBool, 81 Optional: true, 82 ForceNew: false, 83 Computed: true, 84 }, 85 "dns_nameservers": &schema.Schema{ 86 Type: schema.TypeSet, 87 Optional: true, 88 ForceNew: false, 89 Elem: &schema.Schema{Type: schema.TypeString}, 90 Set: schema.HashString, 91 }, 92 "host_routes": &schema.Schema{ 93 Type: schema.TypeList, 94 Optional: true, 95 ForceNew: false, 96 Elem: &schema.Resource{ 97 Schema: map[string]*schema.Schema{ 98 "destination_cidr": &schema.Schema{ 99 Type: schema.TypeString, 100 Required: true, 101 }, 102 "next_hop": &schema.Schema{ 103 Type: schema.TypeString, 104 Required: true, 105 }, 106 }, 107 }, 108 }, 109 }, 110 } 111 } 112 113 func resourceNetworkingSubnetV2Create(d *schema.ResourceData, meta interface{}) error { 114 config := meta.(*Config) 115 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 116 if err != nil { 117 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 118 } 119 120 createOpts := subnets.CreateOpts{ 121 NetworkID: d.Get("network_id").(string), 122 CIDR: d.Get("cidr").(string), 123 Name: d.Get("name").(string), 124 TenantID: d.Get("tenant_id").(string), 125 AllocationPools: resourceSubnetAllocationPoolsV2(d), 126 GatewayIP: d.Get("gateway_ip").(string), 127 IPVersion: d.Get("ip_version").(int), 128 DNSNameservers: resourceSubnetDNSNameserversV2(d), 129 HostRoutes: resourceSubnetHostRoutesV2(d), 130 } 131 132 if raw, ok := d.GetOk("enable_dhcp"); ok { 133 value := raw.(bool) 134 createOpts.EnableDHCP = &value 135 } 136 137 log.Printf("[DEBUG] Create Options: %#v", createOpts) 138 s, err := subnets.Create(networkingClient, createOpts).Extract() 139 if err != nil { 140 return fmt.Errorf("Error creating OpenStack Neutron subnet: %s", err) 141 } 142 log.Printf("[INFO] Subnet ID: %s", s.ID) 143 144 log.Printf("[DEBUG] Waiting for Subnet (%s) to become available", s.ID) 145 stateConf := &resource.StateChangeConf{ 146 Target: []string{"ACTIVE"}, 147 Refresh: waitForSubnetActive(networkingClient, s.ID), 148 Timeout: 2 * time.Minute, 149 Delay: 5 * time.Second, 150 MinTimeout: 3 * time.Second, 151 } 152 153 _, err = stateConf.WaitForState() 154 155 d.SetId(s.ID) 156 157 return resourceNetworkingSubnetV2Read(d, meta) 158 } 159 160 func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) error { 161 config := meta.(*Config) 162 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 163 if err != nil { 164 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 165 } 166 167 s, err := subnets.Get(networkingClient, d.Id()).Extract() 168 if err != nil { 169 return CheckDeleted(d, err, "subnet") 170 } 171 172 log.Printf("[DEBUG] Retreived Subnet %s: %+v", d.Id(), s) 173 174 d.Set("newtork_id", s.NetworkID) 175 d.Set("cidr", s.CIDR) 176 d.Set("ip_version", s.IPVersion) 177 d.Set("name", s.Name) 178 d.Set("tenant_id", s.TenantID) 179 d.Set("allocation_pools", s.AllocationPools) 180 d.Set("gateway_ip", s.GatewayIP) 181 d.Set("enable_dhcp", s.EnableDHCP) 182 d.Set("dns_nameservers", s.DNSNameservers) 183 d.Set("host_routes", s.HostRoutes) 184 185 return nil 186 } 187 188 func resourceNetworkingSubnetV2Update(d *schema.ResourceData, meta interface{}) error { 189 config := meta.(*Config) 190 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 191 if err != nil { 192 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 193 } 194 195 var updateOpts subnets.UpdateOpts 196 197 if d.HasChange("name") { 198 updateOpts.Name = d.Get("name").(string) 199 } 200 201 if d.HasChange("gateway_ip") { 202 updateOpts.GatewayIP = d.Get("gateway_ip").(string) 203 } 204 205 if d.HasChange("dns_nameservers") { 206 updateOpts.DNSNameservers = resourceSubnetDNSNameserversV2(d) 207 } 208 209 if d.HasChange("host_routes") { 210 updateOpts.HostRoutes = resourceSubnetHostRoutesV2(d) 211 } 212 213 if d.HasChange("enable_dhcp") { 214 v := d.Get("enable_dhcp").(bool) 215 updateOpts.EnableDHCP = &v 216 } 217 218 log.Printf("[DEBUG] Updating Subnet %s with options: %+v", d.Id(), updateOpts) 219 220 _, err = subnets.Update(networkingClient, d.Id(), updateOpts).Extract() 221 if err != nil { 222 return fmt.Errorf("Error updating OpenStack Neutron Subnet: %s", err) 223 } 224 225 return resourceNetworkingSubnetV2Read(d, meta) 226 } 227 228 func resourceNetworkingSubnetV2Delete(d *schema.ResourceData, meta interface{}) error { 229 config := meta.(*Config) 230 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 231 if err != nil { 232 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 233 } 234 235 stateConf := &resource.StateChangeConf{ 236 Pending: []string{"ACTIVE"}, 237 Target: []string{"DELETED"}, 238 Refresh: waitForSubnetDelete(networkingClient, d.Id()), 239 Timeout: 2 * time.Minute, 240 Delay: 5 * time.Second, 241 MinTimeout: 3 * time.Second, 242 } 243 244 _, err = stateConf.WaitForState() 245 if err != nil { 246 return fmt.Errorf("Error deleting OpenStack Neutron Subnet: %s", err) 247 } 248 249 d.SetId("") 250 return nil 251 } 252 253 func resourceSubnetAllocationPoolsV2(d *schema.ResourceData) []subnets.AllocationPool { 254 rawAPs := d.Get("allocation_pools").([]interface{}) 255 aps := make([]subnets.AllocationPool, len(rawAPs)) 256 for i, raw := range rawAPs { 257 rawMap := raw.(map[string]interface{}) 258 aps[i] = subnets.AllocationPool{ 259 Start: rawMap["start"].(string), 260 End: rawMap["end"].(string), 261 } 262 } 263 return aps 264 } 265 266 func resourceSubnetDNSNameserversV2(d *schema.ResourceData) []string { 267 rawDNSN := d.Get("dns_nameservers").(*schema.Set) 268 dnsn := make([]string, rawDNSN.Len()) 269 for i, raw := range rawDNSN.List() { 270 dnsn[i] = raw.(string) 271 } 272 return dnsn 273 } 274 275 func resourceSubnetHostRoutesV2(d *schema.ResourceData) []subnets.HostRoute { 276 rawHR := d.Get("host_routes").([]interface{}) 277 hr := make([]subnets.HostRoute, len(rawHR)) 278 for i, raw := range rawHR { 279 rawMap := raw.(map[string]interface{}) 280 hr[i] = subnets.HostRoute{ 281 DestinationCIDR: rawMap["destination_cidr"].(string), 282 NextHop: rawMap["next_hop"].(string), 283 } 284 } 285 return hr 286 } 287 288 func waitForSubnetActive(networkingClient *gophercloud.ServiceClient, subnetId string) resource.StateRefreshFunc { 289 return func() (interface{}, string, error) { 290 s, err := subnets.Get(networkingClient, subnetId).Extract() 291 if err != nil { 292 return nil, "", err 293 } 294 295 log.Printf("[DEBUG] OpenStack Neutron Subnet: %+v", s) 296 return s, "ACTIVE", nil 297 } 298 } 299 300 func waitForSubnetDelete(networkingClient *gophercloud.ServiceClient, subnetId string) resource.StateRefreshFunc { 301 return func() (interface{}, string, error) { 302 log.Printf("[DEBUG] Attempting to delete OpenStack Subnet %s.\n", subnetId) 303 304 s, err := subnets.Get(networkingClient, subnetId).Extract() 305 if err != nil { 306 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 307 if !ok { 308 return s, "ACTIVE", err 309 } 310 if errCode.Actual == 404 { 311 log.Printf("[DEBUG] Successfully deleted OpenStack Subnet %s", subnetId) 312 return s, "DELETED", nil 313 } 314 } 315 316 err = subnets.Delete(networkingClient, subnetId).ExtractErr() 317 if err != nil { 318 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 319 if !ok { 320 return s, "ACTIVE", err 321 } 322 if errCode.Actual == 404 { 323 log.Printf("[DEBUG] Successfully deleted OpenStack Subnet %s", subnetId) 324 return s, "DELETED", nil 325 } 326 } 327 328 log.Printf("[DEBUG] OpenStack Subnet %s still active.\n", subnetId) 329 return s, "ACTIVE", nil 330 } 331 }