github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/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:    2 * 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  	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  	var updateOpts routers.UpdateOpts
   205  	if d.HasChange("name") {
   206  		updateOpts.Name = d.Get("name").(string)
   207  	}
   208  	if d.HasChange("admin_state_up") {
   209  		asu := d.Get("admin_state_up").(bool)
   210  		updateOpts.AdminStateUp = &asu
   211  	}
   212  
   213  	log.Printf("[DEBUG] Updating Router %s with options: %+v", d.Id(), updateOpts)
   214  
   215  	_, err = routers.Update(networkingClient, d.Id(), updateOpts).Extract()
   216  	if err != nil {
   217  		return fmt.Errorf("Error updating OpenStack Neutron Router: %s", err)
   218  	}
   219  
   220  	return resourceNetworkingRouterV2Read(d, meta)
   221  }
   222  
   223  func resourceNetworkingRouterV2Delete(d *schema.ResourceData, meta interface{}) error {
   224  	config := meta.(*Config)
   225  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   226  	if err != nil {
   227  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   228  	}
   229  
   230  	stateConf := &resource.StateChangeConf{
   231  		Pending:    []string{"ACTIVE"},
   232  		Target:     []string{"DELETED"},
   233  		Refresh:    waitForRouterDelete(networkingClient, d.Id()),
   234  		Timeout:    2 * time.Minute,
   235  		Delay:      5 * time.Second,
   236  		MinTimeout: 3 * time.Second,
   237  	}
   238  
   239  	_, err = stateConf.WaitForState()
   240  	if err != nil {
   241  		return fmt.Errorf("Error deleting OpenStack Neutron Router: %s", err)
   242  	}
   243  
   244  	d.SetId("")
   245  	return nil
   246  }
   247  
   248  func waitForRouterActive(networkingClient *gophercloud.ServiceClient, routerId string) resource.StateRefreshFunc {
   249  	return func() (interface{}, string, error) {
   250  		r, err := routers.Get(networkingClient, routerId).Extract()
   251  		if err != nil {
   252  			return nil, r.Status, err
   253  		}
   254  
   255  		log.Printf("[DEBUG] OpenStack Neutron Router: %+v", r)
   256  		return r, r.Status, nil
   257  	}
   258  }
   259  
   260  func waitForRouterDelete(networkingClient *gophercloud.ServiceClient, routerId string) resource.StateRefreshFunc {
   261  	return func() (interface{}, string, error) {
   262  		log.Printf("[DEBUG] Attempting to delete OpenStack Router %s.\n", routerId)
   263  
   264  		r, err := routers.Get(networkingClient, routerId).Extract()
   265  		if err != nil {
   266  			errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
   267  			if !ok {
   268  				return r, "ACTIVE", err
   269  			}
   270  			if errCode.Actual == 404 {
   271  				log.Printf("[DEBUG] Successfully deleted OpenStack Router %s", routerId)
   272  				return r, "DELETED", nil
   273  			}
   274  		}
   275  
   276  		err = routers.Delete(networkingClient, routerId).ExtractErr()
   277  		if err != nil {
   278  			errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
   279  			if !ok {
   280  				return r, "ACTIVE", err
   281  			}
   282  			if errCode.Actual == 404 {
   283  				log.Printf("[DEBUG] Successfully deleted OpenStack Router %s", routerId)
   284  				return r, "DELETED", nil
   285  			}
   286  		}
   287  
   288  		log.Printf("[DEBUG] OpenStack Router %s still active.\n", routerId)
   289  		return r, "ACTIVE", nil
   290  	}
   291  }
   292  
   293  func routerValueSpecs(d *schema.ResourceData) map[string]string {
   294  	m := make(map[string]string)
   295  	for key, val := range d.Get("value_specs").(map[string]interface{}) {
   296  		m[key] = val.(string)
   297  	}
   298  	return m
   299  }