Skip to content

Commit

Permalink
Networking: add port data source
Browse files Browse the repository at this point in the history
  • Loading branch information
kayrus committed Jan 7, 2019
1 parent ca31961 commit 983ea59
Show file tree
Hide file tree
Showing 7 changed files with 397 additions and 11 deletions.
259 changes: 259 additions & 0 deletions openstack/data_source_openstack_networking_port_v2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
package openstack

import (
"fmt"
"log"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

listOpts := p.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)
}

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

allPorts, err := p.ExtractPorts(pages)
if err != nil {
return fmt.Errorf("Unable to retrieve Ports: %s", err)
}

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

var port struct {
p.Port
extradhcpopts.ExtraDHCPOptsExt
}
var ports []p.Port

// 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 {
ports = append(ports, p)
}
}
if len(ports) > 0 && len(ips) > 0 {
d.Set("all_fixed_ips", ips)
break
}
}
if len(ports) == 0 {
return fmt.Errorf("No Port found")
}
} else {
ports = allPorts
}

if len(ports) > 1 {
return fmt.Errorf("More than one Port found (%d). Try to use in a combination with the 'openstack_networking_port_ids_v2' data source", len(ports))
}

err = p.Get(networkingClient, ports[0].ID).ExtractInto(&port)
if err != nil {
return fmt.Errorf("No Port found: %s", err)
}

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
}
43 changes: 43 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,43 @@
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{
resource.TestStep{
Config: testAccNetworkingV2PortDataSource_basic,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair(
"data.openstack_networking_port_v2.port", "id",
"openstack_networking_port_v2.port_1", "id"),
),
},
},
})
}

const testAccNetworkingV2PortDataSource_basic = `
resource "openstack_networking_network_v2" "network_1" {
name = "network_1"
admin_state_up = "true"
}
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"
}
data "openstack_networking_port_v2" "port" {
name = "${openstack_networking_port_v2.port_1.name}"
}
`
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
}
1 change: 1 addition & 0 deletions openstack/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ func Provider() terraform.ResourceProvider {
"openstack_networking_subnetpool_v2": dataSourceNetworkingSubnetPoolV2(),
"openstack_networking_floatingip_v2": dataSourceNetworkingFloatingIPV2(),
"openstack_networking_router_v2": dataSourceNetworkingRouterV2(),
"openstack_networking_port_v2": dataSourceNetworkingPortV2(),
"openstack_sharedfilesystem_share_v2": dataSourceSharedFilesystemShareV2(),
},

Expand Down
11 changes: 11 additions & 0 deletions openstack/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,14 @@ func expandToMapStringString(v map[string]interface{}) map[string]string {

return m
}

// 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

0 comments on commit 983ea59

Please sign in to comment.