1package rules
2
3import (
4	"github.com/gophercloud/gophercloud"
5	"github.com/gophercloud/gophercloud/pagination"
6)
7
8type (
9	// Protocol represents a valid rule protocol.
10	Protocol string
11)
12
13const (
14	// ProtocolAny is to allow any protocol.
15	ProtocolAny Protocol = "any"
16
17	// ProtocolICMP is to allow the ICMP protocol.
18	ProtocolICMP Protocol = "icmp"
19
20	// ProtocolTCP is to allow the TCP protocol.
21	ProtocolTCP Protocol = "tcp"
22
23	// ProtocolUDP is to allow the UDP protocol.
24	ProtocolUDP Protocol = "udp"
25)
26
27// ListOptsBuilder allows extensions to add additional parameters to the
28// List request.
29type ListOptsBuilder interface {
30	ToRuleListQuery() (string, error)
31}
32
33// ListOpts allows the filtering and sorting of paginated collections through
34// the API. Filtering is achieved by passing in struct field values that map to
35// the Firewall rule attributes you want to see returned. SortKey allows you to
36// sort by a particular firewall rule attribute. SortDir sets the direction, and
37// is either `asc' or `desc'. Marker and Limit are used for pagination.
38type ListOpts struct {
39	TenantID             string `q:"tenant_id"`
40	ProjectID            string `q:"project_id"`
41	Name                 string `q:"name"`
42	Description          string `q:"description"`
43	Protocol             string `q:"protocol"`
44	Action               string `q:"action"`
45	IPVersion            int    `q:"ip_version"`
46	SourceIPAddress      string `q:"source_ip_address"`
47	DestinationIPAddress string `q:"destination_ip_address"`
48	SourcePort           string `q:"source_port"`
49	DestinationPort      string `q:"destination_port"`
50	Enabled              bool   `q:"enabled"`
51	ID                   string `q:"id"`
52	Limit                int    `q:"limit"`
53	Marker               string `q:"marker"`
54	SortKey              string `q:"sort_key"`
55	SortDir              string `q:"sort_dir"`
56}
57
58// ToRuleListQuery formats a ListOpts into a query string.
59func (opts ListOpts) ToRuleListQuery() (string, error) {
60	q, err := gophercloud.BuildQueryString(opts)
61	if err != nil {
62		return "", err
63	}
64	return q.String(), nil
65}
66
67// List returns a Pager which allows you to iterate over a collection of
68// firewall rules. It accepts a ListOpts struct, which allows you to filter
69// and sort the returned collection for greater efficiency.
70//
71// Default policy settings return only those firewall rules that are owned by
72// the tenant who submits the request, unless an admin user submits the request.
73func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
74	url := rootURL(c)
75
76	if opts != nil {
77		query, err := opts.ToRuleListQuery()
78		if err != nil {
79			return pagination.Pager{Err: err}
80		}
81		url += query
82	}
83
84	return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
85		return RulePage{pagination.LinkedPageBase{PageResult: r}}
86	})
87}
88
89// CreateOptsBuilder allows extensions to add additional parameters to the
90// Create request.
91type CreateOptsBuilder interface {
92	ToRuleCreateMap() (map[string]interface{}, error)
93}
94
95// CreateOpts contains all the values needed to create a new firewall rule.
96type CreateOpts struct {
97	Protocol             Protocol              `json:"protocol" required:"true"`
98	Action               string                `json:"action" required:"true"`
99	TenantID             string                `json:"tenant_id,omitempty"`
100	ProjectID            string                `json:"project_id,omitempty"`
101	Name                 string                `json:"name,omitempty"`
102	Description          string                `json:"description,omitempty"`
103	IPVersion            gophercloud.IPVersion `json:"ip_version,omitempty"`
104	SourceIPAddress      string                `json:"source_ip_address,omitempty"`
105	DestinationIPAddress string                `json:"destination_ip_address,omitempty"`
106	SourcePort           string                `json:"source_port,omitempty"`
107	DestinationPort      string                `json:"destination_port,omitempty"`
108	Shared               *bool                 `json:"shared,omitempty"`
109	Enabled              *bool                 `json:"enabled,omitempty"`
110}
111
112// ToRuleCreateMap casts a CreateOpts struct to a map.
113func (opts CreateOpts) ToRuleCreateMap() (map[string]interface{}, error) {
114	b, err := gophercloud.BuildRequestBody(opts, "firewall_rule")
115	if err != nil {
116		return nil, err
117	}
118
119	if m := b["firewall_rule"].(map[string]interface{}); m["protocol"] == "any" {
120		m["protocol"] = nil
121	}
122
123	return b, nil
124}
125
126// Create accepts a CreateOpts struct and uses the values to create a new
127// firewall rule.
128func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
129	b, err := opts.ToRuleCreateMap()
130	if err != nil {
131		r.Err = err
132		return
133	}
134	_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
135	return
136}
137
138// Get retrieves a particular firewall rule based on its unique ID.
139func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
140	_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
141	return
142}
143
144// UpdateOptsBuilder allows extensions to add additional parameters to the
145// Update request.
146type UpdateOptsBuilder interface {
147	ToRuleUpdateMap() (map[string]interface{}, error)
148}
149
150// UpdateOpts contains the values used when updating a firewall rule.
151// These fields are all pointers so that unset fields will not cause the
152// existing Rule attribute to be removed.
153type UpdateOpts struct {
154	Protocol             *string                `json:"protocol,omitempty"`
155	Action               *string                `json:"action,omitempty"`
156	Name                 *string                `json:"name,omitempty"`
157	Description          *string                `json:"description,omitempty"`
158	IPVersion            *gophercloud.IPVersion `json:"ip_version,omitempty"`
159	SourceIPAddress      *string                `json:"source_ip_address,omitempty"`
160	DestinationIPAddress *string                `json:"destination_ip_address,omitempty"`
161	SourcePort           *string                `json:"source_port,omitempty"`
162	DestinationPort      *string                `json:"destination_port,omitempty"`
163	Shared               *bool                  `json:"shared,omitempty"`
164	Enabled              *bool                  `json:"enabled,omitempty"`
165}
166
167// ToRuleUpdateMap casts a UpdateOpts struct to a map.
168func (opts UpdateOpts) ToRuleUpdateMap() (map[string]interface{}, error) {
169	return gophercloud.BuildRequestBody(opts, "firewall_rule")
170}
171
172// Update allows firewall policies to be updated.
173func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
174	b, err := opts.ToRuleUpdateMap()
175	if err != nil {
176		r.Err = err
177		return
178	}
179	_, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
180		OkCodes: []int{200},
181	})
182	return
183}
184
185// Delete will permanently delete a particular firewall rule based on its
186// unique ID.
187func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
188	_, r.Err = c.Delete(resourceURL(c, id), nil)
189	return
190}
191