Support FWaaS - Policies
diff --git a/openstack/networking/v2/extensions/fwaas/policies/requests.go b/openstack/networking/v2/extensions/fwaas/policies/requests.go
new file mode 100644
index 0000000..5242f3a
--- /dev/null
+++ b/openstack/networking/v2/extensions/fwaas/policies/requests.go
@@ -0,0 +1,175 @@
+package policies
+
+import (
+ "github.com/racker/perigee"
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/pagination"
+)
+
+type ListOpts struct {
+ TenantID string `q:"tenant_id"`
+ Name string `q:"name"`
+ Description string `q:"description"`
+ ID string `q:"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
+// firewall policies. It accepts a ListOpts struct, which allows you to filter
+// and sort the returned collection for greater efficiency.
+//
+// Default policy settings return only those firewall policies that are owned by the
+// tenant who submits the request, unless an admin user submits the request.
+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 PolicyPage{pagination.LinkedPageBase{PageResult: r}}
+ })
+}
+
+// CreateOpts contains all the values needed to create a new firewall policy.
+type CreateOpts struct {
+ // Only required if the caller has an admin role and wants to create a firewall policy
+ // for another tenant.
+ TenantId string
+ Name string
+ Description string
+ Rules []string
+}
+
+// Create accepts a CreateOpts struct and uses the values to create a new firewall policy
+func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
+ type policy struct {
+ TenantId string `json:"tenant_id,omitempty"`
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ Rules []string `json:"firewall_rules,omitempty"`
+ }
+ type request struct {
+ Policy policy `json:"firewall_policy"`
+ }
+
+ reqBody := request{Policy: policy{
+ TenantId: opts.TenantId,
+ Name: opts.Name,
+ Description: opts.Description,
+ Rules: opts.Rules,
+ }}
+
+ var res CreateResult
+ _, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
+ MoreHeaders: c.AuthenticatedHeaders(),
+ ReqBody: &reqBody,
+ Results: &res.Body,
+ OkCodes: []int{201},
+ })
+ return res
+}
+
+// Get retrieves a particular firewall policy based on its unique ID.
+func Get(c *gophercloud.ServiceClient, id string) GetResult {
+ var res GetResult
+ _, res.Err = perigee.Request("GET", resourceURL(c, id), perigee.Options{
+ MoreHeaders: c.AuthenticatedHeaders(),
+ Results: &res.Body,
+ OkCodes: []int{200},
+ })
+ return res
+}
+
+// UpdateOpts contains the values used when updating a firewall policy.
+type UpdateOpts struct {
+ // Name of the firewall policy.
+ Name string
+ Description string
+ Rules []string
+}
+
+// Update allows firewall policies to be updated.
+func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResult {
+ type policy struct {
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Rules []string `json:"firewall_rules,omitempty"`
+ }
+ type request struct {
+ Policy policy `json:"firewall_policy"`
+ }
+
+ reqBody := request{Policy: policy{
+ Name: opts.Name,
+ Description: opts.Description,
+ Rules: opts.Rules,
+ }}
+
+ // Send request to API
+ var res UpdateResult
+ _, res.Err = perigee.Request("PUT", resourceURL(c, id), perigee.Options{
+ MoreHeaders: c.AuthenticatedHeaders(),
+ ReqBody: &reqBody,
+ Results: &res.Body,
+ OkCodes: []int{200},
+ })
+ return res
+}
+
+// Delete will permanently delete a particular firewall policy based on its unique ID.
+func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
+ var res DeleteResult
+ _, res.Err = perigee.Request("DELETE", resourceURL(c, id), perigee.Options{
+ MoreHeaders: c.AuthenticatedHeaders(),
+ OkCodes: []int{204},
+ })
+ return res
+}
+
+func InsertRule(c *gophercloud.ServiceClient, policyID, ruleID, beforeID, afterID string) error {
+ type request struct {
+ RuleId string `json:"firewall_rule_id"`
+ Before string `json:"insert_before,omitempty"`
+ After string `json:"insert_after,omitempty"`
+ }
+
+ reqBody := request{
+ RuleId: ruleID,
+ Before: beforeID,
+ After: afterID,
+ }
+
+ // Send request to API
+ var res commonResult
+ _, res.Err = perigee.Request("PUT", insertURL(c, policyID), perigee.Options{
+ MoreHeaders: c.AuthenticatedHeaders(),
+ ReqBody: &reqBody,
+ Results: &res.Body,
+ OkCodes: []int{200},
+ })
+ return res.Err
+}
+
+func RemoveRule(c *gophercloud.ServiceClient, policyID, ruleID string) error {
+ type request struct {
+ RuleId string `json:"firewall_rule_id"`
+ }
+
+ reqBody := request{
+ RuleId: ruleID,
+ }
+
+ // Send request to API
+ var res commonResult
+ _, res.Err = perigee.Request("PUT", removeURL(c, policyID), perigee.Options{
+ MoreHeaders: c.AuthenticatedHeaders(),
+ ReqBody: &reqBody,
+ Results: &res.Body,
+ OkCodes: []int{200},
+ })
+ return res.Err
+}
diff --git a/openstack/networking/v2/extensions/fwaas/policies/requests_test.go b/openstack/networking/v2/extensions/fwaas/policies/requests_test.go
new file mode 100644
index 0000000..cdf6fbd
--- /dev/null
+++ b/openstack/networking/v2/extensions/fwaas/policies/requests_test.go
@@ -0,0 +1,3 @@
+package policies
+
+// TODO
diff --git a/openstack/networking/v2/extensions/fwaas/policies/results.go b/openstack/networking/v2/extensions/fwaas/policies/results.go
new file mode 100644
index 0000000..cc8842f
--- /dev/null
+++ b/openstack/networking/v2/extensions/fwaas/policies/results.go
@@ -0,0 +1,98 @@
+package policies
+
+import (
+ "github.com/mitchellh/mapstructure"
+ "github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/pagination"
+)
+
+type Policy struct {
+ Id string `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Rules []string `json:"firewall_rules,omitempty" mapstructure:"firewall_rules"`
+}
+
+type commonResult struct {
+ gophercloud.Result
+}
+
+// Extract is a function that accepts a result and extracts a firewall policy.
+func (r commonResult) Extract() (*Policy, error) {
+ if r.Err != nil {
+ return nil, r.Err
+ }
+
+ var res struct {
+ Policy *Policy `json:"firewall_policy" mapstructure:"firewall_policy"`
+ }
+
+ err := mapstructure.Decode(r.Body, &res)
+
+ return res.Policy, err
+}
+
+// PolicyPage is the page returned by a pager when traversing over a
+// collection of firewall policies.
+type PolicyPage struct {
+ pagination.LinkedPageBase
+}
+
+// NextPageURL is invoked when a paginated collection of firewall policies 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 PolicyPage) NextPageURL() (string, error) {
+ type resp struct {
+ Links []gophercloud.Link `mapstructure:"firewall_policies_links"`
+ }
+
+ var r resp
+ err := mapstructure.Decode(p.Body, &r)
+ if err != nil {
+ return "", err
+ }
+
+ return gophercloud.ExtractNextURL(r.Links)
+}
+
+// IsEmpty checks whether a PolicyPage struct is empty.
+func (p PolicyPage) IsEmpty() (bool, error) {
+ is, err := ExtractPolicies(p)
+ if err != nil {
+ return true, nil
+ }
+ return len(is) == 0, nil
+}
+
+// ExtractPolicies accepts a Page struct, specifically a RouterPage struct,
+// and extracts the elements into a slice of Router structs. In other words,
+// a generic collection is mapped into a relevant slice.
+func ExtractPolicies(page pagination.Page) ([]Policy, error) {
+ var resp struct {
+ Policies []Policy `mapstructure:"firewall_policies" json:"firewall_policies"`
+ }
+
+ err := mapstructure.Decode(page.(PolicyPage).Body, &resp)
+
+ return resp.Policies, err
+}
+
+// GetResult represents the result of a get operation.
+type GetResult struct {
+ commonResult
+}
+
+// UpdateResult represents the result of an update operation.
+type UpdateResult struct {
+ commonResult
+}
+
+// DeleteResult represents the result of a delete operation.
+type DeleteResult struct {
+ gophercloud.ErrResult
+}
+
+// CreateResult represents the result of a create operation.
+type CreateResult struct {
+ commonResult
+}
diff --git a/openstack/networking/v2/extensions/fwaas/policies/urls.go b/openstack/networking/v2/extensions/fwaas/policies/urls.go
new file mode 100644
index 0000000..27ea9ae
--- /dev/null
+++ b/openstack/networking/v2/extensions/fwaas/policies/urls.go
@@ -0,0 +1,26 @@
+package policies
+
+import "github.com/rackspace/gophercloud"
+
+const (
+ rootPath = "fw"
+ resourcePath = "firewall_policies"
+ insertPath = "insert_rule"
+ removePath = "remove_rule"
+)
+
+func rootURL(c *gophercloud.ServiceClient) string {
+ return c.ServiceURL(rootPath, resourcePath)
+}
+
+func resourceURL(c *gophercloud.ServiceClient, id string) string {
+ return c.ServiceURL(rootPath, resourcePath, id)
+}
+
+func insertURL(c *gophercloud.ServiceClient, id string) string {
+ return c.ServiceURL(rootPath, resourcePath, id, insertPath)
+}
+
+func removeURL(c *gophercloud.ServiceClient, id string) string {
+ return c.ServiceURL(rootPath, resourcePath, id, removePath)
+}