Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Networking: add port data source #567

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
297 changes: 297 additions & 0 deletions openstack/data_source_openstack_networking_port_v2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
package openstack

import (
"fmt"
"log"
"strings"

"github.com/hashicorp/terraform/helper/schema"

"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/extradhcpopts"
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
)

type extraPort struct {
ports.Port
extradhcpopts.ExtraDHCPOptsExt
}

func dataSourceNetworkingPortV2() *schema.Resource {
return &schema.Resource{
Read: dataSourceNetworkingPortV2Read,

Schema: map[string]*schema.Schema{
"region": {
Type: schema.TypeString,
Optional: true,
},

"port_id": {
Type: schema.TypeString,
Optional: true,
},

"name": {
Type: schema.TypeString,
Optional: true,
},

"description": {
Type: schema.TypeString,
Optional: true,
},

"admin_state_up": {
Type: schema.TypeBool,
Optional: true,
},

"network_id": {
Type: schema.TypeString,
Optional: true,
},

"tenant_id": {
Type: schema.TypeString,
Optional: true,
},

"project_id": {
Type: schema.TypeString,
Optional: true,
},

"device_owner": {
Type: schema.TypeString,
Optional: true,
},

"mac_address": {
Type: schema.TypeString,
Optional: true,
},

"device_id": {
Type: schema.TypeString,
Optional: true,
},

"fixed_ip": {
Type: schema.TypeString,
Optional: true,
},

"security_group_ids": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},

"tags": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"allowed_address_pairs": {
Type: schema.TypeSet,
Computed: true,
Set: allowedAddressPairsHash,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"ip_address": {
Type: schema.TypeString,
Computed: true,
},
"mac_address": {
Type: schema.TypeString,
Computed: true,
},
},
},
},

"all_fixed_ips": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"all_security_group_ids": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},

"all_tags": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"extra_dhcp_option": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Computed: true,
},
"value": {
Type: schema.TypeString,
Computed: true,
},
"ip_version": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},
},
}
}

func dataSourceNetworkingPortV2Read(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
networkingClient, err := config.networkingV2Client(GetRegion(d, config))

listOpts := ports.ListOpts{}

if v, ok := d.GetOk("port_id"); ok {
listOpts.ID = v.(string)
}

if v, ok := d.GetOk("name"); ok {
listOpts.Name = v.(string)
}

if v, ok := d.GetOk("description"); ok {
listOpts.Description = v.(string)
}

if v, ok := d.GetOkExists("admin_state_up"); ok {
asu := v.(bool)
listOpts.AdminStateUp = &asu
}

if v, ok := d.GetOk("network_id"); ok {
listOpts.Status = v.(string)
}

if v, ok := d.GetOk("tenant_id"); ok {
listOpts.TenantID = v.(string)
}

if v, ok := d.GetOk("project_id"); ok {
listOpts.ProjectID = v.(string)
}

if v, ok := d.GetOk("device_owner"); ok {
listOpts.DeviceOwner = v.(string)
}

if v, ok := d.GetOk("mac_address"); ok {
listOpts.MACAddress = v.(string)
}

if v, ok := d.GetOk("device_id"); ok {
listOpts.DeviceID = v.(string)
}

tags := networkV2AttributesTags(d)
if len(tags) > 0 {
listOpts.Tags = strings.Join(tags, ",")
}

allPages, err := ports.List(networkingClient, listOpts).AllPages()
if err != nil {
return fmt.Errorf("Unable to list Ports: %s", err)
}

var allPorts []extraPort

err = ports.ExtractPortsInto(allPages, &allPorts)
if err != nil {
return fmt.Errorf("Unable to retrieve Ports: %s", err)
}

if len(allPorts) == 0 {
return fmt.Errorf("No Port found")
}

var portsList []extraPort

// Create a slice of all returned Fixed IPs.
// This will be in the order returned by the API,
// which is usually alpha-numeric.
if v, ok := d.GetOk("fixed_ip"); ok {
for _, p := range allPorts {
var ips = []string{}
for _, ipObject := range p.FixedIPs {
ips = append(ips, ipObject.IPAddress)
if v == ipObject.IPAddress {
portsList = append(portsList, p)
}
}
if len(portsList) > 0 && len(ips) > 0 {
d.Set("all_fixed_ips", ips)
break
}
}
if len(portsList) == 0 {
log.Printf("No Port found after the 'fixed_ip' filter")
return fmt.Errorf("No Port found")
}
} else {
portsList = allPorts
}

v := d.Get("security_group_ids").(*schema.Set)
securityGroups := resourcePortSecurityGroupsV2(v)
if len(securityGroups) > 0 {
var sgPorts []extraPort
for _, p := range portsList {
for _, sg := range p.SecurityGroups {
if strSliceContains(securityGroups, sg) {
sgPorts = append(sgPorts, p)
}
}
}
if len(sgPorts) == 0 {
log.Printf("[DEBUG] No Port found after the 'security_group_ids' filter")
return fmt.Errorf("No Port found")
}
portsList = sgPorts
}

if len(portsList) > 1 {
return fmt.Errorf("More than one Port found (%d)", len(portsList))
}

port := portsList[0]

log.Printf("[DEBUG] Retrieved Port %s: %+v", port.ID, port)
d.SetId(port.ID)

d.Set("port_id", port.ID)
d.Set("name", port.Name)
d.Set("description", port.Description)
d.Set("admin_state_up", port.AdminStateUp)
d.Set("network_id", port.NetworkID)
d.Set("tenant_id", port.TenantID)
d.Set("project_id", port.ProjectID)
d.Set("device_owner", port.DeviceOwner)
d.Set("mac_address", port.MACAddress)
d.Set("device_id", port.DeviceID)
d.Set("region", GetRegion(d, config))
d.Set("all_tags", port.Tags)
d.Set("all_security_group_ids", port.SecurityGroups)
d.Set("allowed_address_pairs", flattenNetworkingPortAllowedAddressPairsV2(port.MACAddress, port.AllowedAddressPairs))
d.Set("extra_dhcp_option", flattenNetworkingPortDHCPOptsV2(port.ExtraDHCPOptsExt))

return nil
}
82 changes: 82 additions & 0 deletions openstack/data_source_openstack_networking_port_v2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package openstack

