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 }