Shuffled resources into sub-packages and upgraded to new pagination idiom
diff --git a/openstack/networking/v2/networks/requests.go b/openstack/networking/v2/networks/requests.go
index 06b0fe7..98e70d1 100644
--- a/openstack/networking/v2/networks/requests.go
+++ b/openstack/networking/v2/networks/requests.go
@@ -1,10 +1,24 @@
package networks
import (
+ "strconv"
+
"github.com/racker/perigee"
"github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/openstack/utils"
)
+type ListOpts struct {
+ Status string
+ Name string
+ AdminStateUp *bool
+ TenantID string
+ Shared *bool
+ ID string
+ Page int
+ PerPage int
+}
+
type NetworkOpts struct {
AdminStateUp bool
Name string
@@ -12,12 +26,54 @@
TenantID string
}
-func Get(c *gophercloud.ServiceClient, id string) (*NetworkResult, error) {
- var n NetworkResult
- _, err := perigee.Request("GET", NetworkURL(c, id), perigee.Options{
+func ptrToStr(val *bool) string {
+ if *val == true {
+ return "true"
+ } else if *val == false {
+ return "false"
+ } else {
+ return ""
+ }
+}
+
+func List(c *gophercloud.ServiceClient, opts ListOpts) gophercloud.Pager {
+ // Build query parameters
+ q := make(map[string]string)
+ if opts.Status != "" {
+ q["status"] = opts.Status
+ }
+ if opts.Name != "" {
+ q["name"] = opts.Name
+ }
+ if opts.AdminStateUp != nil {
+ q["admin_state_up"] = ptrToStr(opts.AdminStateUp)
+ }
+ if opts.TenantID != "" {
+ q["tenant_id"] = opts.TenantID
+ }
+ if opts.Shared != nil {
+ q["shared"] = ptrToStr(opts.Shared)
+ }
+ if opts.ID != "" {
+ q["id"] = opts.ID
+ }
+ if opts.Page != 0 {
+ q["page"] = strconv.Itoa(opts.Page)
+ }
+ if opts.PerPage != 0 {
+ q["per_page"] = strconv.Itoa(opts.PerPage)
+ }
+
+ u := ListURL(c) + utils.BuildQuery(q)
+ return gophercloud.NewLinkedPager(c, u)
+}
+
+func Get(c *gophercloud.ServiceClient, id string) (*Network, error) {
+ var n Network
+ _, err := perigee.Request("GET", GetURL(c, id), perigee.Options{
MoreHeaders: c.Provider.AuthenticatedHeaders(),
Results: &struct {
- Network *NetworkResult `json:"network"`
+ Network *Network `json:"network"`
}{&n},
OkCodes: []int{200},
})
@@ -73,7 +129,7 @@
return res.Network, nil
}
-func Update(c *gophercloud.ServiceClient, networkID string, opts NetworkOpts) (*NetworkResult, error) {
+func Update(c *gophercloud.ServiceClient, networkID string, opts NetworkOpts) (*Network, error) {
// Define structures
type network struct {
AdminStateUp bool `json:"admin_state_up"`
@@ -86,7 +142,7 @@
Network network `json:"network"`
}
type response struct {
- Network *NetworkResult `json:"network"`
+ Network *Network `json:"network"`
}
// Populate request body
@@ -102,7 +158,7 @@
// Send request to API
var res response
- _, err := perigee.Request("PUT", NetworkURL(c, networkID), perigee.Options{
+ _, err := perigee.Request("PUT", GetURL(c, networkID), perigee.Options{
MoreHeaders: c.Provider.AuthenticatedHeaders(),
ReqBody: &reqBody,
Results: &res,
@@ -114,3 +170,11 @@
return res.Network, nil
}
+
+func Delete(c *gophercloud.ServiceClient, networkID string) error {
+ _, err := perigee.Request("DELETE", DeleteURL(c, networkID), perigee.Options{
+ MoreHeaders: c.Provider.AuthenticatedHeaders(),
+ OkCodes: []int{204},
+ })
+ return err
+}
diff --git a/openstack/networking/v2/networks/requests_test.go b/openstack/networking/v2/networks/requests_test.go
index 6fa8222..e677f8e 100644
--- a/openstack/networking/v2/networks/requests_test.go
+++ b/openstack/networking/v2/networks/requests_test.go
@@ -20,6 +20,105 @@
}
}
+func TestList(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/v2.0/networks", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "X-Auth-Token", TokenID)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "networks": [
+ {
+ "status": "ACTIVE",
+ "subnets": [
+ "54d6f61d-db07-451c-9ab3-b9609b6b6f0b"
+ ],
+ "name": "private-network",
+ "provider:physical_network": null,
+ "admin_state_up": true,
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "provider:network_type": "local",
+ "router:external": true,
+ "shared": true,
+ "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "provider:segmentation_id": null
+ },
+ {
+ "status": "ACTIVE",
+ "subnets": [
+ "08eae331-0402-425a-923c-34f7cfe39c1b"
+ ],
+ "name": "private",
+ "provider:physical_network": null,
+ "admin_state_up": true,
+ "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "provider:network_type": "local",
+ "router:external": true,
+ "shared": true,
+ "id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+ "provider:segmentation_id": null
+ }
+ ]
+}
+ `)
+ })
+
+ client := ServiceClient()
+ count := 0
+
+ List(client, ListOpts{}).EachPage(func(page gophercloud.Page) (bool, error) {
+ count++
+ actual, err := ExtractNetworks(page)
+ if err != nil {
+ t.Errorf("Failed to extract networks: %v", err)
+ return false, err
+ }
+
+ expected := []Network{
+ Network{
+ Status: "ACTIVE",
+ Subnets: []interface{}{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"},
+ Name: "private-network",
+ ProviderPhysicalNetwork: "",
+ AdminStateUp: true,
+ TenantID: "4fd44f30292945e481c7b8a0c8908869",
+ ProviderNetworkType: "local",
+ RouterExternal: true,
+ Shared: true,
+ ID: "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ ProviderSegmentationID: 0,
+ },
+ Network{
+ Status: "ACTIVE",
+ Subnets: []interface{}{"08eae331-0402-425a-923c-34f7cfe39c1b"},
+ Name: "private",
+ ProviderPhysicalNetwork: "",
+ AdminStateUp: true,
+ TenantID: "26a7980765d0414dbc1fc1f88cdb7e6e",
+ ProviderNetworkType: "local",
+ RouterExternal: true,
+ Shared: true,
+ ID: "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+ ProviderSegmentationID: 0,
+ },
+ }
+
+ th.CheckDeepEquals(t, expected, actual)
+
+ return true, nil
+ })
+
+ if count != 1 {
+ t.Errorf("Expected 1 page, got %d", count)
+ }
+}
+
func TestGet(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
diff --git a/openstack/networking/v2/networks/results.go b/openstack/networking/v2/networks/results.go
index 4678793..b23395a 100644
--- a/openstack/networking/v2/networks/results.go
+++ b/openstack/networking/v2/networks/results.go
@@ -1,5 +1,10 @@
package networks
+import (
+ "github.com/mitchellh/mapstructure"
+ "github.com/rackspace/gophercloud"
+)
+
type NetworkProvider struct {
ProviderSegmentationID int `json:"provider:segmentation_id"`
ProviderPhysicalNetwork string `json:"provider:physical_network"`
@@ -7,19 +12,17 @@
}
type Network struct {
- Status string `json:"status"`
- Subnets []interface{} `json:"subnets"`
- Name string `json:"name"`
- AdminStateUp bool `json:"admin_state_up"`
- TenantID string `json:"tenant_id"`
- Shared bool `json:"shared"`
- ID string `json:"id"`
-}
-
-type NetworkResult struct {
- Network
- NetworkProvider
- RouterExternal bool `json:"router:external"`
+ Status string `mapstructure:"status" json:"status"`
+ Subnets []interface{} `mapstructure:"subnets" json:"subnets"`
+ Name string `mapstructure:"name" json:"name"`
+ AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
+ TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
+ Shared bool `mapstructure:"shared" json:"shared"`
+ ID string `mapstructure:"id" json:"id"`
+ ProviderSegmentationID int `mapstructure:"provider:segmentation_id" json:"provider:segmentation_id"`
+ ProviderPhysicalNetwork string `mapstructure:"provider:physical_network" json:"provider:physical_network"`
+ ProviderNetworkType string `mapstructure:"provider:network_type" json:"provider:network_type"`
+ RouterExternal bool `mapstructure:"router:external" json:"router:external"`
}
type NetworkCreateResult struct {
@@ -27,3 +30,16 @@
Segments []NetworkProvider `json:"segments"`
PortSecurityEnabled bool `json:"port_security_enabled"`
}
+
+func ExtractNetworks(page gophercloud.Page) ([]Network, error) {
+ var resp struct {
+ Networks []Network `mapstructure:"networks" json:"networks"`
+ }
+
+ err := mapstructure.Decode(page.(gophercloud.LinkedPage).Body, &resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return resp.Networks, nil
+}
diff --git a/openstack/networking/v2/networks/urls.go b/openstack/networking/v2/networks/urls.go
index 13fcc03..a0d660a 100644
--- a/openstack/networking/v2/networks/urls.go
+++ b/openstack/networking/v2/networks/urls.go
@@ -4,10 +4,26 @@
const Version = "v2.0"
-func NetworkURL(c *gophercloud.ServiceClient, id string) string {
+func ResourceURL(c *gophercloud.ServiceClient, id string) string {
return c.ServiceURL(Version, "networks", id)
}
-func CreateURL(c *gophercloud.ServiceClient) string {
+func RootURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL(Version, "networks")
}
+
+func GetURL(c *gophercloud.ServiceClient, id string) string {
+ return ResourceURL(c, id)
+}
+
+func ListURL(c *gophercloud.ServiceClient) string {
+ return RootURL(c)
+}
+
+func CreateURL(c *gophercloud.ServiceClient) string {
+ return RootURL(c)
+}
+
+func DeleteURL(c *gophercloud.ServiceClient, id string) string {
+ return ResourceURL(c, id)
+}
diff --git a/openstack/networking/v2/networks/urls_test.go b/openstack/networking/v2/networks/urls_test.go
index b8970a2..84a7ae6 100644
--- a/openstack/networking/v2/networks/urls_test.go
+++ b/openstack/networking/v2/networks/urls_test.go
@@ -13,8 +13,8 @@
return &gophercloud.ServiceClient{Endpoint: Endpoint}
}
-func TestNetworkURL(t *testing.T) {
- actual := NetworkURL(EndpointClient(), "foo")
+func TestGetURL(t *testing.T) {
+ actual := GetURL(EndpointClient(), "foo")
expected := Endpoint + "v2.0/networks/foo"
th.AssertEquals(t, expected, actual)
}
@@ -24,3 +24,15 @@
expected := Endpoint + "v2.0/networks"
th.AssertEquals(t, expected, actual)
}
+
+func TestListURL(t *testing.T) {
+ actual := CreateURL(EndpointClient())
+ expected := Endpoint + "v2.0/networks"
+ th.AssertEquals(t, expected, actual)
+}
+
+func TestDeleteURL(t *testing.T) {
+ actual := DeleteURL(EndpointClient(), "foo")
+ expected := Endpoint + "v2.0/networks/foo"
+ th.AssertEquals(t, expected, actual)
+}