Adding router interface operations :elephant:
diff --git a/openstack/networking/v2/extensions/layer3/routers/requests.go b/openstack/networking/v2/extensions/layer3/routers/requests.go
index 670dc8f..7a95f95 100755
--- a/openstack/networking/v2/extensions/layer3/routers/requests.go
+++ b/openstack/networking/v2/extensions/layer3/routers/requests.go
@@ -1,6 +1,7 @@
package routers
import (
+ "fmt"
"strconv"
"github.com/racker/perigee"
@@ -22,6 +23,14 @@
return c.ServiceURL(version, resourcePath, id)
}
+func addInterfaceURL(c *gophercloud.ServiceClient, id string) string {
+ return c.ServiceURL(version, resourcePath, id, "add_router_interface")
+}
+
+func removeInterfaceURL(c *gophercloud.ServiceClient, id string) string {
+ return c.ServiceURL(version, resourcePath, id, "remove_router_interface")
+}
+
type ListOpts struct {
ID string
Name string
@@ -168,3 +177,60 @@
res.Err = err
return res
}
+
+var errInvalidInterfaceOpts = fmt.Errorf("When adding a router interface you must provide either a subnet ID or a port ID")
+
+type InterfaceOpts struct {
+ SubnetID string
+ PortID string
+}
+
+func AddInterface(c *gophercloud.ServiceClient, id string, opts InterfaceOpts) InterfaceResult {
+ var res InterfaceResult
+
+ // Validate
+ if (opts.SubnetID == "" && opts.PortID == "") || (opts.SubnetID != "" && opts.PortID != "") {
+ res.Err = errInvalidInterfaceOpts
+ }
+
+ type request struct {
+ SubnetID string `json:"subnet_id,omitempty"`
+ PortID string `json:"port_id,omitempty"`
+ }
+
+ body := request{SubnetID: opts.SubnetID, PortID: opts.PortID}
+
+ _, err := perigee.Request("PUT", addInterfaceURL(c, id), perigee.Options{
+ MoreHeaders: c.Provider.AuthenticatedHeaders(),
+ ReqBody: &body,
+ Results: &res.Resp,
+ OkCodes: []int{200},
+ })
+ res.Err = err
+ return res
+}
+
+func RemoveInterface(c *gophercloud.ServiceClient, id string, opts InterfaceOpts) InterfaceResult {
+ var res InterfaceResult
+
+ // Validate
+ if (opts.SubnetID == "" && opts.PortID == "") || (opts.SubnetID != "" && opts.PortID != "") {
+ res.Err = errInvalidInterfaceOpts
+ }
+
+ type request struct {
+ SubnetID string `json:"subnet_id,omitempty"`
+ PortID string `json:"port_id,omitempty"`
+ }
+
+ body := request{SubnetID: opts.SubnetID, PortID: opts.PortID}
+
+ _, err := perigee.Request("PUT", removeInterfaceURL(c, id), perigee.Options{
+ MoreHeaders: c.Provider.AuthenticatedHeaders(),
+ ReqBody: &body,
+ Results: &res.Resp,
+ OkCodes: []int{200},
+ })
+ 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 e005ed8..5aaefd8 100755
--- a/openstack/networking/v2/extensions/layer3/routers/requests_test.go
+++ b/openstack/networking/v2/extensions/layer3/routers/requests_test.go
@@ -258,3 +258,79 @@
res := Delete(serviceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c")
th.AssertNoErr(t, res.Err)
}
+
+func TestAddInterface(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c/add_router_interface", 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, `
+{
+ "subnet_id": "a2f1f29d-571b-4533-907f-5803ab96ead1"
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "subnet_id": "0d32a837-8069-4ec3-84c4-3eef3e10b188",
+ "tenant_id": "017d8de156df4177889f31a9bd6edc00",
+ "port_id": "3f990102-4485-4df1-97a0-2c35bdb85b31",
+ "id": "9a83fa11-8da5-436e-9afe-3d3ac5ce7770"
+}
+`)
+ })
+
+ opts := InterfaceOpts{SubnetID: "a2f1f29d-571b-4533-907f-5803ab96ead1"}
+ res, err := AddInterface(serviceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, "0d32a837-8069-4ec3-84c4-3eef3e10b188", res.SubnetID)
+ th.AssertEquals(t, "017d8de156df4177889f31a9bd6edc00", res.TenantID)
+ th.AssertEquals(t, "3f990102-4485-4df1-97a0-2c35bdb85b31", res.PortID)
+ th.AssertEquals(t, "9a83fa11-8da5-436e-9afe-3d3ac5ce7770", res.ID)
+}
+
+func TestRemoveInterface(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+
+ th.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c/remove_router_interface", 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, `
+{
+ "subnet_id": "a2f1f29d-571b-4533-907f-5803ab96ead1"
+}
+ `)
+
+ w.Header().Add("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ fmt.Fprintf(w, `
+{
+ "subnet_id": "0d32a837-8069-4ec3-84c4-3eef3e10b188",
+ "tenant_id": "017d8de156df4177889f31a9bd6edc00",
+ "port_id": "3f990102-4485-4df1-97a0-2c35bdb85b31",
+ "id": "9a83fa11-8da5-436e-9afe-3d3ac5ce7770"
+}
+`)
+ })
+
+ opts := InterfaceOpts{SubnetID: "a2f1f29d-571b-4533-907f-5803ab96ead1"}
+ res, err := RemoveInterface(serviceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract()
+ th.AssertNoErr(t, err)
+
+ th.AssertEquals(t, "0d32a837-8069-4ec3-84c4-3eef3e10b188", res.SubnetID)
+ th.AssertEquals(t, "017d8de156df4177889f31a9bd6edc00", res.TenantID)
+ th.AssertEquals(t, "3f990102-4485-4df1-97a0-2c35bdb85b31", res.PortID)
+ th.AssertEquals(t, "9a83fa11-8da5-436e-9afe-3d3ac5ce7770", res.ID)
+}
diff --git a/openstack/networking/v2/extensions/layer3/routers/results.go b/openstack/networking/v2/extensions/layer3/routers/results.go
index 8b2e5ea..9067366 100755
--- a/openstack/networking/v2/extensions/layer3/routers/results.go
+++ b/openstack/networking/v2/extensions/layer3/routers/results.go
@@ -112,3 +112,28 @@
}
type DeleteResult commonResult
+
+type InterfaceInfo struct {
+ SubnetID string `json:"subnet_id" mapstructure:"subnet_id"`
+ PortID string `json:"port_id" mapstructure:"port_id"`
+ ID string `json:"id" mapstructure:"id"`
+ TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
+}
+
+type InterfaceResult struct {
+ gophercloud.CommonResult
+}
+
+func (r InterfaceResult) Extract() (*InterfaceInfo, error) {
+ if r.Err != nil {
+ return nil, r.Err
+ }
+
+ var res *InterfaceInfo
+ err := mapstructure.Decode(r.Resp, &res)
+ if err != nil {
+ return nil, fmt.Errorf("Error decoding Neutron router interface: %v", err)
+ }
+
+ return res, nil
+}