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