github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/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/resource"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  
    11  	"github.com/gophercloud/gophercloud"
    12  	"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
    13  )
    14  
    15  func resourceNetworkingPortV2() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceNetworkingPortV2Create,
    18  		Read:   resourceNetworkingPortV2Read,
    19  		Update: resourceNetworkingPortV2Update,
    20  		Delete: resourceNetworkingPortV2Delete,
    21  		Importer: &schema.ResourceImporter{
    22  			State: schema.ImportStatePassthrough,
    23  		},
    24  
    25  		Schema: map[string]*schema.Schema{
    26  			"region": &schema.Schema{
    27  				Type:        schema.TypeString,
    28  				Required:    true,
    29  				ForceNew:    true,
    30  				DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""),
    31  			},
    32  			"name": &schema.Schema{
    33  				Type:     schema.TypeString,
    34  				Optional: true,
    35  				ForceNew: false,
    36  			},
    37  			"network_id": &schema.Schema{
    38  				Type:     schema.TypeString,
    39  				Required: true,
    40  				ForceNew: true,
    41  			},
    42  			"admin_state_up": &schema.Schema{
    43  				Type:     schema.TypeBool,
    44  				Optional: true,
    45  				ForceNew: false,
    46  				Computed: true,
    47  			},
    48  			"mac_address": &schema.Schema{
    49  				Type:     schema.TypeString,
    50  				Optional: true,
    51  				ForceNew: true,
    52  				Computed: true,
    53  			},
    54  			"tenant_id": &schema.Schema{
    55  				Type:     schema.TypeString,
    56  				Optional: true,
    57  				ForceNew: true,
    58  				Computed: true,
    59  			},
    60  			"device_owner": &schema.Schema{
    61  				Type:     schema.TypeString,
    62  				Optional: true,
    63  				ForceNew: true,
    64  				Computed: true,
    65  			},
    66  			"security_group_ids": &schema.Schema{
    67  				Type:     schema.TypeSet,
    68  				Optional: true,
    69  				ForceNew: false,
    70  				Computed: true,
    71  				Elem:     &schema.Schema{Type: schema.TypeString},
    72  				Set:      schema.HashString,
    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  				Computed: true,
    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  							Optional: true,
    94  							Computed: true,
    95  						},
    96  					},
    97  				},
    98  			},
    99  			"allowed_address_pairs": &schema.Schema{
   100  				Type:     schema.TypeList,
   101  				Optional: true,
   102  				ForceNew: false,
   103  				Computed: true,
   104  				Elem: &schema.Resource{
   105  					Schema: map[string]*schema.Schema{
   106  						"ip_address": &schema.Schema{
   107  							Type:     schema.TypeString,
   108  							Required: true,
   109  						},
   110  						"mac_address": &schema.Schema{
   111  							Type:     schema.TypeString,
   112  							Optional: true,
   113  							Computed: true,
   114  						},
   115  					},
   116  				},
   117  			},
   118  			"value_specs": &schema.Schema{
   119  				Type:     schema.TypeMap,
   120  				Optional: true,
   121  				ForceNew: true,
   122  			},
   123  		},
   124  	}
   125  }
   126  
   127  func resourceNetworkingPortV2Create(d *schema.ResourceData, meta interface{}) error {
   128  	config := meta.(*Config)
   129  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   130  	if err != nil {
   131  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   132  	}
   133  
   134  	createOpts := PortCreateOpts{
   135  		ports.CreateOpts{
   136  			Name:                d.Get("name").(string),
   137  			AdminStateUp:        resourcePortAdminStateUpV2(d),
   138  			NetworkID:           d.Get("network_id").(string),
   139  			MACAddress:          d.Get("mac_address").(string),
   140  			TenantID:            d.Get("tenant_id").(string),
   141  			DeviceOwner:         d.Get("device_owner").(string),
   142  			SecurityGroups:      resourcePortSecurityGroupsV2(d),
   143  			DeviceID:            d.Get("device_id").(string),
   144  			FixedIPs:            resourcePortFixedIpsV2(d),
   145  			AllowedAddressPairs: resourceAllowedAddressPairsV2(d),
   146  		},
   147  		MapValueSpecs(d),
   148  	}
   149  
   150  	log.Printf("[DEBUG] Create Options: %#v", createOpts)
   151  	p, err := ports.Create(networkingClient, createOpts).Extract()
   152  	if err != nil {
   153  		return fmt.Errorf("Error creating OpenStack Neutron network: %s", err)
   154  	}
   155  	log.Printf("[INFO] Network ID: %s", p.ID)
   156  
   157  	log.Printf("[DEBUG] Waiting for OpenStack Neutron Port (%s) to become available.", p.ID)
   158  
   159  	stateConf := &resource.StateChangeConf{
   160  		Target:     []string{"ACTIVE"},
   161  		Refresh:    waitForNetworkPortActive(networkingClient, p.ID),
   162  		Timeout:    2 * time.Minute,
   163  		Delay:      5 * time.Second,
   164  		MinTimeout: 3 * time.Second,
   165  	}
   166  
   167  	_, err = stateConf.WaitForState()
   168  
   169  	d.SetId(p.ID)
   170  
   171  	return resourceNetworkingPortV2Read(d, meta)
   172  }
   173  
   174  func resourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) error {
   175  	config := meta.(*Config)
   176  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   177  	if err != nil {
   178  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   179  	}
   180  
   181  	p, err := ports.Get(networkingClient, d.Id()).Extract()
   182  	if err != nil {
   183  		return CheckDeleted(d, err, "port")
   184  	}
   185  
   186  	log.Printf("[DEBUG] Retrieved Port %s: %+v", d.Id(), p)
   187  
   188  	d.Set("name", p.Name)
   189  	d.Set("admin_state_up", p.AdminStateUp)
   190  	d.Set("network_id", p.NetworkID)
   191  	d.Set("mac_address", p.MACAddress)
   192  	d.Set("tenant_id", p.TenantID)
   193  	d.Set("device_owner", p.DeviceOwner)
   194  	d.Set("security_group_ids", p.SecurityGroups)
   195  	d.Set("device_id", p.DeviceID)
   196  
   197  	// Convert FixedIPs to list of map
   198  	var ips []map[string]interface{}
   199  	for _, ipObject := range p.FixedIPs {
   200  		ip := make(map[string]interface{})
   201  		ip["subnet_id"] = ipObject.SubnetID
   202  		ip["ip_address"] = ipObject.IPAddress
   203  		ips = append(ips, ip)
   204  	}
   205  	d.Set("fixed_ip", ips)
   206  
   207  	// Convert AllowedAddressPairs to list of map
   208  	var pairs []map[string]interface{}
   209  	for _, pairObject := range p.AllowedAddressPairs {
   210  		pair := make(map[string]interface{})
   211  		pair["ip_address"] = pairObject.IPAddress
   212  		pair["mac_address"] = pairObject.MACAddress
   213  		pairs = append(pairs, pair)
   214  	}
   215  	d.Set("allowed_address_pairs", pairs)
   216  
   217  	return nil
   218  }
   219  
   220  func resourceNetworkingPortV2Update(d *schema.ResourceData, meta interface{}) error {
   221  	config := meta.(*Config)
   222  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   223  	if err != nil {
   224  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   225  	}
   226  
   227  	var updateOpts ports.UpdateOpts
   228  
   229  	if d.HasChange("name") {
   230  		updateOpts.Name = d.Get("name").(string)
   231  	}
   232  
   233  	if d.HasChange("admin_state_up") {
   234  		updateOpts.AdminStateUp = resourcePortAdminStateUpV2(d)
   235  	}
   236  
   237  	if d.HasChange("device_owner") {
   238  		updateOpts.DeviceOwner = d.Get("device_owner").(string)
   239  	}
   240  
   241  	if d.HasChange("security_group_ids") {
   242  		updateOpts.SecurityGroups = resourcePortSecurityGroupsV2(d)
   243  	}
   244  
   245  	if d.HasChange("device_id") {
   246  		updateOpts.DeviceID = d.Get("device_id").(string)
   247  	}
   248  
   249  	if d.HasChange("fixed_ip") {
   250  		updateOpts.FixedIPs = resourcePortFixedIpsV2(d)
   251  	}
   252  
   253  	if d.HasChange("allowed_address_pairs") {
   254  		updateOpts.AllowedAddressPairs = resourceAllowedAddressPairsV2(d)
   255  	}
   256  
   257  	log.Printf("[DEBUG] Updating Port %s with options: %+v", d.Id(), updateOpts)
   258  
   259  	_, err = ports.Update(networkingClient, d.Id(), updateOpts).Extract()
   260  	if err != nil {
   261  		return fmt.Errorf("Error updating OpenStack Neutron Network: %s", err)
   262  	}
   263  
   264  	return resourceNetworkingPortV2Read(d, meta)
   265  }
   266  
   267  func resourceNetworkingPortV2Delete(d *schema.ResourceData, meta interface{}) error {
   268  	config := meta.(*Config)
   269  	networkingClient, err := config.networkingV2Client(d.Get("region").(string))
   270  	if err != nil {
   271  		return fmt.Errorf("Error creating OpenStack networking client: %s", err)
   272  	}
   273  
   274  	stateConf := &resource.StateChangeConf{
   275  		Pending:    []string{"ACTIVE"},
   276  		Target:     []string{"DELETED"},
   277  		Refresh:    waitForNetworkPortDelete(networkingClient, d.Id()),
   278  		Timeout:    2 * time.Minute,
   279  		Delay:      5 * time.Second,
   280  		MinTimeout: 3 * time.Second,
   281  	}
   282  
   283  	_, err = stateConf.WaitForState()
   284  	if err != nil {
   285  		return fmt.Errorf("Error deleting OpenStack Neutron Network: %s", err)
   286  	}
   287  
   288  	d.SetId("")
   289  	return nil
   290  }
   291  
   292  func resourcePortSecurityGroupsV2(d *schema.ResourceData) []string {
   293  	rawSecurityGroups := d.Get("security_group_ids").(*schema.Set)
   294  	groups := make([]string, rawSecurityGroups.Len())
   295  	for i, raw := range rawSecurityGroups.List() {
   296  		groups[i] = raw.(string)
   297  	}
   298  	return groups
   299  }
   300  
   301  func resourcePortFixedIpsV2(d *schema.ResourceData) interface{} {
   302  	rawIP := d.Get("fixed_ip").([]interface{})
   303  
   304  	if len(rawIP) == 0 {
   305  		return nil
   306  	}
   307  
   308  	ip := make([]ports.IP, len(rawIP))
   309  	for i, raw := range rawIP {
   310  		rawMap := raw.(map[string]interface{})
   311  		ip[i] = ports.IP{
   312  			SubnetID:  rawMap["subnet_id"].(string),
   313  			IPAddress: rawMap["ip_address"].(string),
   314  		}
   315  	}
   316  	return ip
   317  }
   318  
   319  func resourceAllowedAddressPairsV2(d *schema.ResourceData) []ports.AddressPair {
   320  	// ports.AddressPair
   321  	rawPairs := d.Get("allowed_address_pairs").([]interface{})
   322  
   323  	if len(rawPairs) == 0 {
   324  		return nil
   325  	}
   326  
   327  	pairs := make([]ports.AddressPair, len(rawPairs))
   328  	for i, raw := range rawPairs {
   329  		rawMap := raw.(map[string]interface{})
   330  		pairs[i] = ports.AddressPair{
   331  			IPAddress:  rawMap["ip_address"].(string),
   332  			MACAddress: rawMap["mac_address"].(string),
   333  		}
   334  	}
   335  	return pairs
   336  }
   337  
   338  func resourcePortAdminStateUpV2(d *schema.ResourceData) *bool {
   339  	value := false
   340  
   341  	if raw, ok := d.GetOk("admin_state_up"); ok && raw == true {
   342  		value = true
   343  	}
   344  
   345  	return &value
   346  }
   347  
   348  func waitForNetworkPortActive(networkingClient *gophercloud.ServiceClient, portId string) resource.StateRefreshFunc {
   349  	return func() (interface{}, string, error) {
   350  		p, err := ports.Get(networkingClient, portId).Extract()
   351  		if err != nil {
   352  			return nil, "", err
   353  		}
   354  
   355  		log.Printf("[DEBUG] OpenStack Neutron Port: %+v", p)
   356  		if p.Status == "DOWN" || p.Status == "ACTIVE" {
   357  			return p, "ACTIVE", nil
   358  		}
   359  
   360  		return p, p.Status, nil
   361  	}
   362  }
   363  
   364  func waitForNetworkPortDelete(networkingClient *gophercloud.ServiceClient, portId string) resource.StateRefreshFunc {
   365  	return func() (interface{}, string, error) {
   366  		log.Printf("[DEBUG] Attempting to delete OpenStack Neutron Port %s", portId)
   367  
   368  		p, err := ports.Get(networkingClient, portId).Extract()
   369  		if err != nil {
   370  			if _, ok := err.(gophercloud.ErrDefault404); ok {
   371  				log.Printf("[DEBUG] Successfully deleted OpenStack Port %s", portId)
   372  				return p, "DELETED", nil
   373  			}
   374  			return p, "ACTIVE", err
   375  		}
   376  
   377  		err = ports.Delete(networkingClient, portId).ExtractErr()
   378  		if err != nil {
   379  			if _, ok := err.(gophercloud.ErrDefault404); ok {
   380  				log.Printf("[DEBUG] Successfully deleted OpenStack Port %s", portId)
   381  				return p, "DELETED", nil
   382  			}
   383  			return p, "ACTIVE", err
   384  		}
   385  
   386  		log.Printf("[DEBUG] OpenStack Port %s still active.\n", portId)
   387  		return p, "ACTIVE", nil
   388  	}
   389  }