github.com/gabrielperezs/terraform@v0.7.0-rc2.0.20160715084931-f7da2612946f/builtin/providers/openstack/resource_openstack_networking_router_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/extensions/layer3/routers"
    13  )
    14  
    15  func resourceNetworkingRouterV2() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceNetworkingRouterV2Create,
    18  		Read:   resourceNetworkingRouterV2Read,
    19  		Update: resourceNetworkingRouterV2Update,
    20  		Delete: resourceNetworkingRouterV2Delete,
    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  			"name": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Optional: true,
    32  				ForceNew: false,
    33  			},
    34  			"admin_state_up": &schema.Schema{
    35  				Type:     schema.TypeBool,
    36  				Optional: true,
    37  				ForceNew: false,
    38  				Computed: true,
    39  			},
    40  			"distributed": &schema.Schema{
    41  				Type:     schema.TypeBool,
    42  				Optional: true,
    43  				ForceNew: true,
    44  				Computed: true,
    45  			},
    46  			"external_gateway": &schema.Schema{
    47  				Type:     schema.TypeString,
    48  				Optional: true,
    49  				ForceNew: false,
    50  			},
    51  			"tenant_id": &schema.Schema{
    52  				Type:     schema.TypeString,
    53  				Optional: true,
    54  				ForceNew: true,
    55  				Computed: true,
    56  			},
    57  			"value_specs": &schema.Schema{
    58  				Type:     schema.TypeMap,
    59  				Optional: true,
    60  				ForceNew: true,
    61  			},
    62  		},
    63  	}
    64  }
    65  
    66  // routerCreateOpts contains all the values needed to create a new router. There are
    67  // no required values.
    68  type RouterCreateOpts struct {
    69  	Name         string
    70  	AdminStateUp *bool
    71  	Distributed  *bool
    72  	TenantID     string
    73  	GatewayInfo  *routers.GatewayInfo
    74  	ValueSpecs   map[string]string
    75  }
    76  
    77  // ToRouterCreateMap casts a routerCreateOpts struct to a map.
    78  func (opts RouterCreateOpts) ToRouterCreateMap() (map[string]interface{}, error) {
    79  	r := make(map[string]interface{})
    80  
    81  	if gophercloud.MaybeString(opts.Name) != nil {
    82  		r["name"] = opts.Name
    83  	}
    84  
    85  	if opts.AdminStateUp != nil {
    86  		r["admin_state_up"] = opts.AdminStateUp
    87  	}
    88  
    89  	if opts.Distributed != nil {
    90  		r["distributed"] = opts.Distributed
    91  	}
    92  
    93  	if gophercloud.MaybeString(opts.TenantID) != nil {
    94  		r["tenant_id"] = opts.TenantID
    95  	}
    96  
    97  	if opts.GatewayInfo != nil {
    98  		r["external_gateway_info"] = opts.GatewayInfo
    99  	}
   100  
   101  	if opts.ValueSpecs != nil {
   102  		for k, v := range opts.ValueSpecs {
   103  			r[k] = v
   104  		}
   105  	}
   106  
   107  	return map[string]interface{}{"router": r}, nil
   108  }
   109  
   110  func resourceNetworkingRouterV2Create(d *schema.ResourceData, meta interface{}) error {
   111  	config := meta.(*Config)
   112  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   113  	if err != nil {
   114  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   115  	}
   116  
   117  	createOpts := RouterCreateOpts{
   118  		Name:       d.Get("name").(string),
   119  		TenantID:   d.Get("tenant_id").(string),
   120  		ValueSpecs: routerValueSpecs(d),
   121  	}
   122  
   123  	if asuRaw, ok := d.GetOk("admin_state_up"); ok {
   124  		asu := asuRaw.(bool)
   125  		createOpts.AdminStateUp = &asu
   126  	}
   127  
   128  	if dRaw, ok := d.GetOk("distributed"); ok {
   129  		d := dRaw.(bool)
   130  		createOpts.Distributed = &d
   131  	}
   132  
   133  	externalGateway := d.Get("external_gateway").(string)
   134  	if externalGateway != "" {
   135  		gatewayInfo := routers.GatewayInfo{
   136  			NetworkID: externalGateway,
   137  		}
   138  		createOpts.GatewayInfo = &gatewayInfo
   139  	}
   140  
   141  	log.Printf("[DEBUG] Create Options: %#v", createOpts)
   142  	n, err := routers.Create(networkingClient, createOpts).Extract()
   143  	if err != nil {
   144  		return fmt.Errorf("Error creating OpenStack Neutron router: %s", err)
   145  	}
   146  	log.Printf("[INFO] Router ID: %s", n.ID)
   147  
   148  	log.Printf("[DEBUG] Waiting for OpenStack Neutron Router (%s) to become available", n.ID)
   149  	stateConf := &resource.StateChangeConf{
   150  		Pending:    []string{"BUILD", "PENDING_CREATE", "PENDING_UPDATE"},
   151  		Target:     []string{"ACTIVE"},
   152  		Refresh:    waitForRouterActive(networkingClient, n.ID),
   153  		Timeout:    10 * time.Minute,
   154  		Delay:      5 * time.Second,
   155  		MinTimeout: 3 * time.Second,
   156  	}
   157  
   158  	_, err = stateConf.WaitForState()
   159  
   160  	d.SetId(n.ID)
   161  
   162  	return resourceNetworkingRouterV2Read(d, meta)
   163  }
   164  
   165  func resourceNetworkingRouterV2Read(d *schema.ResourceData, meta interface{}) error {
   166  	config := meta.(*Config)
   167  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   168  	if err != nil {
   169  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   170  	}
   171  
   172  	n, err := routers.Get(networkingClient, d.Id()).Extract()
   173  	if err != nil {
   174  		httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError)
   175  		if !ok {
   176  			return fmt.Errorf("Error retrieving OpenStack Neutron Router: %s", err)
   177  		}
   178  
   179  		if httpError.Actual == 404 {
   180  			d.SetId("")
   181  			return nil
   182  		}
   183  		return fmt.Errorf("Error retrieving OpenStack Neutron Router: %s", err)
   184  	}
   185  
   186  	log.Printf("[DEBUG] Retreived Router %s: %+v", d.Id(), n)
   187  
   188  	d.Set("name", n.Name)
   189  	d.Set("admin_state_up", n.AdminStateUp)
   190  	d.Set("distributed", n.Distributed)
   191  	d.Set("tenant_id", n.TenantID)
   192  	d.Set("external_gateway", n.GatewayInfo.NetworkID)
   193  
   194  	return nil
   195  }
   196  
   197  func resourceNetworkingRouterV2Update(d *schema.ResourceData, meta interface{}) error {
   198  	routerId := d.Id()
   199  	osMutexKV.Lock(routerId)
   200  	defer osMutexKV.Unlock(routerId)
   201  
   202  	config := meta.(*Config)
   203  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   204  	if err != nil {
   205  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   206  	}
   207  
   208  	var updateOpts routers.UpdateOpts
   209  	if d.HasChange("name") {
   210  		updateOpts.Name = d.Get("name").(string)
   211  	}
   212  	if d.HasChange("admin_state_up") {
   213  		asu := d.Get("admin_state_up").(bool)
   214  		updateOpts.AdminStateUp = &asu
   215  	}
   216  
   217  	log.Printf("[DEBUG] Updating Router %s with options: %+v", d.Id(), updateOpts)
   218  
   219  	_, err = routers.Update(networkingClient, d.Id(), updateOpts).Extract()
   220  	if err != nil {
   221  		return fmt.Errorf("Error updating OpenStack Neutron Router: %s", err)
   222  	}
   223  
   224  	return resourceNetworkingRouterV2Read(d, meta)
   225  }
   226  
   227  func resourceNetworkingRouterV2Delete(d *schema.ResourceData, meta interface{}) error {
   228  	config := meta.(*Config)
   229  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   230  	if err != nil {
   231  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   232  	}
   233  
   234  	stateConf := &resource.StateChangeConf{
   235  		Pending:    []string{"ACTIVE"},
   236  		Target:     []string{"DELETED"},
   237  		Refresh:    waitForRouterDelete(networkingClient, d.Id()),
   238  		Timeout:    10 * time.Minute,
   239  		Delay:      5 * time.Second,
   240  		MinTimeout: 3 * time.Second,
   241  	}
   242  
   243  	_, err = stateConf.WaitForState()
   244  	if err != nil {
   245  		return fmt.Errorf("Error deleting OpenStack Neutron Router: %s", err)
   246  	}
   247  
   248  	d.SetId("")
   249  	return nil
   250  }
   251  
   252  func waitForRouterActive(networkingClient *gophercloud.ServiceClient, routerId string) resource.StateRefreshFunc {
   253  	return func() (interface{}, string, error) {
   254  		r, err := routers.Get(networkingClient, routerId).Extract()
   255  		if err != nil {
   256  			return nil, r.Status, err
   257  		}
   258  
   259  		log.Printf("[DEBUG] OpenStack Neutron Router: %+v", r)
   260  		return r, r.Status, nil
   261  	}
   262  }
   263  
   264  func waitForRouterDelete(networkingClient *gophercloud.ServiceClient, routerId string) resource.StateRefreshFunc {
   265  	return func() (interface{}, string, error) {
   266  		log.Printf("[DEBUG] Attempting to delete OpenStack Router %s.\n", routerId)
   267  
   268  		r, err := routers.Get(networkingClient, routerId).Extract()
   269  		if err != nil {
   270  			errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
   271  			if !ok {
   272  				return r, "ACTIVE", err
   273  			}
   274  			if errCode.Actual == 404 {
   275  				log.Printf("[DEBUG] Successfully deleted OpenStack Router %s", routerId)
   276  				return r, "DELETED", nil
   277  			}
   278  		}
   279  
   280  		err = routers.Delete(networkingClient, routerId).ExtractErr()
   281  		if err != nil {
   282  			errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
   283  			if !ok {
   284  				return r, "ACTIVE", err
   285  			}
   286  			if errCode.Actual == 404 {
   287  				log.Printf("[DEBUG] Successfully deleted OpenStack Router %s", routerId)
   288  				return r, "DELETED", nil
   289  			}
   290  		}
   291  
   292  		log.Printf("[DEBUG] OpenStack Router %s still active.\n", routerId)
   293  		return r, "ACTIVE", nil
   294  	}
   295  }
   296  
   297  func routerValueSpecs(d *schema.ResourceData) map[string]string {
   298  	m := make(map[string]string)
   299  	for key, val := range d.Get("value_specs").(map[string]interface{}) {
   300  		m[key] = val.(string)
   301  	}
   302  	return m
   303  }