Merge pull request #353 from julienvey/allocate_floating_ip

Make portID not mandatory in floatingips
diff --git a/openstack/networking/v2/extensions/layer3/floatingips/requests.go b/openstack/networking/v2/extensions/layer3/floatingips/requests.go
index d23f9e2..89d7cc0 100644
--- a/openstack/networking/v2/extensions/layer3/floatingips/requests.go
+++ b/openstack/networking/v2/extensions/layer3/floatingips/requests.go
@@ -53,7 +53,6 @@
 
 var (
 	errFloatingNetworkIDRequired = fmt.Errorf("A NetworkID is required")
-	errPortIDRequired            = fmt.Errorf("A PortID is required")
 )
 
 // Create accepts a CreateOpts struct and uses the values provided to create a
@@ -88,16 +87,12 @@
 		res.Err = errFloatingNetworkIDRequired
 		return res
 	}
-	if opts.PortID == "" {
-		res.Err = errPortIDRequired
-		return res
-	}
 
 	// Define structures
 	type floatingIP struct {
 		FloatingNetworkID string `json:"floating_network_id"`
 		FloatingIP        string `json:"floating_ip_address,omitempty"`
-		PortID            string `json:"port_id"`
+		PortID            string `json:"port_id,omitempty"`
 		FixedIP           string `json:"fixed_ip_address,omitempty"`
 		TenantID          string `json:"tenant_id,omitempty"`
 	}
diff --git a/openstack/networking/v2/extensions/layer3/floatingips/requests_test.go b/openstack/networking/v2/extensions/layer3/floatingips/requests_test.go
index 19614be..d914a79 100644
--- a/openstack/networking/v2/extensions/layer3/floatingips/requests_test.go
+++ b/openstack/networking/v2/extensions/layer3/floatingips/requests_test.go
@@ -170,6 +170,55 @@
 	th.AssertEquals(t, "10.0.0.3", ip.FixedIP)
 }
 
+func TestCreateEmptyPort(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/v2.0/floatingips", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
+		th.TestHeader(t, r, "Content-Type", "application/json")
+		th.TestHeader(t, r, "Accept", "application/json")
+		th.TestJSONRequest(t, r, `
+			{
+				"floatingip": {
+					"floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57"
+				}
+			}
+			`)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusCreated)
+
+		fmt.Fprintf(w, `
+				{
+					"floatingip": {
+						"router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f",
+						"tenant_id": "4969c491a3c74ee4af974e6d800c62de",
+						"floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57",
+						"fixed_ip_address": "10.0.0.3",
+						"floating_ip_address": "",
+						"id": "2f245a7b-796b-4f26-9cf9-9e82d248fda7"
+					}
+				}
+				`)
+	})
+
+	options := CreateOpts{
+		FloatingNetworkID: "376da547-b977-4cfe-9cba-275c80debf57",
+	}
+
+	ip, err := Create(fake.ServiceClient(), options).Extract()
+	th.AssertNoErr(t, err)
+
+	th.AssertEquals(t, "2f245a7b-796b-4f26-9cf9-9e82d248fda7", ip.ID)
+	th.AssertEquals(t, "4969c491a3c74ee4af974e6d800c62de", ip.TenantID)
+	th.AssertEquals(t, "376da547-b977-4cfe-9cba-275c80debf57", ip.FloatingNetworkID)
+	th.AssertEquals(t, "", ip.FloatingIP)
+	th.AssertEquals(t, "", ip.PortID)
+	th.AssertEquals(t, "10.0.0.3", ip.FixedIP)
+}
+
 func TestGet(t *testing.T) {
 	th.SetupHTTP()
 	defer th.TeardownHTTP()