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