github.com/willrstern/terraform@v0.6.7-0.20151106173844-fa471ddbb53a/builtin/providers/openstack/resource_openstack_networking_port_v2.go (about)

     1  package openstack
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/hashicorp/terraform/helper/hashcode"
    10  	"github.com/hashicorp/terraform/helper/resource"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  
    13  	"github.com/rackspace/gophercloud"
    14  	"github.com/rackspace/gophercloud/openstack/networking/v2/ports"
    15  )
    16  
    17  func resourceNetworkingPortV2() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceNetworkingPortV2Create,
    20  		Read:   resourceNetworkingPortV2Read,
    21  		Update: resourceNetworkingPortV2Update,
    22  		Delete: resourceNetworkingPortV2Delete,
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"region": &schema.Schema{
    26  				Type:        schema.TypeString,
    27  				Required:    true,
    28  				ForceNew:    true,
    29  				DefaultFunc: envDefaultFuncAllowMissing("OS_REGION_NAME"),
    30  			},
    31  			"name": &schema.Schema{
    32  				Type:     schema.TypeString,
    33  				Optional: true,
    34  				ForceNew: false,
    35  			},
    36  			"network_id": &schema.Schema{
    37  				Type:     schema.TypeString,
    38  				Required: true,
    39  				ForceNew: true,
    40  			},
    41  			"admin_state_up": &schema.Schema{
    42  				Type:     schema.TypeString,
    43  				Optional: true,
    44  				ForceNew: false,
    45  				Computed: true,
    46  			},
    47  			"mac_address": &schema.Schema{
    48  				Type:     schema.TypeString,
    49  				Optional: true,
    50  				ForceNew: true,
    51  				Computed: true,
    52  			},
    53  			"tenant_id": &schema.Schema{
    54  				Type:     schema.TypeString,
    55  				Optional: true,
    56  				ForceNew: true,
    57  				Computed: true,
    58  			},
    59  			"device_owner": &schema.Schema{
    60  				Type:     schema.TypeString,
    61  				Optional: true,
    62  				ForceNew: true,
    63  				Computed: true,
    64  			},
    65  			"security_groups": &schema.Schema{
    66  				Type:     schema.TypeSet,
    67  				Optional: true,
    68  				ForceNew: false,
    69  				Computed: true,
    70  				Elem:     &schema.Schema{Type: schema.TypeString},
    71  				Set: func(v interface{}) int {
    72  					return hashcode.String(v.(string))
    73  				},
    74  			},
    75  			"device_id": &schema.Schema{
    76  				Type:     schema.TypeString,
    77  				Optional: true,
    78  				ForceNew: true,
    79  				Computed: true,
    80  			},
    81  			"fixed_ips": &schema.Schema{
    82  				Type:     schema.TypeList,
    83  				Optional: true,
    84  				ForceNew: false,
    85  				Elem: &schema.Resource{
    86  					Schema: map[string]*schema.Schema{
    87  						"subnet_id": &schema.Schema{
    88  							Type:     schema.TypeString,
    89  							Required: true,
    90  						},
    91  						"ip_address": &schema.Schema{
    92  							Type:     schema.TypeString,
    93  							Required: true,
    94  						},
    95  					},
    96  				},
    97  			},
    98  		},
    99  	}
   100  }
   101  
   102  func resourceNetworkingPortV2Create(d *schema.ResourceData, meta interface{}) error {
   103  	config := meta.(*Config)
   104  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   105  	if err != nil {
   106  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   107  	}
   108  
   109  	createOpts := ports.CreateOpts{
   110  		Name:           d.Get("name").(string),
   111  		AdminStateUp:   resourcePortAdminStateUpV2(d),
   112  		NetworkID:      d.Get("network_id").(string),
   113  		MACAddress:     d.Get("mac_address").(string),
   114  		TenantID:       d.Get("tenant_id").(string),
   115  		DeviceOwner:    d.Get("device_owner").(string),
   116  		SecurityGroups: resourcePortSecurityGroupsV2(d),
   117  		DeviceID:       d.Get("device_id").(string),
   118  		FixedIPs:       resourcePortFixedIpsV2(d),
   119  	}
   120  
   121  	log.Printf("[DEBUG] Create Options: %#v", createOpts)
   122  	p, err := ports.Create(networkingClient, createOpts).Extract()
   123  	if err != nil {
   124  		return fmt.Errorf("Error creating OpenStack Neutron network: %s", err)
   125  	}
   126  	log.Printf("[INFO] Network ID: %s", p.ID)
   127  
   128  	log.Printf("[DEBUG] Waiting for OpenStack Neutron Port (%s) to become available.", p.ID)
   129  
   130  	stateConf := &resource.StateChangeConf{
   131  		Target:     "ACTIVE",
   132  		Refresh:    waitForNetworkPortActive(networkingClient, p.ID),
   133  		Timeout:    2 * time.Minute,
   134  		Delay:      5 * time.Second,
   135  		MinTimeout: 3 * time.Second,
   136  	}
   137  
   138  	_, err = stateConf.WaitForState()
   139  
   140  	d.SetId(p.ID)
   141  
   142  	return resourceNetworkingPortV2Read(d, meta)
   143  }
   144  
   145  func resourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) error {
   146  	config := meta.(*Config)
   147  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   148  	if err != nil {
   149  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   150  	}
   151  
   152  	p, err := ports.Get(networkingClient, d.Id()).Extract()
   153  	if err != nil {
   154  		return CheckDeleted(d, err, "port")
   155  	}
   156  
   157  	log.Printf("[DEBUG] Retreived Port %s: %+v", d.Id(), p)
   158  
   159  	d.Set("name", p.Name)
   160  	d.Set("admin_state_up", strconv.FormatBool(p.AdminStateUp))
   161  	d.Set("network_id", p.NetworkID)
   162  	d.Set("mac_address", p.MACAddress)
   163  	d.Set("tenant_id", p.TenantID)
   164  	d.Set("device_owner", p.DeviceOwner)
   165  	d.Set("security_groups", p.SecurityGroups)
   166  	d.Set("device_id", p.DeviceID)
   167  	d.Set("fixed_ips", p.FixedIPs)
   168  
   169  	return nil
   170  }
   171  
   172  func resourceNetworkingPortV2Update(d *schema.ResourceData, meta interface{}) error {
   173  	config := meta.(*Config)
   174  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   175  	if err != nil {
   176  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   177  	}
   178  
   179  	var updateOpts ports.UpdateOpts
   180  
   181  	if d.HasChange("name") {
   182  		updateOpts.Name = d.Get("name").(string)
   183  	}
   184  
   185  	if d.HasChange("admin_state_up") {
   186  		updateOpts.AdminStateUp = resourcePortAdminStateUpV2(d)
   187  	}
   188  
   189  	if d.HasChange("device_owner") {
   190  		updateOpts.DeviceOwner = d.Get("device_owner").(string)
   191  	}
   192  
   193  	if d.HasChange("security_groups") {
   194  		updateOpts.SecurityGroups = resourcePortSecurityGroupsV2(d)
   195  	}
   196  
   197  	if d.HasChange("device_id") {
   198  		updateOpts.DeviceID = d.Get("device_id").(string)
   199  	}
   200  
   201  	if d.HasChange("fixed_ips") {
   202  		updateOpts.FixedIPs = resourcePortFixedIpsV2(d)
   203  	}
   204  
   205  	log.Printf("[DEBUG] Updating Port %s with options: %+v", d.Id(), updateOpts)
   206  
   207  	_, err = ports.Update(networkingClient, d.Id(), updateOpts).Extract()
   208  	if err != nil {
   209  		return fmt.Errorf("Error updating OpenStack Neutron Network: %s", err)
   210  	}
   211  
   212  	return resourceNetworkingPortV2Read(d, meta)
   213  }
   214  
   215  func resourceNetworkingPortV2Delete(d *schema.ResourceData, meta interface{}) error {
   216  	config := meta.(*Config)
   217  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   218  	if err != nil {
   219  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   220  	}
   221  
   222  	stateConf := &resource.StateChangeConf{
   223  		Pending:    []string{"ACTIVE"},
   224  		Target:     "DELETED",
   225  		Refresh:    waitForNetworkPortDelete(networkingClient, d.Id()),
   226  		Timeout:    2 * time.Minute,
   227  		Delay:      5 * time.Second,
   228  		MinTimeout: 3 * time.Second,
   229  	}
   230  
   231  	_, err = stateConf.WaitForState()
   232  	if err != nil {
   233  		return fmt.Errorf("Error deleting OpenStack Neutron Network: %s", err)
   234  	}
   235  
   236  	d.SetId("")
   237  	return nil
   238  }
   239  
   240  func resourcePortSecurityGroupsV2(d *schema.ResourceData) []string {
   241  	rawSecurityGroups := d.Get("security_groups").(*schema.Set)
   242  	groups := make([]string, rawSecurityGroups.Len())
   243  	for i, raw := range rawSecurityGroups.List() {
   244  		groups[i] = raw.(string)
   245  	}
   246  	return groups
   247  }
   248  
   249  func resourcePortFixedIpsV2(d *schema.ResourceData) []ports.IP {
   250  	rawIP := d.Get("fixed_ips").([]interface{})
   251  	ip := make([]ports.IP, len(rawIP))
   252  	for i, raw := range rawIP {
   253  		rawMap := raw.(map[string]interface{})
   254  		ip[i] = ports.IP{
   255  			SubnetID:  rawMap["subnet_id"].(string),
   256  			IPAddress: rawMap["ip_address"].(string),
   257  		}
   258  	}
   259  
   260  	return ip
   261  }
   262  
   263  func resourcePortAdminStateUpV2(d *schema.ResourceData) *bool {
   264  	value := false
   265  
   266  	if raw, ok := d.GetOk("admin_state_up"); ok && raw == "true" {
   267  		value = true
   268  	}
   269  
   270  	return &value
   271  }
   272  
   273  func waitForNetworkPortActive(networkingClient *gophercloud.ServiceClient, portId string) resource.StateRefreshFunc {
   274  	return func() (interface{}, string, error) {
   275  		p, err := ports.Get(networkingClient, portId).Extract()
   276  		if err != nil {
   277  			return nil, "", err
   278  		}
   279  
   280  		log.Printf("[DEBUG] OpenStack Neutron Port: %+v", p)
   281  		if p.Status == "DOWN" || p.Status == "ACTIVE" {
   282  			return p, "ACTIVE", nil
   283  		}
   284  
   285  		return p, p.Status, nil
   286  	}
   287  }
   288  
   289  func waitForNetworkPortDelete(networkingClient *gophercloud.ServiceClient, portId string) resource.StateRefreshFunc {
   290  	return func() (interface{}, string, error) {
   291  		log.Printf("[DEBUG] Attempting to delete OpenStack Neutron Port %s", portId)
   292  
   293  		p, err := ports.Get(networkingClient, portId).Extract()
   294  		if err != nil {
   295  			errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
   296  			if !ok {
   297  				return p, "ACTIVE", err
   298  			}
   299  			if errCode.Actual == 404 {
   300  				log.Printf("[DEBUG] Successfully deleted OpenStack Port %s", portId)
   301  				return p, "DELETED", nil
   302  			}
   303  		}
   304  
   305  		err = ports.Delete(networkingClient, portId).ExtractErr()
   306  		if err != nil {
   307  			errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError)
   308  			if !ok {
   309  				return p, "ACTIVE", err
   310  			}
   311  			if errCode.Actual == 404 {
   312  				log.Printf("[DEBUG] Successfully deleted OpenStack Port %s", portId)
   313  				return p, "DELETED", nil
   314  			}
   315  		}
   316  
   317  		log.Printf("[DEBUG] OpenStack Port %s still active.\n", portId)
   318  		return p, "ACTIVE", nil
   319  	}
   320  }