Modifying opts and model structs with stricter types
diff --git a/openstack/networking/v2/networks/requests.go b/openstack/networking/v2/networks/requests.go
index 73b8a1f..4f1037e 100644
--- a/openstack/networking/v2/networks/requests.go
+++ b/openstack/networking/v2/networks/requests.go
@@ -23,7 +23,7 @@
SortDir string
}
-type NetworkOpts struct {
+type networkOpts struct {
AdminStateUp bool
Name string
Shared *bool
@@ -98,7 +98,9 @@
return &n, nil
}
-func Create(c *gophercloud.ServiceClient, opts NetworkOpts) (*NetworkCreateResult, error) {
+type CreateOpts networkOpts
+
+func Create(c *gophercloud.ServiceClient, opts CreateOpts) (*NetworkCreateResult, error) {
// Define structures
type network struct {
AdminStateUp bool `json:"admin_state_up"`
@@ -144,13 +146,14 @@
return res.Network, nil
}
-func Update(c *gophercloud.ServiceClient, networkID string, opts NetworkOpts) (*Network, error) {
+type UpdateOpts networkOpts
+
+func Update(c *gophercloud.ServiceClient, networkID string, opts UpdateOpts) (*Network, error) {
// Define structures
type network struct {
- AdminStateUp bool `json:"admin_state_up"`
- Name string `json:"name"`
- Shared *bool `json:"shared,omitempty"`
- TenantID *string `json:"tenant_id,omitempty"`
+ AdminStateUp bool `json:"admin_state_up"`
+ Name string `json:"name"`
+ Shared *bool `json:"shared,omitempty"`
}
type request struct {
@@ -167,10 +170,6 @@
Shared: opts.Shared,
}}
- if opts.TenantID != "" {
- reqBody.Network.TenantID = &opts.TenantID
- }
-
// Send request to API
var res response
_, err := perigee.Request("PUT", GetURL(c, networkID), perigee.Options{
diff --git a/openstack/networking/v2/networks/requests_test.go b/openstack/networking/v2/networks/requests_test.go
index b4332b0..b637b50 100644
--- a/openstack/networking/v2/networks/requests_test.go
+++ b/openstack/networking/v2/networks/requests_test.go
@@ -84,7 +84,7 @@
expected := []Network{
Network{
Status: "ACTIVE",
- Subnets: []interface{}{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"},
+ Subnets: []string{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"},
Name: "private-network",
ProviderPhysicalNetwork: "",
AdminStateUp: true,
@@ -97,7 +97,7 @@
},
Network{
Status: "ACTIVE",
- Subnets: []interface{}{"08eae331-0402-425a-923c-34f7cfe39c1b"},
+ Subnets: []string{"08eae331-0402-425a-923c-34f7cfe39c1b"},
Name: "private",
ProviderPhysicalNetwork: "",
AdminStateUp: true,
@@ -156,7 +156,7 @@
th.AssertNoErr(t, err)
th.AssertEquals(t, n.Status, "ACTIVE")
- th.AssertDeepEquals(t, n.Subnets, []interface{}{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"})
+ th.AssertDeepEquals(t, n.Subnets, []string{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"})
th.AssertEquals(t, n.Name, "private-network")
th.AssertEquals(t, n.ProviderPhysicalNetwork, "")
th.AssertEquals(t, n.ProviderNetworkType, "local")
@@ -217,12 +217,12 @@
`)
})
- options := NetworkOpts{Name: "sample_network", AdminStateUp: true}
+ options := CreateOpts{Name: "sample_network", AdminStateUp: true}
n, err := Create(ServiceClient(), options)
th.AssertNoErr(t, err)
th.AssertEquals(t, n.Status, "ACTIVE")
- th.AssertDeepEquals(t, n.Subnets, []interface{}{})
+ th.AssertDeepEquals(t, n.Subnets, []string{})
th.AssertEquals(t, n.Name, "net1")
th.AssertEquals(t, n.AdminStateUp, true)
th.AssertEquals(t, n.TenantID, "9bacb3c5d39d41a79512987f338cf177")
@@ -259,7 +259,7 @@
})
shared := true
- options := NetworkOpts{Name: "sample_network", AdminStateUp: true, Shared: &shared, TenantID: "12345"}
+ options := CreateOpts{Name: "sample_network", AdminStateUp: true, Shared: &shared, TenantID: "12345"}
_, err := Create(ServiceClient(), options)
th.AssertNoErr(t, err)
}
@@ -306,7 +306,7 @@
})
shared := true
- options := NetworkOpts{Name: "new_network_name", AdminStateUp: false, Shared: &shared}
+ options := UpdateOpts{Name: "new_network_name", AdminStateUp: false, Shared: &shared}
n, err := Update(ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options)
th.AssertNoErr(t, err)
diff --git a/openstack/networking/v2/networks/results.go b/openstack/networking/v2/networks/results.go
index 1f4b809..78bdff5 100644
--- a/openstack/networking/v2/networks/results.go
+++ b/openstack/networking/v2/networks/results.go
@@ -12,17 +12,26 @@
}
type Network struct {
- 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"`
+ // UUID for the network
+ ID string `mapstructure:"id" json:"id"`
+ // Human-readable name for the network. Might not be unique.
+ Name string `mapstructure:"name" json:"name"`
+ // The administrative state of network. If false (down), the network does not forward packets.
+ AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
+ // Indicates whether network is currently operational. Possible values include
+ // `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.
+ Status string `mapstructure:"status" json:"status"`
+ // Subnets associated with this network.
+ Subnets []string `mapstructure:"subnets" json:"subnets"`
+ // Owner of network. Only admin users can specify a tenant_id other than its own.
+ TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
+ // Specifies whether the network resource can be accessed by any tenant or not.
+ Shared bool `mapstructure:"shared" json:"shared"`
+
+ 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 {
diff --git a/openstack/networking/v2/ports/requests.go b/openstack/networking/v2/ports/requests.go
index 6543313..cc0949f 100644
--- a/openstack/networking/v2/ports/requests.go
+++ b/openstack/networking/v2/ports/requests.go
@@ -91,7 +91,7 @@
q["sort_dir"] = opts.SortDir
}
- u := ListURL(c) + utils.BuildQuery(q)
+ u := listURL(c) + utils.BuildQuery(q)
return pagination.NewPager(c, u, func(r pagination.LastHTTPResponse) pagination.Page {
return PortPage{pagination.LinkedPageBase(r)}
})
@@ -99,7 +99,7 @@
func Get(c *gophercloud.ServiceClient, id string) (*Port, error) {
var p Port
- _, err := perigee.Request("GET", GetURL(c, id), perigee.Options{
+ _, err := perigee.Request("GET", getURL(c, id), perigee.Options{
MoreHeaders: c.Provider.AuthenticatedHeaders(),
Results: &struct {
Port *Port `json:"port"`
@@ -112,17 +112,6 @@
return &p, nil
}
-type PortOpts struct {
- NetworkID string
- Status string
- Name string
- AdminStateUp *bool
- TenantID string
- MACAddress string
- FixedIPs interface{}
- SecurityGroups []string
-}
-
func maybeString(original string) *string {
if original != "" {
return &original
@@ -130,15 +119,28 @@
return nil
}
-func Create(c *gophercloud.ServiceClient, opts PortOpts) (*Port, error) {
+type CreateOpts struct {
+ NetworkID string
+ Name string
+ AdminStateUp *bool
+ MACAddress string
+ FixedIPs interface{}
+ DeviceID string
+ DeviceOwner string
+ TenantID string
+ SecurityGroups []string
+}
+
+func Create(c *gophercloud.ServiceClient, opts CreateOpts) (*Port, error) {
type port struct {
NetworkID string `json:"network_id,omitempty"`
- Status *string `json:"status,omitempty"`
Name *string `json:"name,omitempty"`
AdminStateUp *bool `json:"admin_state_up,omitempty"`
- TenantID *string `json:"tenant_id,omitempty"`
MACAddress *string `json:"mac_address,omitempty"`
FixedIPs interface{} `json:"fixed_ips,omitempty"`
+ DeviceID *string `json:"device_id,omitempty"`
+ DeviceOwner *string `json:"device_owner,omitempty"`
+ TenantID *string `json:"tenant_id,omitempty"`
SecurityGroups []string `json:"security_groups,omitempty"`
}
type request struct {
@@ -153,11 +155,12 @@
// Populate request body
reqBody := request{Port: port{
NetworkID: opts.NetworkID,
- Status: maybeString(opts.Status),
Name: maybeString(opts.Name),
AdminStateUp: opts.AdminStateUp,
TenantID: maybeString(opts.TenantID),
MACAddress: maybeString(opts.MACAddress),
+ DeviceID: maybeString(opts.DeviceID),
+ DeviceOwner: maybeString(opts.DeviceOwner),
}}
if opts.FixedIPs != nil {
@@ -173,7 +176,7 @@
Port *Port `json:"port"`
}
var res response
- _, err := perigee.Request("POST", CreateURL(c), perigee.Options{
+ _, err := perigee.Request("POST", createURL(c), perigee.Options{
MoreHeaders: c.Provider.AuthenticatedHeaders(),
ReqBody: &reqBody,
Results: &res,
@@ -187,34 +190,34 @@
return res.Port, nil
}
-func Update(c *gophercloud.ServiceClient, id string, opts PortOpts) (*Port, error) {
+type UpdateOpts struct {
+ Name string
+ AdminStateUp *bool
+ FixedIPs interface{}
+ DeviceID string
+ DeviceOwner string
+ SecurityGroups []string
+}
+
+func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (*Port, error) {
type port struct {
- NetworkID string `json:"network_id,omitempty"`
- Status *string `json:"status,omitempty"`
Name *string `json:"name,omitempty"`
AdminStateUp *bool `json:"admin_state_up,omitempty"`
- TenantID *string `json:"tenant_id,omitempty"`
- MACAddress *string `json:"mac_address,omitempty"`
FixedIPs interface{} `json:"fixed_ips,omitempty"`
+ DeviceID *string `json:"device_id,omitempty"`
+ DeviceOwner *string `json:"device_owner,omitempty"`
SecurityGroups []string `json:"security_groups,omitempty"`
}
type request struct {
Port port `json:"port"`
}
- // Validate
- if opts.NetworkID == "" {
- return nil, ErrNetworkIDRequired
- }
-
// Populate request body
reqBody := request{Port: port{
- NetworkID: opts.NetworkID,
- Status: maybeString(opts.Status),
Name: maybeString(opts.Name),
AdminStateUp: opts.AdminStateUp,
- TenantID: maybeString(opts.TenantID),
- MACAddress: maybeString(opts.MACAddress),
+ DeviceID: maybeString(opts.DeviceID),
+ DeviceOwner: maybeString(opts.DeviceOwner),
}}
if opts.FixedIPs != nil {
@@ -230,7 +233,7 @@
Port *Port `json:"port"`
}
var res response
- _, err := perigee.Request("PUT", UpdateURL(c, id), perigee.Options{
+ _, err := perigee.Request("PUT", updateURL(c, id), perigee.Options{
MoreHeaders: c.Provider.AuthenticatedHeaders(),
ReqBody: &reqBody,
Results: &res,
@@ -244,7 +247,7 @@
}
func Delete(c *gophercloud.ServiceClient, id string) error {
- _, err := perigee.Request("DELETE", DeleteURL(c, id), perigee.Options{
+ _, err := perigee.Request("DELETE", deleteURL(c, id), perigee.Options{
MoreHeaders: c.Provider.AuthenticatedHeaders(),
OkCodes: []int{204},
})
diff --git a/openstack/networking/v2/ports/requests_test.go b/openstack/networking/v2/ports/requests_test.go
index cb4cc2c..83b0153 100644
--- a/openstack/networking/v2/ports/requests_test.go
+++ b/openstack/networking/v2/ports/requests_test.go
@@ -10,13 +10,11 @@
th "github.com/rackspace/gophercloud/testhelper"
)
-const TokenID = "123"
+const tokenID = "123"
func ServiceClient() *gophercloud.ServiceClient {
return &gophercloud.ServiceClient{
- Provider: &gophercloud.ProviderClient{
- TokenID: TokenID,
- },
+ Provider: &gophercloud.ProviderClient{TokenID: tokenID},
Endpoint: th.Endpoint(),
}
}
@@ -27,7 +25,7 @@
th.Mux.HandleFunc("/v2.0/ports", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
- th.TestHeader(t, r, "X-Auth-Token", TokenID)
+ th.TestHeader(t, r, "X-Auth-Token", tokenID)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
@@ -122,7 +120,7 @@
th.Mux.HandleFunc("/v2.0/ports/46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
- th.TestHeader(t, r, "X-Auth-Token", TokenID)
+ th.TestHeader(t, r, "X-Auth-Token", tokenID)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
@@ -192,7 +190,7 @@
th.Mux.HandleFunc("/v2.0/ports", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
- th.TestHeader(t, r, "X-Auth-Token", TokenID)
+ 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, `
@@ -241,7 +239,7 @@
})
asu := true
- options := PortOpts{Name: "private-port", AdminStateUp: &asu, NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7"}
+ options := CreateOpts{Name: "private-port", AdminStateUp: &asu, NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7"}
n, err := Create(ServiceClient(), options)
th.AssertNoErr(t, err)
@@ -272,13 +270,12 @@
th.Mux.HandleFunc("/v2.0/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "PUT")
- th.TestHeader(t, r, "X-Auth-Token", TokenID)
+ 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, `
{
"port": {
- "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7",
"name": "new_port_name",
"fixed_ips": [
{
@@ -328,9 +325,8 @@
`)
})
- options := PortOpts{
- NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7",
- Name: "new_port_name",
+ options := UpdateOpts{
+ Name: "new_port_name",
FixedIPs: []IP{
IP{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"},
},
@@ -353,7 +349,7 @@
th.Mux.HandleFunc("/v2.0/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "DELETE")
- th.TestHeader(t, r, "X-Auth-Token", TokenID)
+ th.TestHeader(t, r, "X-Auth-Token", tokenID)
w.WriteHeader(http.StatusNoContent)
})
diff --git a/openstack/networking/v2/ports/results.go b/openstack/networking/v2/ports/results.go
index f7f947d..7e90d8d 100644
--- a/openstack/networking/v2/ports/results.go
+++ b/openstack/networking/v2/ports/results.go
@@ -11,19 +11,33 @@
}
type Port struct {
- Status string `mapstructure:"status" json:"status"`
- Name string `mapstructure:"name" json:"name"`
+ // UUID for the port.
+ ID string `mapstructure:"id" json:"id"`
+ // Network that this port is associated with.
+ NetworkID string `mapstructure:"network_id" json:"network_id"`
+ // Human-readable name for the port. Might not be unique.
+ Name string `mapstructure:"name" json:"name"`
+ // Administrative state of port. If false (down), port does not forward packets.
+ AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
+ // Indicates whether network is currently operational. Possible values include
+ // `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.
+ Status string `mapstructure:"status" json:"status"`
+ // Mac address to use on this port.
+ MACAddress string `mapstructure:"mac_address" json:"mac_address"`
+ // Specifies IP addresses for the port thus associating the port itself with
+ // the subnets where the IP addresses are picked from
+ FixedIPs []IP `mapstructure:"fixed_ips" json:"fixed_ips"`
+ // Owner of network. Only admin users can specify a tenant_id other than its own.
+ TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
+ // Identifies the entity (e.g.: dhcp agent) using this port.
+ DeviceOwner string `mapstructure:"device_owner" json:"device_owner"`
+ // Specifies the IDs of any security groups associated with a port.
+ SecurityGroups []string `mapstructure:"security_groups" json:"security_groups"`
+ // Identifies the device (e.g., virtual server) using this port.
+ DeviceID string `mapstructure:"device_id" json:"device_id"`
+
AllowedAddressPairs []interface{} `mapstructure:"allowed" json:"allowed"`
- AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
- NetworkID string `mapstructure:"network_id" json:"network_id"`
- TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
ExtraDHCPOpts interface{} `mapstructure:"extra_dhcp_opts" json:"extra_dhcp_opts"`
- DeviceOwner string `mapstructure:"device_owner" json:"device_owner"`
- MACAddress string `mapstructure:"mac_address" json:"mac_address"`
- FixedIPs []IP `mapstructure:"fixed_ips" json:"fixed_ips"`
- ID string `mapstructure:"id" json:"id"`
- SecurityGroups []string `mapstructure:"security_groups" json:"security_groups"`
- DeviceID string `mapstructure:"device_id" json:"device_id"`
BindingHostID string `mapstructure:"binding:host_id" json:"binding:host_id"`
BindingVIFDetails interface{} `mapstructure:"binding:vif_details" json:"binding:vif_details"`
BindingVIFType string `mapstructure:"binding:vif_type" json:"binding:vif_type"`
diff --git a/openstack/networking/v2/ports/urls.go b/openstack/networking/v2/ports/urls.go
index 5dc4696..558b399 100644
--- a/openstack/networking/v2/ports/urls.go
+++ b/openstack/networking/v2/ports/urls.go
@@ -2,32 +2,32 @@
import "github.com/rackspace/gophercloud"
-const Version = "v2.0"
+const version = "v2.0"
-func ResourceURL(c *gophercloud.ServiceClient, id string) string {
- return c.ServiceURL(Version, "ports", id)
+func resourceURL(c *gophercloud.ServiceClient, id string) string {
+ return c.ServiceURL(version, "ports", id)
}
-func RootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(Version, "ports")
+func rootURL(c *gophercloud.ServiceClient) string {
+ return c.ServiceURL(version, "ports")
}
-func ListURL(c *gophercloud.ServiceClient) string {
- return RootURL(c)
+func listURL(c *gophercloud.ServiceClient) string {
+ return rootURL(c)
}
-func GetURL(c *gophercloud.ServiceClient, id string) string {
- return ResourceURL(c, id)
+func getURL(c *gophercloud.ServiceClient, id string) string {
+ return resourceURL(c, id)
}
-func CreateURL(c *gophercloud.ServiceClient) string {
- return RootURL(c)
+func createURL(c *gophercloud.ServiceClient) string {
+ return rootURL(c)
}
-func UpdateURL(c *gophercloud.ServiceClient, id string) string {
- return ResourceURL(c, id)
+func updateURL(c *gophercloud.ServiceClient, id string) string {
+ return resourceURL(c, id)
}
-func DeleteURL(c *gophercloud.ServiceClient, id string) string {
- return ResourceURL(c, id)
+func deleteURL(c *gophercloud.ServiceClient, id string) string {
+ return resourceURL(c, id)
}
diff --git a/openstack/networking/v2/ports/urls_tests.go b/openstack/networking/v2/ports/urls_tests.go
index 089725d..6fb20aa 100644
--- a/openstack/networking/v2/ports/urls_tests.go
+++ b/openstack/networking/v2/ports/urls_tests.go
@@ -7,38 +7,38 @@
th "github.com/rackspace/gophercloud/testhelper"
)
-const Endpoint = "http://localhost:57909/"
+const endpoint = "http://localhost:57909/"
-func EndpointClient() *gophercloud.ServiceClient {
- return &gophercloud.ServiceClient{Endpoint: Endpoint}
+func endpointClient() *gophercloud.ServiceClient {
+ return &gophercloud.ServiceClient{Endpoint: endpoint}
}
func TestListURL(t *testing.T) {
- actual := ListURL(EndpointClient())
- expected := Endpoint + "v2.0/ports"
+ actual := listURL(endpointClient())
+ expected := endpoint + "v2.0/ports"
th.AssertEquals(t, expected, actual)
}
func TestGetURL(t *testing.T) {
- actual := GetURL(EndpointClient(), "foo")
- expected := Endpoint + "v2.0/ports/foo"
+ actual := getURL(endpointClient(), "foo")
+ expected := endpoint + "v2.0/ports/foo"
th.AssertEquals(t, expected, actual)
}
func TestCreateURL(t *testing.T) {
- actual := CreateURL(EndpointClient())
- expected := Endpoint + "v2.0/ports"
+ actual := createURL(endpointClient())
+ expected := endpoint + "v2.0/ports"
th.AssertEquals(t, expected, actual)
}
func TestUpdateURL(t *testing.T) {
- actual := UpdateURL(EndpointClient(), "foo")
- expected := Endpoint + "v2.0/ports/foo"
+ actual := updateURL(endpointClient(), "foo")
+ expected := endpoint + "v2.0/ports/foo"
th.AssertEquals(t, expected, actual)
}
func TestDeleteURL(t *testing.T) {
- actual := DeleteURL(EndpointClient(), "foo")
- expected := Endpoint + "v2.0/ports/foo"
+ actual := deleteURL(endpointClient(), "foo")
+ expected := endpoint + "v2.0/ports/foo"
th.AssertEquals(t, expected, actual)
}
diff --git a/openstack/networking/v2/subnets/requests.go b/openstack/networking/v2/subnets/requests.go
index f592739..ff36765 100644
--- a/openstack/networking/v2/subnets/requests.go
+++ b/openstack/networking/v2/subnets/requests.go
@@ -89,12 +89,20 @@
return &s, nil
}
+// maybeString returns nil for empty strings and nil for empty.
+func maybeString(original string) *string {
+ if original != "" {
+ return &original
+ }
+ return nil
+}
+
const (
IPv4 = 4
IPv6 = 6
)
-type SubnetOpts struct {
+type CreateOpts struct {
// Required
NetworkID string
CIDR string
@@ -104,19 +112,12 @@
AllocationPools []AllocationPool
GatewayIP string
IPVersion int
- ID string
EnableDHCP *bool
+ DNSNameservers []string
+ HostRoutes []interface{}
}
-// maybeString returns nil for empty strings and nil for empty.
-func maybeString(original string) *string {
- if original != "" {
- return &original
- }
- return nil
-}
-
-func Create(c *gophercloud.ServiceClient, opts SubnetOpts) (*Subnet, error) {
+func Create(c *gophercloud.ServiceClient, opts CreateOpts) (*Subnet, error) {
// Validate required options
if opts.NetworkID == "" {
return nil, ErrNetworkIDRequired
@@ -136,8 +137,9 @@
AllocationPools []AllocationPool `json:"allocation_pools,omitempty"`
GatewayIP *string `json:"gateway_ip,omitempty"`
IPVersion int `json:"ip_version,omitempty"`
- ID *string `json:"id,omitempty"`
EnableDHCP *bool `json:"enable_dhcp,omitempty"`
+ DNSNameservers []string `json:"dns_nameservers,omitempty"`
+ HostRoutes []interface{} `json:"host_routes,omitempty"`
}
type request struct {
Subnet subnet `json:"subnet"`
@@ -149,17 +151,21 @@
Name: maybeString(opts.Name),
TenantID: maybeString(opts.TenantID),
GatewayIP: maybeString(opts.GatewayIP),
- ID: maybeString(opts.ID),
EnableDHCP: opts.EnableDHCP,
}}
if opts.IPVersion != 0 {
reqBody.Subnet.IPVersion = opts.IPVersion
}
-
if len(opts.AllocationPools) != 0 {
reqBody.Subnet.AllocationPools = opts.AllocationPools
}
+ if len(opts.DNSNameservers) != 0 {
+ reqBody.Subnet.DNSNameservers = opts.DNSNameservers
+ }
+ if len(opts.HostRoutes) != 0 {
+ reqBody.Subnet.HostRoutes = opts.HostRoutes
+ }
type response struct {
Subnet *Subnet `json:"subnet"`
@@ -179,38 +185,38 @@
return res.Subnet, nil
}
-func Update(c *gophercloud.ServiceClient, id string, opts SubnetOpts) (*Subnet, error) {
- if opts.CIDR != "" {
- return nil, ErrCIDRNotUpdatable
- }
- if opts.IPVersion != 0 {
- return nil, ErrIPVersionNotUpdatable
- }
+type UpdateOpts struct {
+ Name string
+ GatewayIP string
+ DNSNameservers []string
+ HostRoutes []interface{}
+ EnableDHCP *bool
+}
+func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (*Subnet, error) {
type subnet struct {
- NetworkID string `json:"network_id,omitempty"`
- Name *string `json:"name,omitempty"`
- TenantID *string `json:"tenant_id,omitempty"`
- AllocationPools []AllocationPool `json:"allocation_pools,omitempty"`
- GatewayIP *string `json:"gateway_ip,omitempty"`
- ID *string `json:"id,omitempty"`
- EnableDHCP *bool `json:"enable_dhcp,omitempty"`
+ Name *string `json:"name,omitempty"`
+ GatewayIP *string `json:"gateway_ip,omitempty"`
+ DNSNameservers []string `json:"dns_nameservers,omitempty"`
+ HostRoutes []interface{} `json:"host_routes,omitempty"`
+ EnableDHCP *bool `json:"enable_dhcp,omitempty"`
}
type request struct {
Subnet subnet `json:"subnet"`
}
reqBody := request{Subnet: subnet{
- NetworkID: opts.NetworkID,
Name: maybeString(opts.Name),
- TenantID: maybeString(opts.TenantID),
GatewayIP: maybeString(opts.GatewayIP),
- ID: maybeString(opts.ID),
EnableDHCP: opts.EnableDHCP,
}}
- if len(opts.AllocationPools) != 0 {
- reqBody.Subnet.AllocationPools = opts.AllocationPools
+ if len(opts.DNSNameservers) != 0 {
+ reqBody.Subnet.DNSNameservers = opts.DNSNameservers
+ }
+
+ if len(opts.HostRoutes) != 0 {
+ reqBody.Subnet.HostRoutes = opts.HostRoutes
}
type response struct {
diff --git a/openstack/networking/v2/subnets/requests_test.go b/openstack/networking/v2/subnets/requests_test.go
index edf59e7..63e9cc2 100644
--- a/openstack/networking/v2/subnets/requests_test.go
+++ b/openstack/networking/v2/subnets/requests_test.go
@@ -92,7 +92,7 @@
EnableDHCP: true,
NetworkID: "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
TenantID: "26a7980765d0414dbc1fc1f88cdb7e6e",
- DNSNameservers: []interface{}{},
+ DNSNameservers: []string{},
AllocationPools: []AllocationPool{
AllocationPool{
Start: "10.0.0.2",
@@ -110,7 +110,7 @@
EnableDHCP: true,
NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22",
TenantID: "4fd44f30292945e481c7b8a0c8908869",
- DNSNameservers: []interface{}{},
+ DNSNameservers: []string{},
AllocationPools: []AllocationPool{
AllocationPool{
Start: "192.0.0.2",
@@ -177,7 +177,7 @@
th.AssertEquals(t, s.EnableDHCP, true)
th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869")
- th.AssertDeepEquals(t, s.DNSNameservers, []interface{}{})
+ th.AssertDeepEquals(t, s.DNSNameservers, []string{})
th.AssertDeepEquals(t, s.AllocationPools, []AllocationPool{
AllocationPool{
Start: "192.0.0.2",
@@ -237,7 +237,7 @@
`)
})
- opts := SubnetOpts{NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22", IPVersion: 4, CIDR: "192.168.199.0/24"}
+ opts := CreateOpts{NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22", IPVersion: 4, CIDR: "192.168.199.0/24"}
s, err := Create(ServiceClient(), opts)
th.AssertNoErr(t, err)
@@ -245,7 +245,7 @@
th.AssertEquals(t, s.EnableDHCP, true)
th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869")
- th.AssertDeepEquals(t, s.DNSNameservers, []interface{}{})
+ th.AssertDeepEquals(t, s.DNSNameservers, []string{})
th.AssertDeepEquals(t, s.AllocationPools, []AllocationPool{
AllocationPool{
Start: "192.168.199.2",
@@ -303,7 +303,7 @@
`)
})
- opts := SubnetOpts{Name: "my_new_subnet"}
+ opts := UpdateOpts{Name: "my_new_subnet"}
s, err := Update(ServiceClient(), "08eae331-0402-425a-923c-34f7cfe39c1b", opts)
th.AssertNoErr(t, err)
@@ -311,15 +311,6 @@
th.AssertEquals(t, s.ID, "08eae331-0402-425a-923c-34f7cfe39c1b")
}
-func TestCertainAttrsCannotBeUpdated(t *testing.T) {
- opts := SubnetOpts{IPVersion: 6, CIDR: "192.0.0.1/24"}
- _, err := Update(ServiceClient(), "08eae331-0402-425a-923c-34f7cfe39c1b", opts)
-
- if err == nil {
- t.Errorf("An error was expected when updating IPVersion and CIDR, none was raised")
- }
-}
-
func TestDelete(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
diff --git a/openstack/networking/v2/subnets/results.go b/openstack/networking/v2/subnets/results.go
index 3de2668..d916a1c 100644
--- a/openstack/networking/v2/subnets/results.go
+++ b/openstack/networking/v2/subnets/results.go
@@ -11,17 +11,28 @@
}
type Subnet struct {
- Name string `mapstructure:"name" json:"name"`
- EnableDHCP bool `mapstructure:"enable_dhcp" json:"enable_dhcp"`
- NetworkID string `mapstructure:"network_id" json:"network_id"`
- TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
- DNSNameservers []interface{} `mapstructure:"dns_nameservers" json:"dns_nameservers"`
+ // UUID representing the subnet
+ ID string `mapstructure:"id" json:"id"`
+ // UUID of the parent network
+ NetworkID string `mapstructure:"network_id" json:"network_id"`
+ // Human-readable name for the subnet. Might not be unique.
+ Name string `mapstructure:"name" json:"name"`
+ // IP version, either `4' or `6'
+ IPVersion int `mapstructure:"ip_version" json:"ip_version"`
+ // CIDR representing IP range for this subnet, based on IP version
+ CIDR string `mapstructure:"cidr" json:"cidr"`
+ // Default gateway used by devices in this subnet
+ GatewayIP string `mapstructure:"gateway_ip" json:"gateway_ip"`
+ // DNS name servers used by hosts in this subnet.
+ DNSNameservers []string `mapstructure:"dns_nameservers" json:"dns_nameservers"`
+ // Sub-ranges of CIDR available for dynamic allocation to ports. See AllocationPool.
AllocationPools []AllocationPool `mapstructure:"allocation_pools" json:"allocation_pools"`
- HostRoutes []interface{} `mapstructure:"host_routes" json:"host_routes"`
- IPVersion int `mapstructure:"ip_version" json:"ip_version"`
- GatewayIP string `mapstructure:"gateway_ip" json:"gateway_ip"`
- CIDR string `mapstructure:"cidr" json:"cidr"`
- ID string `mapstructure:"id" json:"id"`
+ // Routes that should be used by devices with IPs from this subnet (not including local subnet route).
+ HostRoutes []interface{} `mapstructure:"host_routes" json:"host_routes"`
+ // Specifies whether DHCP is enabled for this subnet or not.
+ EnableDHCP bool `mapstructure:"enable_dhcp" json:"enable_dhcp"`
+ // Owner of network. Only admin users can specify a tenant_id other than its own.
+ TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
}
type SubnetPage struct {