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 }