github.com/gabrielperezs/terraform@v0.7.0-rc2.0.20160715084931-f7da2612946f/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/rackspace/gophercloud" 12 "github.com/rackspace/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 }, 100 } 101 } 102 103 func resourceNetworkingPortV2Create(d *schema.ResourceData, meta interface{}) error { 104 config := meta.(*Config) 105 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 106 if err != nil { 107 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 108 } 109 110 createOpts := ports.CreateOpts{ 111 Name: d.Get("name").(string), 112 AdminStateUp: resourcePortAdminStateUpV2(d), 113 NetworkID: d.Get("network_id").(string), 114 MACAddress: d.Get("mac_address").(string), 115 TenantID: d.Get("tenant_id").(string), 116 DeviceOwner: d.Get("device_owner").(string), 117 SecurityGroups: resourcePortSecurityGroupsV2(d), 118 DeviceID: d.Get("device_id").(string), 119 FixedIPs: resourcePortFixedIpsV2(d), 120 } 121 122 log.Printf("[DEBUG] Create Options: %#v", createOpts) 123 p, err := ports.Create(networkingClient, createOpts).Extract() 124 if err != nil { 125 return fmt.Errorf("Error creating OpenStack Neutron network: %s", err) 126 } 127 log.Printf("[INFO] Network ID: %s", p.ID) 128 129 log.Printf("[DEBUG] Waiting for OpenStack Neutron Port (%s) to become available.", p.ID) 130 131 stateConf := &resource.StateChangeConf{ 132 Target: []string{"ACTIVE"}, 133 Refresh: waitForNetworkPortActive(networkingClient, p.ID), 134 Timeout: 2 * time.Minute, 135 Delay: 5 * time.Second, 136 MinTimeout: 3 * time.Second, 137 } 138 139 _, err = stateConf.WaitForState() 140 141 d.SetId(p.ID) 142 143 return resourceNetworkingPortV2Read(d, meta) 144 } 145 146 func resourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) error { 147 config := meta.(*Config) 148 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 149 if err != nil { 150 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 151 } 152 153 p, err := ports.Get(networkingClient, d.Id()).Extract() 154 if err != nil { 155 return CheckDeleted(d, err, "port") 156 } 157 158 log.Printf("[DEBUG] Retreived Port %s: %+v", d.Id(), p) 159 160 d.Set("name", p.Name) 161 d.Set("admin_state_up", p.AdminStateUp) 162 d.Set("network_id", p.NetworkID) 163 d.Set("mac_address", p.MACAddress) 164 d.Set("tenant_id", p.TenantID) 165 d.Set("device_owner", p.DeviceOwner) 166 d.Set("security_group_ids", p.SecurityGroups) 167 d.Set("device_id", p.DeviceID) 168 169 // Convert FixedIPs to list of map 170 var ips []map[string]interface{} 171 for _, ipObject := range p.FixedIPs { 172 ip := make(map[string]interface{}) 173 ip["subnet_id"] = ipObject.SubnetID 174 ip["ip_address"] = ipObject.IPAddress 175 ips = append(ips, ip) 176 } 177 d.Set("fixed_ip", ips) 178 179 return nil 180 } 181 182 func resourceNetworkingPortV2Update(d *schema.ResourceData, meta interface{}) error { 183 config := meta.(*Config) 184 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 185 if err != nil { 186 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 187 } 188 189 var updateOpts ports.UpdateOpts 190 191 if d.HasChange("name") { 192 updateOpts.Name = d.Get("name").(string) 193 } 194 195 if d.HasChange("admin_state_up") { 196 updateOpts.AdminStateUp = resourcePortAdminStateUpV2(d) 197 } 198 199 if d.HasChange("device_owner") { 200 updateOpts.DeviceOwner = d.Get("device_owner").(string) 201 } 202 203 if d.HasChange("security_group_ids") { 204 updateOpts.SecurityGroups = resourcePortSecurityGroupsV2(d) 205 } 206 207 if d.HasChange("device_id") { 208 updateOpts.DeviceID = d.Get("device_id").(string) 209 } 210 211 if d.HasChange("fixed_ip") { 212 updateOpts.FixedIPs = resourcePortFixedIpsV2(d) 213 } 214 215 log.Printf("[DEBUG] Updating Port %s with options: %+v", d.Id(), updateOpts) 216 217 _, err = ports.Update(networkingClient, d.Id(), updateOpts).Extract() 218 if err != nil { 219 return fmt.Errorf("Error updating OpenStack Neutron Network: %s", err) 220 } 221 222 return resourceNetworkingPortV2Read(d, meta) 223 } 224 225 func resourceNetworkingPortV2Delete(d *schema.ResourceData, meta interface{}) error { 226 config := meta.(*Config) 227 networkingClient, err := config.networkingV2Client(d.Get("region").(string)) 228 if err != nil { 229 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 230 } 231 232 stateConf := &resource.StateChangeConf{ 233 Pending: []string{"ACTIVE"}, 234 Target: []string{"DELETED"}, 235 Refresh: waitForNetworkPortDelete(networkingClient, d.Id()), 236 Timeout: 2 * time.Minute, 237 Delay: 5 * time.Second, 238 MinTimeout: 3 * time.Second, 239 } 240 241 _, err = stateConf.WaitForState() 242 if err != nil { 243 return fmt.Errorf("Error deleting OpenStack Neutron Network: %s", err) 244 } 245 246 d.SetId("") 247 return nil 248 } 249 250 func resourcePortSecurityGroupsV2(d *schema.ResourceData) []string { 251 rawSecurityGroups := d.Get("security_group_ids").(*schema.Set) 252 groups := make([]string, rawSecurityGroups.Len()) 253 for i, raw := range rawSecurityGroups.List() { 254 groups[i] = raw.(string) 255 } 256 return groups 257 } 258 259 func resourcePortFixedIpsV2(d *schema.ResourceData) interface{} { 260 rawIP := d.Get("fixed_ip").([]interface{}) 261 262 if len(rawIP) == 0 { 263 return nil 264 } 265 266 ip := make([]ports.IP, len(rawIP)) 267 for i, raw := range rawIP { 268 rawMap := raw.(map[string]interface{}) 269 ip[i] = ports.IP{ 270 SubnetID: rawMap["subnet_id"].(string), 271 IPAddress: rawMap["ip_address"].(string), 272 } 273 } 274 return ip 275 276 } 277 278 func resourcePortAdminStateUpV2(d *schema.ResourceData) *bool { 279 value := false 280 281 if raw, ok := d.GetOk("admin_state_up"); ok && raw == true { 282 value = true 283 } 284 285 return &value 286 } 287 288 func waitForNetworkPortActive(networkingClient *gophercloud.ServiceClient, portId string) resource.StateRefreshFunc { 289 return func() (interface{}, string, error) { 290 p, err := ports.Get(networkingClient, portId).Extract() 291 if err != nil { 292 return nil, "", err 293 } 294 295 log.Printf("[DEBUG] OpenStack Neutron Port: %+v", p) 296 if p.Status == "DOWN" || p.Status == "ACTIVE" { 297 return p, "ACTIVE", nil 298 } 299 300 return p, p.Status, nil 301 } 302 } 303 304 func waitForNetworkPortDelete(networkingClient *gophercloud.ServiceClient, portId string) resource.StateRefreshFunc { 305 return func() (interface{}, string, error) { 306 log.Printf("[DEBUG] Attempting to delete OpenStack Neutron Port %s", portId) 307 308 p, err := ports.Get(networkingClient, portId).Extract() 309 if err != nil { 310 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 311 if !ok { 312 return p, "ACTIVE", err 313 } 314 if errCode.Actual == 404 { 315 log.Printf("[DEBUG] Successfully deleted OpenStack Port %s", portId) 316 return p, "DELETED", nil 317 } 318 } 319 320 err = ports.Delete(networkingClient, portId).ExtractErr() 321 if err != nil { 322 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 323 if !ok { 324 return p, "ACTIVE", err 325 } 326 if errCode.Actual == 404 { 327 log.Printf("[DEBUG] Successfully deleted OpenStack Port %s", portId) 328 return p, "DELETED", nil 329 } 330 } 331 332 log.Printf("[DEBUG] OpenStack Port %s still active.\n", portId) 333 return p, "ACTIVE", nil 334 } 335 }