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  }