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