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  }