diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index fc9201945..bf08913ba 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -997,183 +997,193 @@ }, { "ImportPath": "github.com/rackspace/gophercloud", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/schedulerhints", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/flavors", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/images", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/compute/v2/servers", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v2/tenants", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v2/tokens", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/identity/v3/tokens", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" + }, + { + "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups", + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" + }, + { + "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules", + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/networks", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/ports", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/networking/v2/subnets", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/accounts", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/containers", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/objectstorage/v1/objects", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/openstack/utils", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/pagination", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/testhelper", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/rackspace/gophercloud/testhelper/client", - "Comment": "v1.0.0-868-ga09b5b4", - "Rev": "a09b5b4eb58195b6fb3898496586b8d6aeb558e0" + "Comment": "v1.0.0-884-gc54bbac", + "Rev": "c54bbac81d19eb4df3ad167764dbb6ff2e7194de" }, { "ImportPath": "github.com/satori/go.uuid", diff --git a/vendor/github.com/rackspace/gophercloud/auth_options.go b/vendor/github.com/rackspace/gophercloud/auth_options.go index d26e16ac1..07ace1366 100644 --- a/vendor/github.com/rackspace/gophercloud/auth_options.go +++ b/vendor/github.com/rackspace/gophercloud/auth_options.go @@ -42,6 +42,11 @@ type AuthOptions struct { // re-authenticate automatically if/when your token expires. If you set it to // false, it will not cache these settings, but re-authentication will not be // possible. This setting defaults to false. + // + // NOTE: The reauth function will try to re-authenticate endlessly if left unchecked. + // The way to limit the number of attempts is to provide a custom HTTP client to the provider client + // and provide a transport that implements the RoundTripper interface and stores the number of failed retries. + // For an example of this, see here: https://github.com/rackspace/rack/blob/1.0.0/auth/clients.go#L311 AllowReauth bool // TokenID allows users to authenticate (possibly as another user) with an diff --git a/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go new file mode 100644 index 000000000..2712ac162 --- /dev/null +++ b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups/requests.go @@ -0,0 +1,131 @@ +package groups + +import ( + "fmt" + + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/pagination" +) + +// 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 floating IP attributes you want to see returned. SortKey allows you to +// sort by a particular network attribute. SortDir sets the direction, and is +// either `asc' or `desc'. Marker and Limit are used for pagination. +type ListOpts struct { + ID string `q:"id"` + Name string `q:"name"` + TenantID string `q:"tenant_id"` + Limit int `q:"limit"` + Marker string `q:"marker"` + SortKey string `q:"sort_key"` + SortDir string `q:"sort_dir"` +} + +// List returns a Pager which allows you to iterate over a collection of +// security groups. It accepts a ListOpts struct, which allows you to filter +// and sort the returned collection for greater efficiency. +func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { + q, err := gophercloud.BuildQueryString(&opts) + if err != nil { + return pagination.Pager{Err: err} + } + u := rootURL(c) + q.String() + return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { + return SecGroupPage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +var ( + errNameRequired = fmt.Errorf("Name is required") +) + +// CreateOpts contains all the values needed to create a new security group. +type CreateOpts struct { + // Required. Human-readable name for the VIP. Does not have to be unique. + Name string + + // Required for admins. Indicates the owner of the VIP. + TenantID string + + // Optional. Describes the security group. + Description string +} + +// Create is an operation which provisions a new security group with default +// security group rules for the IPv4 and IPv6 ether types. +func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult { + var res CreateResult + + // Validate required opts + if opts.Name == "" { + res.Err = errNameRequired + return res + } + + type secgroup struct { + Name string `json:"name"` + TenantID string `json:"tenant_id,omitempty"` + Description string `json:"description,omitempty"` + } + + type request struct { + SecGroup secgroup `json:"security_group"` + } + + reqBody := request{SecGroup: secgroup{ + Name: opts.Name, + TenantID: opts.TenantID, + Description: opts.Description, + }} + + _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil) + return res +} + +// Get retrieves a particular security group based on its unique ID. +func Get(c *gophercloud.ServiceClient, id string) GetResult { + var res GetResult + _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil) + return res +} + +// Delete will permanently delete a particular security group based on its unique ID. +func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { + var res DeleteResult + _, res.Err = c.Delete(resourceURL(c, id), nil) + return res +} + +// IDFromName is a convenience function that returns a security group's ID given its name. +func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) { + securityGroupCount := 0 + securityGroupID := "" + if name == "" { + return "", fmt.Errorf("A security group name must be provided.") + } + pager := List(client, ListOpts{}) + pager.EachPage(func(page pagination.Page) (bool, error) { + securityGroupList, err := ExtractGroups(page) + if err != nil { + return false, err + } + + for _, s := range securityGroupList { + if s.Name == name { + securityGroupCount++ + securityGroupID = s.ID + } + } + return true, nil + }) + + switch securityGroupCount { + case 0: + return "", fmt.Errorf("Unable to find security group: %s", name) + case 1: + return securityGroupID, nil + default: + return "", fmt.Errorf("Found %d security groups matching %s", securityGroupCount, name) + } +} diff --git a/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups/results.go b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups/results.go new file mode 100644 index 000000000..49db261c2 --- /dev/null +++ b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups/results.go @@ -0,0 +1,108 @@ +package groups + +import ( + "github.com/mitchellh/mapstructure" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules" + "github.com/rackspace/gophercloud/pagination" +) + +// SecGroup represents a container for security group rules. +type SecGroup struct { + // The UUID for the security group. + ID string + + // Human-readable name for the security group. Might not be unique. Cannot be + // named "default" as that is automatically created for a tenant. + Name string + + // The security group description. + Description string + + // A slice of security group rules that dictate the permitted behaviour for + // traffic entering and leaving the group. + Rules []rules.SecGroupRule `json:"security_group_rules" mapstructure:"security_group_rules"` + + // Owner of the security group. Only admin users can specify a TenantID + // other than their own. + TenantID string `json:"tenant_id" mapstructure:"tenant_id"` +} + +// SecGroupPage is the page returned by a pager when traversing over a +// collection of security groups. +type SecGroupPage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of security groups 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 SecGroupPage) NextPageURL() (string, error) { + type resp struct { + Links []gophercloud.Link `mapstructure:"security_groups_links"` + } + + var r resp + err := mapstructure.Decode(p.Body, &r) + if err != nil { + return "", err + } + + return gophercloud.ExtractNextURL(r.Links) +} + +// IsEmpty checks whether a SecGroupPage struct is empty. +func (p SecGroupPage) IsEmpty() (bool, error) { + is, err := ExtractGroups(p) + if err != nil { + return true, nil + } + return len(is) == 0, nil +} + +// ExtractGroups accepts a Page struct, specifically a SecGroupPage struct, +// and extracts the elements into a slice of SecGroup structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractGroups(page pagination.Page) ([]SecGroup, error) { + var resp struct { + SecGroups []SecGroup `mapstructure:"security_groups" json:"security_groups"` + } + + err := mapstructure.Decode(page.(SecGroupPage).Body, &resp) + + return resp.SecGroups, err +} + +type commonResult struct { + gophercloud.Result +} + +// Extract is a function that accepts a result and extracts a security group. +func (r commonResult) Extract() (*SecGroup, error) { + if r.Err != nil { + return nil, r.Err + } + + var res struct { + SecGroup *SecGroup `mapstructure:"security_group" json:"security_group"` + } + + err := mapstructure.Decode(r.Body, &res) + + return res.SecGroup, err +} + +// CreateResult represents the result of a create operation. +type CreateResult struct { + commonResult +} + +// GetResult represents the result of a get operation. +type GetResult struct { + commonResult +} + +// DeleteResult represents the result of a delete operation. +type DeleteResult struct { + gophercloud.ErrResult +} diff --git a/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups/urls.go b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups/urls.go new file mode 100644 index 000000000..84f7324f0 --- /dev/null +++ b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups/urls.go @@ -0,0 +1,13 @@ +package groups + +import "github.com/rackspace/gophercloud" + +const rootPath = "security-groups" + +func rootURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL(rootPath) +} + +func resourceURL(c *gophercloud.ServiceClient, id string) string { + return c.ServiceURL(rootPath, id) +} diff --git a/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules/requests.go b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules/requests.go new file mode 100644 index 000000000..e06934a09 --- /dev/null +++ b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules/requests.go @@ -0,0 +1,174 @@ +package rules + +import ( + "fmt" + + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/pagination" +) + +// 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 security group attributes you want to see returned. SortKey allows you to +// sort by a particular network attribute. SortDir sets the direction, and is +// either `asc' or `desc'. Marker and Limit are used for pagination. +type ListOpts struct { + Direction string `q:"direction"` + EtherType string `q:"ethertype"` + ID string `q:"id"` + PortRangeMax int `q:"port_range_max"` + PortRangeMin int `q:"port_range_min"` + Protocol string `q:"protocol"` + RemoteGroupID string `q:"remote_group_id"` + RemoteIPPrefix string `q:"remote_ip_prefix"` + SecGroupID string `q:"security_group_id"` + TenantID string `q:"tenant_id"` + Limit int `q:"limit"` + Marker string `q:"marker"` + SortKey string `q:"sort_key"` + SortDir string `q:"sort_dir"` +} + +// List returns a Pager which allows you to iterate over a collection of +// security group rules. It accepts a ListOpts struct, which allows you to filter +// and sort the returned collection for greater efficiency. +func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager { + q, err := gophercloud.BuildQueryString(&opts) + if err != nil { + return pagination.Pager{Err: err} + } + u := rootURL(c) + q.String() + return pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { + return SecGroupRulePage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// Errors +var ( + errValidDirectionRequired = fmt.Errorf("A valid Direction is required") + errValidEtherTypeRequired = fmt.Errorf("A valid EtherType is required") + errSecGroupIDRequired = fmt.Errorf("A valid SecGroupID is required") + errValidProtocolRequired = fmt.Errorf("A valid Protocol is required") +) + +// Constants useful for CreateOpts +const ( + DirIngress = "ingress" + DirEgress = "egress" + Ether4 = "IPv4" + Ether6 = "IPv6" + ProtocolTCP = "tcp" + ProtocolUDP = "udp" + ProtocolICMP = "icmp" +) + +// CreateOpts contains all the values needed to create a new security group rule. +type CreateOpts struct { + // Required. Must be either "ingress" or "egress": the direction in which the + // security group rule is applied. + Direction string + + // Required. Must be "IPv4" or "IPv6", and addresses represented in CIDR must + // match the ingress or egress rules. + EtherType string + + // Required. The security group ID to associate with this security group rule. + SecGroupID string + + // Optional. The maximum port number in the range that is matched by the + // security group rule. The PortRangeMin attribute constrains the PortRangeMax + // attribute. If the protocol is ICMP, this value must be an ICMP type. + PortRangeMax int + + // Optional. The minimum port number in the range that is matched by the + // security group rule. If the protocol is TCP or UDP, this value must be + // less than or equal to the value of the PortRangeMax attribute. If the + // protocol is ICMP, this value must be an ICMP type. + PortRangeMin int + + // Optional. The protocol that is matched by the security group rule. Valid + // values are "tcp", "udp", "icmp" or an empty string. + Protocol string + + // Optional. The remote group ID to be associated with this security group + // rule. You can specify either RemoteGroupID or RemoteIPPrefix. + RemoteGroupID string + + // Optional. The remote IP prefix to be associated with this security group + // rule. You can specify either RemoteGroupID or RemoteIPPrefix. This + // attribute matches the specified IP prefix as the source IP address of the + // IP packet. + RemoteIPPrefix string + + // Required for admins. Indicates the owner of the VIP. + TenantID string +} + +// Create is an operation which adds a new security group rule and associates it +// with an existing security group (whose ID is specified in CreateOpts). +func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult { + var res CreateResult + + // Validate required opts + if opts.Direction != DirIngress && opts.Direction != DirEgress { + res.Err = errValidDirectionRequired + return res + } + if opts.EtherType != Ether4 && opts.EtherType != Ether6 { + res.Err = errValidEtherTypeRequired + return res + } + if opts.SecGroupID == "" { + res.Err = errSecGroupIDRequired + return res + } + if opts.Protocol != "" && opts.Protocol != ProtocolTCP && opts.Protocol != ProtocolUDP && opts.Protocol != ProtocolICMP { + res.Err = errValidProtocolRequired + return res + } + + type secrule struct { + Direction string `json:"direction"` + EtherType string `json:"ethertype"` + SecGroupID string `json:"security_group_id"` + PortRangeMax int `json:"port_range_max,omitempty"` + PortRangeMin int `json:"port_range_min,omitempty"` + Protocol string `json:"protocol,omitempty"` + RemoteGroupID string `json:"remote_group_id,omitempty"` + RemoteIPPrefix string `json:"remote_ip_prefix,omitempty"` + TenantID string `json:"tenant_id,omitempty"` + } + + type request struct { + SecRule secrule `json:"security_group_rule"` + } + + reqBody := request{SecRule: secrule{ + Direction: opts.Direction, + EtherType: opts.EtherType, + SecGroupID: opts.SecGroupID, + PortRangeMax: opts.PortRangeMax, + PortRangeMin: opts.PortRangeMin, + Protocol: opts.Protocol, + RemoteGroupID: opts.RemoteGroupID, + RemoteIPPrefix: opts.RemoteIPPrefix, + TenantID: opts.TenantID, + }} + + _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil) + return res +} + +// Get retrieves a particular security group rule based on its unique ID. +func Get(c *gophercloud.ServiceClient, id string) GetResult { + var res GetResult + _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil) + return res +} + +// Delete will permanently delete a particular security group rule based on its unique ID. +func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { + var res DeleteResult + _, res.Err = c.Delete(resourceURL(c, id), nil) + return res +} diff --git a/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules/results.go b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules/results.go new file mode 100644 index 000000000..6e1385768 --- /dev/null +++ b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules/results.go @@ -0,0 +1,133 @@ +package rules + +import ( + "github.com/mitchellh/mapstructure" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/pagination" +) + +// SecGroupRule represents a rule to dictate the behaviour of incoming or +// outgoing traffic for a particular security group. +type SecGroupRule struct { + // The UUID for this security group rule. + ID string + + // The direction in which the security group rule is applied. The only values + // allowed are "ingress" or "egress". For a compute instance, an ingress + // security group rule is applied to incoming (ingress) traffic for that + // instance. An egress rule is applied to traffic leaving the instance. + Direction string + + // Must be IPv4 or IPv6, and addresses represented in CIDR must match the + // ingress or egress rules. + EtherType string `json:"ethertype" mapstructure:"ethertype"` + + // The security group ID to associate with this security group rule. + SecGroupID string `json:"security_group_id" mapstructure:"security_group_id"` + + // The minimum port number in the range that is matched by the security group + // rule. If the protocol is TCP or UDP, this value must be less than or equal + // to the value of the PortRangeMax attribute. If the protocol is ICMP, this + // value must be an ICMP type. + PortRangeMin int `json:"port_range_min" mapstructure:"port_range_min"` + + // The maximum port number in the range that is matched by the security group + // rule. The PortRangeMin attribute constrains the PortRangeMax attribute. If + // the protocol is ICMP, this value must be an ICMP type. + PortRangeMax int `json:"port_range_max" mapstructure:"port_range_max"` + + // The protocol that is matched by the security group rule. Valid values are + // "tcp", "udp", "icmp" or an empty string. + Protocol string + + // The remote group ID to be associated with this security group rule. You + // can specify either RemoteGroupID or RemoteIPPrefix. + RemoteGroupID string `json:"remote_group_id" mapstructure:"remote_group_id"` + + // The remote IP prefix to be associated with this security group rule. You + // can specify either RemoteGroupID or RemoteIPPrefix . This attribute + // matches the specified IP prefix as the source IP address of the IP packet. + RemoteIPPrefix string `json:"remote_ip_prefix" mapstructure:"remote_ip_prefix"` + + // The owner of this security group rule. + TenantID string `json:"tenant_id" mapstructure:"tenant_id"` +} + +// SecGroupRulePage is the page returned by a pager when traversing over a +// collection of security group rules. +type SecGroupRulePage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of security group rules 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 SecGroupRulePage) NextPageURL() (string, error) { + type resp struct { + Links []gophercloud.Link `mapstructure:"security_group_rules_links"` + } + + var r resp + err := mapstructure.Decode(p.Body, &r) + if err != nil { + return "", err + } + + return gophercloud.ExtractNextURL(r.Links) +} + +// IsEmpty checks whether a SecGroupRulePage struct is empty. +func (p SecGroupRulePage) IsEmpty() (bool, error) { + is, err := ExtractRules(p) + if err != nil { + return true, nil + } + return len(is) == 0, nil +} + +// ExtractRules accepts a Page struct, specifically a SecGroupRulePage struct, +// and extracts the elements into a slice of SecGroupRule structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractRules(page pagination.Page) ([]SecGroupRule, error) { + var resp struct { + SecGroupRules []SecGroupRule `mapstructure:"security_group_rules" json:"security_group_rules"` + } + + err := mapstructure.Decode(page.(SecGroupRulePage).Body, &resp) + + return resp.SecGroupRules, err +} + +type commonResult struct { + gophercloud.Result +} + +// Extract is a function that accepts a result and extracts a security rule. +func (r commonResult) Extract() (*SecGroupRule, error) { + if r.Err != nil { + return nil, r.Err + } + + var res struct { + SecGroupRule *SecGroupRule `mapstructure:"security_group_rule" json:"security_group_rule"` + } + + err := mapstructure.Decode(r.Body, &res) + + return res.SecGroupRule, err +} + +// CreateResult represents the result of a create operation. +type CreateResult struct { + commonResult +} + +// GetResult represents the result of a get operation. +type GetResult struct { + commonResult +} + +// DeleteResult represents the result of a delete operation. +type DeleteResult struct { + gophercloud.ErrResult +} diff --git a/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules/urls.go b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules/urls.go new file mode 100644 index 000000000..8e2b2bb28 --- /dev/null +++ b/vendor/github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules/urls.go @@ -0,0 +1,13 @@ +package rules + +import "github.com/rackspace/gophercloud" + +const rootPath = "security-group-rules" + +func rootURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL(rootPath) +} + +func resourceURL(c *gophercloud.ServiceClient, id string) string { + return c.ServiceURL(rootPath, id) +}