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