Finishing documentation
diff --git a/openstack/networking/v2/subnets/doc.go b/openstack/networking/v2/subnets/doc.go
index b15101b..43e8296 100644
--- a/openstack/networking/v2/subnets/doc.go
+++ b/openstack/networking/v2/subnets/doc.go
@@ -1 +1,10 @@
+// Package subnets contains functionality for working with Neutron subnet
+// resources. A subnet represents an IP address block that can be used to
+// assign IP addresses to virtual instances. Each subnet must have a CIDR and
+// must be associated with a network. IPs can either be selected from the whole
+// subnet CIDR or from allocation pools specified by the user.
+//
+// A subnet can also have a gateway, a list of DNS name servers, and host routes.
+// This information is pushed to instances whose interfaces are associated with
+// the subnet.
package subnets
diff --git a/openstack/networking/v2/subnets/errors.go b/openstack/networking/v2/subnets/errors.go
index ca2df72..0db0a6e 100644
--- a/openstack/networking/v2/subnets/errors.go
+++ b/openstack/networking/v2/subnets/errors.go
@@ -7,9 +7,7 @@
}
var (
- ErrNetworkIDRequired = err("A network ID is required")
- ErrCIDRRequired = err("A valid CIDR is required")
- ErrInvalidIPType = err("An IP type must either be 4 or 6")
- ErrCIDRNotUpdatable = err("CIDR attributes cannot be updated")
- ErrIPVersionNotUpdatable = err("IP Version attributes cannot be updated")
+ errNetworkIDRequired = err("A network ID is required")
+ errCIDRRequired = err("A valid CIDR is required")
+ errInvalidIPType = err("An IP type must either be 4 or 6")
)
diff --git a/openstack/networking/v2/subnets/requests.go b/openstack/networking/v2/subnets/requests.go
index ff36765..5a07863 100644
--- a/openstack/networking/v2/subnets/requests.go
+++ b/openstack/networking/v2/subnets/requests.go
@@ -9,6 +9,18 @@
"github.com/rackspace/gophercloud/pagination"
)
+func maybeString(original string) *string {
+ if original != "" {
+ return &original
+ }
+ return nil
+}
+
+// ListOpts allows the filtering and sorting of paginated collections through
+// the API. Filtering is achieved by passing in struct field values that map to
+// the subnet attributes you want to see returned. SortKey allows you to sort
+// by a particular subnet attribute. SortDir sets the direction, and is either
+// `asc' or `desc'. Marker and Limit are used for pagination.
type ListOpts struct {
Name string
EnableDHCP *bool
@@ -19,12 +31,18 @@
CIDR string
ID string
Limit int
- Page string
- PerPage string
+ Marker string
SortKey string
SortDir string
}
+// List returns a Pager which allows you to iterate over a collection of
+// subnets. It accepts a ListOpts struct, which allows you to filter and sort
+// the returned collection for greater efficiency.
+//
+// Default policy settings return only those subnets that are owned by the tenant
+// who submits the request, unless the request is submitted by an user with
+// administrative rights.
func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
// Build query parameters
q := make(map[string]string)
@@ -55,11 +73,8 @@
if opts.Limit != 0 {
q["limit"] = strconv.Itoa(opts.Limit)
}
- if opts.Page != "" {
- q["page"] = opts.Page
- }
- if opts.PerPage != "" {
- q["per_page"] = opts.PerPage
+ if opts.Marker != "" {
+ q["marker"] = opts.Marker
}
if opts.SortKey != "" {
q["sort_key"] = opts.SortKey
@@ -68,15 +83,16 @@
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 SubnetPage{pagination.LinkedPageBase(r)}
})
}
+// Get retrieves a specific subnet based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) (*Subnet, error) {
var s Subnet
- _, err := perigee.Request("GET", GetURL(c, id), perigee.Options{
+ _, err := perigee.Request("GET", getURL(c, id), perigee.Options{
MoreHeaders: c.Provider.AuthenticatedHeaders(),
Results: &struct {
Subnet *Subnet `json:"subnet"`
@@ -89,19 +105,13 @@
return &s, nil
}
-// maybeString returns nil for empty strings and nil for empty.
-func maybeString(original string) *string {
- if original != "" {
- return &original
- }
- return nil
-}
-
+// Valid IP types
const (
IPv4 = 4
IPv6 = 6
)
+// CreateOpts represents the attributes used when creating a new subnet.
type CreateOpts struct {
// Required
NetworkID string
@@ -117,16 +127,18 @@
HostRoutes []interface{}
}
+// Create accepts a CreateOpts struct and creates a new subnet using the values
+// provided. You must remember to provide a valid NetworkID, CIDR and IP version.
func Create(c *gophercloud.ServiceClient, opts CreateOpts) (*Subnet, error) {
// Validate required options
if opts.NetworkID == "" {
- return nil, ErrNetworkIDRequired
+ return nil, errNetworkIDRequired
}
if opts.CIDR == "" {
- return nil, ErrCIDRRequired
+ return nil, errCIDRRequired
}
if opts.IPVersion != 0 && opts.IPVersion != IPv4 && opts.IPVersion != IPv6 {
- return nil, ErrInvalidIPType
+ return nil, errInvalidIPType
}
type subnet struct {
@@ -172,7 +184,7 @@
}
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,
@@ -185,6 +197,7 @@
return res.Subnet, nil
}
+// UpdateOpts represents the attributes used when updating an existing subnet.
type UpdateOpts struct {
Name string
GatewayIP string
@@ -193,6 +206,8 @@
EnableDHCP *bool
}
+// Update accepts a UpdateOpts struct and updates an existing subnet using the
+// values provided.
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (*Subnet, error) {
type subnet struct {
Name *string `json:"name,omitempty"`
@@ -224,7 +239,7 @@
}
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,
@@ -237,8 +252,9 @@
return res.Subnet, nil
}
+// Delete accepts a unique ID and deletes the subnet associated with it.
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/subnets/results.go b/openstack/networking/v2/subnets/results.go
index d916a1c..f89bb3b 100644
--- a/openstack/networking/v2/subnets/results.go
+++ b/openstack/networking/v2/subnets/results.go
@@ -5,11 +5,14 @@
"github.com/rackspace/gophercloud/pagination"
)
+// AllocationPool is a sub-struct that represents an allocation pool
type AllocationPool struct {
Start string `json:"start"`
End string `json:"end"`
}
+// Subnet represents a subnet. See package documentation for a top-level
+// description of what this is.
type Subnet struct {
// UUID representing the subnet
ID string `mapstructure:"id" json:"id"`
@@ -35,11 +38,16 @@
TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
}
+// SubnetPage is the page returned by a pager when traversing over a collection
+// of subnets.
type SubnetPage struct {
pagination.LinkedPageBase
}
-func (current SubnetPage) NextPageURL() (string, error) {
+// NextPageURL is invoked when a paginated collection of subnets has reached
+// the end of a page and the pager seeks to traverse over a new one. In order
+// to do this, it needs to construct the next page's URL.
+func (p SubnetPage) NextPageURL() (string, error) {
type link struct {
Href string `mapstructure:"href"`
Rel string `mapstructure:"rel"`
@@ -49,7 +57,7 @@
}
var r resp
- err := mapstructure.Decode(current.Body, &r)
+ err := mapstructure.Decode(p.Body, &r)
if err != nil {
return "", err
}
@@ -67,14 +75,18 @@
return url, nil
}
-func (r SubnetPage) IsEmpty() (bool, error) {
- is, err := ExtractSubnets(r)
+// IsEmpty checks whether a SubnetPage struct is empty.
+func (p SubnetPage) IsEmpty() (bool, error) {
+ is, err := ExtractSubnets(p)
if err != nil {
return true, nil
}
return len(is) == 0, nil
}
+// ExtractSubnets accepts a Page struct, specifically a SubnetPage struct,
+// and extracts the elements into a slice of Subnet structs. In other words,
+// a generic collection is mapped into a relevant slice.
func ExtractSubnets(page pagination.Page) ([]Subnet, error) {
var resp struct {
Subnets []Subnet `mapstructure:"subnets" json:"subnets"`
diff --git a/openstack/networking/v2/subnets/urls.go b/openstack/networking/v2/subnets/urls.go
index fe20c53..ca70b66 100644
--- a/openstack/networking/v2/subnets/urls.go
+++ b/openstack/networking/v2/subnets/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, "subnets", id)
+func resourceURL(c *gophercloud.ServiceClient, id string) string {
+ return c.ServiceURL(version, "subnets", id)
}
-func RootURL(c *gophercloud.ServiceClient) string {
- return c.ServiceURL(Version, "subnets")
+func rootURL(c *gophercloud.ServiceClient) string {
+ return c.ServiceURL(version, "subnets")
}
-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/subnets/urls_tests.go b/openstack/networking/v2/subnets/urls_tests.go
index eec5275..b04b432 100644
--- a/openstack/networking/v2/subnets/urls_tests.go
+++ b/openstack/networking/v2/subnets/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/subnets"
+ actual := listURL(endpointClient())
+ expected := endpoint + "v2.0/subnets"
th.AssertEquals(t, expected, actual)
}
func TestGetURL(t *testing.T) {
- actual := GetURL(EndpointClient(), "foo")
- expected := Endpoint + "v2.0/subnets/foo"
+ actual := getURL(endpointClient(), "foo")
+ expected := endpoint + "v2.0/subnets/foo"
th.AssertEquals(t, expected, actual)
}
func TestCreateURL(t *testing.T) {
- actual := CreateURL(EndpointClient())
- expected := Endpoint + "v2.0/subnets"
+ actual := createURL(endpointClient())
+ expected := endpoint + "v2.0/subnets"
th.AssertEquals(t, expected, actual)
}
func TestUpdateURL(t *testing.T) {
- actual := UpdateURL(EndpointClient(), "foo")
- expected := Endpoint + "v2.0/subnets/foo"
+ actual := updateURL(endpointClient(), "foo")
+ expected := endpoint + "v2.0/subnets/foo"
th.AssertEquals(t, expected, actual)
}
func TestDeleteURL(t *testing.T) {
- actual := DeleteURL(EndpointClient(), "foo")
- expected := Endpoint + "v2.0/subnets/foo"
+ actual := deleteURL(endpointClient(), "foo")
+ expected := endpoint + "v2.0/subnets/foo"
th.AssertEquals(t, expected, actual)
}