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 }