Adds Fixed IP support to os-floating-ips
This commit enables the ability to specify a fixed IP when associating a
floating IP to an instance. If a fixed IP is not specified, Nova will
attempt to associate the floating IP to the first detected fixed IP, as it
did prior to this patch.
diff --git a/openstack/compute/v2/extensions/floatingip/fixtures.go b/openstack/compute/v2/extensions/floatingip/fixtures.go
index 26f3299..e47fa4c 100644
--- a/openstack/compute/v2/extensions/floatingip/fixtures.go
+++ b/openstack/compute/v2/extensions/floatingip/fixtures.go
@@ -155,6 +155,25 @@
})
}
+// HandleFixedAssociateSucessfully configures the test server to respond to a Post request
+// to associate an allocated floating IP with a specific fixed IP address
+func HandleAssociateFixedSuccessfully(t *testing.T) {
+ th.Mux.HandleFunc("/servers/4d8c3732-a248-40ed-bebc-539a6ffd25c0/action", func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "POST")
+ th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
+ th.TestJSONRequest(t, r, `
+{
+ "addFloatingIp": {
+ "address": "10.10.10.2",
+ "fixed_address": "166.78.185.201"
+ }
+}
+`)
+
+ w.WriteHeader(http.StatusAccepted)
+ })
+}
+
// HandleDisassociateSuccessfully configures the test server to respond to a Post request
// to disassociate an allocated floating IP
func HandleDisassociateSuccessfully(t *testing.T) {
diff --git a/openstack/compute/v2/extensions/floatingip/requests.go b/openstack/compute/v2/extensions/floatingip/requests.go
index 8abb72d..941dc3b 100644
--- a/openstack/compute/v2/extensions/floatingip/requests.go
+++ b/openstack/compute/v2/extensions/floatingip/requests.go
@@ -26,6 +26,18 @@
Pool string
}
+// AssociateOpts specifies the required information to associate or disassociate a floating IP to an instance
+type AssociateOpts struct {
+ // ServerID is the UUID of the server
+ ServerID string
+
+ // FixedIP is an optional fixed IP address of the server
+ FixedIP string
+
+ // FloatingIP is the floating IP to associate with an instance
+ FloatingIP string
+}
+
// ToFloatingIPCreateMap constructs a request body from CreateOpts.
func (opts CreateOpts) ToFloatingIPCreateMap() (map[string]interface{}, error) {
if opts.Pool == "" {
@@ -35,6 +47,26 @@
return map[string]interface{}{"pool": opts.Pool}, nil
}
+// ToAssociateMap constructs a request body from AssociateOpts.
+func (opts AssociateOpts) ToAssociateMap() (map[string]interface{}, error) {
+ if opts.ServerID == "" {
+ return nil, errors.New("Required field missing for floating IP association: ServerID")
+ }
+
+ if opts.FloatingIP == "" {
+ return nil, errors.New("Required field missing for floating IP association: FloatingIP")
+ }
+
+ associateInfo := map[string]interface{}{
+ "serverId": opts.ServerID,
+ "floatingIp": opts.FloatingIP,
+ "fixedIp": opts.FixedIP,
+ }
+
+ return associateInfo, nil
+
+}
+
// Create requests the creation of a new floating IP
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
var res CreateResult
@@ -68,6 +100,7 @@
// association / disassociation
// Associate pairs an allocated floating IP with an instance
+// Deprecated. Use AssociateFloatingIP.
func Associate(client *gophercloud.ServiceClient, serverId, fip string) AssociateResult {
var res AssociateResult
@@ -79,7 +112,33 @@
return res
}
+// AssociateFloatingIP pairs an allocated floating IP with an instance.
+func AssociateFloatingIP(client *gophercloud.ServiceClient, opts AssociateOpts) AssociateResult {
+ var res AssociateResult
+
+ associateInfo, err := opts.ToAssociateMap()
+ if err != nil {
+ res.Err = err
+ return res
+ }
+
+ addFloatingIp := make(map[string]interface{})
+ addFloatingIp["address"] = associateInfo["floatingIp"].(string)
+
+ // fixedIp is not required
+ if associateInfo["fixedIp"] != "" {
+ addFloatingIp["fixed_address"] = associateInfo["fixedIp"].(string)
+ }
+
+ serverId := associateInfo["serverId"].(string)
+
+ reqBody := map[string]interface{}{"addFloatingIp": addFloatingIp}
+ _, res.Err = client.Post(associateURL(client, serverId), reqBody, nil, nil)
+ return res
+}
+
// Disassociate decouples an allocated floating IP from an instance
+// Deprecated. Use DisassociateFloatingIP.
func Disassociate(client *gophercloud.ServiceClient, serverId, fip string) DisassociateResult {
var res DisassociateResult
@@ -90,3 +149,23 @@
_, res.Err = client.Post(disassociateURL(client, serverId), reqBody, nil, nil)
return res
}
+
+// DisassociateFloatingIP decouples an allocated floating IP from an instance
+func DisassociateFloatingIP(client *gophercloud.ServiceClient, opts AssociateOpts) DisassociateResult {
+ var res DisassociateResult
+
+ associateInfo, err := opts.ToAssociateMap()
+ if err != nil {
+ res.Err = err
+ return res
+ }
+
+ removeFloatingIp := make(map[string]interface{})
+ removeFloatingIp["address"] = associateInfo["floatingIp"].(string)
+ reqBody := map[string]interface{}{"removeFloatingIp": removeFloatingIp}
+
+ serverId := associateInfo["serverId"].(string)
+
+ _, res.Err = client.Post(disassociateURL(client, serverId), reqBody, nil, nil)
+ return res
+}
diff --git a/openstack/compute/v2/extensions/floatingip/requests_test.go b/openstack/compute/v2/extensions/floatingip/requests_test.go
index ed2460e..b92496b 100644
--- a/openstack/compute/v2/extensions/floatingip/requests_test.go
+++ b/openstack/compute/v2/extensions/floatingip/requests_test.go
@@ -57,7 +57,7 @@
th.AssertNoErr(t, err)
}
-func TestAssociate(t *testing.T) {
+func TestAssociateDeprecated(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleAssociateSuccessfully(t)
@@ -68,7 +68,36 @@
th.AssertNoErr(t, err)
}
-func TestDisassociate(t *testing.T) {
+func TestAssociate(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandleAssociateSuccessfully(t)
+
+ associateOpts := AssociateOpts{
+ ServerID: "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
+ FloatingIP: "10.10.10.2",
+ }
+
+ err := AssociateFloatingIP(client.ServiceClient(), associateOpts).ExtractErr()
+ th.AssertNoErr(t, err)
+}
+
+func TestAssociateFixed(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandleAssociateFixedSuccessfully(t)
+
+ associateOpts := AssociateOpts{
+ ServerID: "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
+ FloatingIP: "10.10.10.2",
+ FixedIP: "166.78.185.201",
+ }
+
+ err := AssociateFloatingIP(client.ServiceClient(), associateOpts).ExtractErr()
+ th.AssertNoErr(t, err)
+}
+
+func TestDisassociateDeprecated(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleDisassociateSuccessfully(t)
@@ -78,3 +107,17 @@
err := Disassociate(client.ServiceClient(), serverId, fip).ExtractErr()
th.AssertNoErr(t, err)
}
+
+func TestDisassociateFloatingIP(t *testing.T) {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandleDisassociateSuccessfully(t)
+
+ associateOpts := AssociateOpts{
+ ServerID: "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
+ FloatingIP: "10.10.10.2",
+ }
+
+ err := DisassociateFloatingIP(client.ServiceClient(), associateOpts).ExtractErr()
+ th.AssertNoErr(t, err)
+}