import (
"testing"

"github.com/hashicorp/terraform/helper/resource"
)

func TestAccNetworkingV2PortDataSource_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckNetworkingV2PortDestroy,
Steps: []resource.TestStep{
{
Config: testAccNetworkingV2PortDataSource_basic,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair(
"data.openstack_networking_port_v2.port_1", "id",
"openstack_networking_port_v2.port_1", "id"),
resource.TestCheckResourceAttrPair(
"data.openstack_networking_port_v2.port_2", "id",
"openstack_networking_port_v2.port_2", "id"),
),
},
},
})
}

const testAccNetworkingV2PortDataSource_basic = `
resource "openstack_networking_network_v2" "network_1" {
name = "network_1"
admin_state_up = "true"
}

data "openstack_networking_secgroup_v2" "default" {
name = "default"
}

resource "openstack_networking_port_v2" "port_1" {
name = "port"
description = "test port"
network_id = "${openstack_networking_network_v2.network_1.id}"
admin_state_up = "true"

security_group_ids = [
"${data.openstack_networking_secgroup_v2.default.id}",
]
}

resource "openstack_networking_port_v2" "port_2" {
name = "port"
description = "test port"
network_id = "${openstack_networking_network_v2.network_1.id}"
admin_state_up = "true"
no_security_groups = "true"

tags = [
"foo",
"bar",
]
}

data "openstack_networking_port_v2" "port_1" {
name = "${openstack_networking_port_v2.port_1.name}"
admin_state_up = "${openstack_networking_port_v2.port_2.admin_state_up}"

security_group_ids = [
"${data.openstack_networking_secgroup_v2.default.id}",
]
}

data "openstack_networking_port_v2" "port_2" {
name = "${openstack_networking_port_v2.port_1.name}"
admin_state_up = "${openstack_networking_port_v2.port_2.admin_state_up}"

tags = [
"foo",
"bar",
]
}
`
11 changes: 0 additions & 11 deletions openstack/lb_v2_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,3 @@ func waitForLBV2L7Rule(lbClient *gophercloud.ServiceClient, parentListener *list

return nil
}

// strSliceContains checks if a given string is contained in a slice
// When anybody asks why Go needs generics, here you go.
func strSliceContains(haystack []string, needle string) bool {
for _, s := range haystack {
if s == needle {
return true
}
}
return false
}
Loading