Finalizing routers
diff --git a/openstack/networking/v2/extensions/layer3/routers/requests.go b/openstack/networking/v2/extensions/layer3/routers/requests.go
index 38ab4f4..670dc8f 100755
--- a/openstack/networking/v2/extensions/layer3/routers/requests.go
+++ b/openstack/networking/v2/extensions/layer3/routers/requests.go
@@ -3,6 +3,7 @@
import (
"strconv"
+ "github.com/racker/perigee"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/utils"
"github.com/rackspace/gophercloud/pagination"
@@ -68,3 +69,102 @@
return RouterPage{pagination.LinkedPageBase(r)}
})
}
+
+type CreateOpts struct {
+ Name string
+ AdminStateUp *bool
+ TenantID string
+ GatewayInfo *GatewayInfo
+}
+
+func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
+ type router struct {
+ Name *string `json:"name,omitempty"`
+ AdminStateUp *bool `json:"admin_state_up,omitempty"`
+ TenantID *string `json:"tenant_id,omitempty"`
+ GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"`
+ }
+
+ type request struct {
+ Router router `json:"router"`
+ }
+
+ reqBody := request{Router: router{
+ Name: gophercloud.MaybeString(opts.Name),
+ AdminStateUp: opts.AdminStateUp,
+ TenantID: gophercloud.MaybeString(opts.TenantID),
+ }}
+
+ if opts.GatewayInfo != nil {
+ reqBody.Router.GatewayInfo = opts.GatewayInfo
+ }
+
+ var res CreateResult
+ _, err := perigee.Request("POST", rootURL(c), perigee.Options{
+ MoreHeaders: c.Provider.AuthenticatedHeaders(),
+ ReqBody: &reqBody,
+ Results: &res.Resp,
+ OkCodes: []int{201},
+ })
+ res.Err = err
+ return res
+}
+
+func Get(c *gophercloud.ServiceClient, id string) GetResult {
+ var res GetResult
+ _, err := perigee.Request("GET", resourceURL(c, id), perigee.Options{
+ MoreHeaders: c.Provider.AuthenticatedHeaders(),
+ Results: &res.Resp,
+ OkCodes: []int{200},
+ })
+ res.Err = err
+ return res
+}
+
+type UpdateOpts struct {
+ Name string
+ AdminStateUp *bool
+ GatewayInfo *GatewayInfo
+}
+
+func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResult {
+ type router struct {
+ Name *string `json:"name,omitempty"`
+ AdminStateUp *bool `json:"admin_state_up,omitempty"`
+ GatewayInfo *GatewayInfo `json:"external_gateway_info,omitempty"`
+ }
+
+ type request struct {
+ Router router `json:"router"`
+ }
+
+ reqBody := request{Router: router{
+ Name: gophercloud.MaybeString(opts.Name),
+ AdminStateUp: opts.AdminStateUp,
+ }}
+
+ if opts.GatewayInfo != nil {
+ reqBody.Router.GatewayInfo = opts.GatewayInfo
+ }
+
+ // Send request to API
+ var res UpdateResult
+ _, err := perigee.Request("PUT", resourceURL(c, id), perigee.Options{
+ MoreHeaders: c.Provider.AuthenticatedHeaders(),
+ ReqBody: &reqBody,
+ Results: &res.Resp,
+ OkCodes: []int{200},
+ })
+ res.Err = err
+ return res
+}
+
+func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
+ var res DeleteResult
+ _, err := perigee.Request("DELETE", resourceURL(c, id), perigee.Options{
+ MoreHeaders: c.Provider.AuthenticatedHeaders(),
+ OkCodes: []int{204},
+ })
+ res.Err = err
+ return res
+}
diff --git a/openstack/networking/v2/extensions/layer3/routers/requests_test.go b/openstack/networking/v2/extensions/layer3/routers/requests_test.go
index 0078fc5..e005ed8 100755
--- a/openstack/networking/v2/extensions/layer3/routers/requests_test.go
+++ b/openstack/networking/v2/extensions/layer3/routers/requests_test.go
@@ -75,20 +75,20 @@
expected := []Router{
Router{
- Status: "ACTIVE",
- ExtGatewayInfo: GatewayInfo{NetworkID: ""},
- AdminStateUp: true,
- Name: "second_routers",
- ID: "7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b",
- TenantID: "6b96ff0cb17a4b859e1e575d221683d3",
+ Status: "ACTIVE",
+ GatewayInfo: GatewayInfo{NetworkID: ""},
+ AdminStateUp: true,
+ Name: "second_routers",
+ ID: "7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b",
+ TenantID: "6b96ff0cb17a4b859e1e575d221683d3",
},
Router{
- Status: "ACTIVE",
- ExtGatewayInfo: GatewayInfo{NetworkID: "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8"},
- AdminStateUp: true,
- Name: "router1",
- ID: "a9254bdb-2613-4a13-ac4c-adc581fba50d",
- TenantID: "33a40233088643acb66ff6eb0ebea679",
+ Status: "ACTIVE",
+ GatewayInfo: GatewayInfo{NetworkID: "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8"},
+ AdminStateUp: true,
+ Name: "router1",
+ ID: "a9254bdb-2613-4a13-ac4c-adc581fba50d",
+ TenantID: "33a40233088643acb66ff6eb0ebea679",
},
}
@@ -103,17 +103,158 @@
}
func TestCreate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ th.Mux.HandleFunc("/v2.0/routers", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", tokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "router":{
+ "name": "foo_router",
+ "admin_state_up": false,
+ "external_gateway_info":{
+ "network_id":"8ca37218-28ff-41cb-9b10-039601ea7e6b"
+ }
+ }
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+
+ fmt.Fprintf(w, `
+{
+ "router": {
+ "status": "ACTIVE",
+ "external_gateway_info": {
+ "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b"
+ },
+ "name": "foo_router",
+ "admin_state_up": false,
+ "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
+ "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e"
+ }
+}
+ `)
+ })
+
+ asu := false
+ gwi := GatewayInfo{NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b"}
+
+ options := CreateOpts{
+ Name: "foo_router",
+ AdminStateUp: &asu,
+ GatewayInfo: &gwi,
+ }
+ r, err := Create(serviceClient(), options).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, "foo_router", r.Name)
+ th.AssertEquals(t, false, r.AdminStateUp)
+ th.AssertDeepEquals(t, GatewayInfo{NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b"}, r.GatewayInfo)
}
func TestGet(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ th.Mux.HandleFunc("/v2.0/routers/a07eea83-7710-4860-931b-5fe220fae533", 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, `
+{
+ "router": {
+ "status": "ACTIVE",
+ "external_gateway_info": {
+ "network_id": "85d76829-6415-48ff-9c63-5c5ca8c61ac6"
+ },
+ "name": "router1",
+ "admin_state_up": true,
+ "tenant_id": "d6554fe62e2f41efbb6e026fad5c1542",
+ "id": "a07eea83-7710-4860-931b-5fe220fae533"
+ }
+}
+ `)
+ })
+
+ n, err := Get(serviceClient(), "a07eea83-7710-4860-931b-5fe220fae533").Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, n.Status, "ACTIVE")
+ th.AssertDeepEquals(t, n.GatewayInfo, GatewayInfo{NetworkID: "85d76829-6415-48ff-9c63-5c5ca8c61ac6"})
+ th.AssertEquals(t, n.Name, "router1")
+ th.AssertEquals(t, n.AdminStateUp, true)
+ th.AssertEquals(t, n.TenantID, "d6554fe62e2f41efbb6e026fad5c1542")
+ th.AssertEquals(t, n.ID, "a07eea83-7710-4860-931b-5fe220fae533")
}
func TestUpdate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "PUT")
+ th.TestHeader(t, r, "X-Auth-Token", tokenID)
+ th.TestHeader(t, r, "Content-Type", "application/json")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestJSONRequest(t, r, `
+{
+ "router": {
+ "name": "new_name",
+ "external_gateway_info": {
+ "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b"
+ }
+ }
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "router": {
+ "status": "ACTIVE",
+ "external_gateway_info": {
+ "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b"
+ },
+ "name": "new_name",
+ "admin_state_up": true,
+ "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
+ "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e"
+ }
+}
+ `)
+ })
+
+ gwi := GatewayInfo{NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b"}
+ options := UpdateOpts{Name: "new_name", GatewayInfo: &gwi}
+
+ n, err := Update(serviceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, n.Name, "new_name")
+ th.AssertDeepEquals(t, n.GatewayInfo, GatewayInfo{NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b"})
}
func TestDelete(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "DELETE")
+ th.TestHeader(t, r, "X-Auth-Token", tokenID)
+ w.WriteHeader(http.StatusNoContent)
+ })
+
+ res := Delete(serviceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c")
+ th.AssertNoErr(t, res.Err)
}
diff --git a/openstack/networking/v2/extensions/layer3/routers/results.go b/openstack/networking/v2/extensions/layer3/routers/results.go
index cdacb5b..8b2e5ea 100755
--- a/openstack/networking/v2/extensions/layer3/routers/results.go
+++ b/openstack/networking/v2/extensions/layer3/routers/results.go
@@ -1,7 +1,10 @@
package routers
import (
+ "fmt"
+
"github.com/mitchellh/mapstructure"
+ "github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
)
@@ -10,12 +13,12 @@
}
type Router struct {
- Status string `json:"status" mapstructure:"status"`
- ExtGatewayInfo GatewayInfo `json:"external_gateway_info" mapstructure:"external_gateway_info"`
- AdminStateUp bool `json:"admin_state_up" mapstructure:"admin_state_up"`
- Name string `json:"name" mapstructure:"name"`
- ID string `json:"id" mapstructure:"id"`
- TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+ Status string `json:"status" mapstructure:"status"`
+ GatewayInfo GatewayInfo `json:"external_gateway_info" mapstructure:"external_gateway_info"`
+ AdminStateUp bool `json:"admin_state_up" mapstructure:"admin_state_up"`
+ Name string `json:"name" mapstructure:"name"`
+ ID string `json:"id" mapstructure:"id"`
+ TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
}
type RouterPage struct {
@@ -70,3 +73,42 @@
return resp.Routers, nil
}
+
+type commonResult struct {
+ gophercloud.CommonResult
+}
+
+// Extract is a function that accepts a result and extracts a network resource.
+func (r commonResult) Extract() (*Router, error) {
+ if r.Err != nil {
+ return nil, r.Err
+ }
+
+ var res struct {
+ Router *Router `json:"router"`
+ }
+
+ err := mapstructure.Decode(r.Resp, &res)
+ if err != nil {
+ return nil, fmt.Errorf("Error decoding Neutron router: %v", err)
+ }
+
+ return res.Router, nil
+}
+
+// CreateResult represents the result of a create operation.
+type CreateResult struct {
+ commonResult
+}
+
+// GetResult represents the result of a get operation.
+type GetResult struct {
+ commonResult
+}
+
+// UpdateResult represents the result of an update operation.
+type UpdateResult struct {
+ commonResult
+}
+
+type DeleteResult commonResult