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
27type (
28	// Action represents a valid rule protocol
29	Action string
30)
31
32const (
33	// ActionAllow is to allow traffic
34	ActionAllow Action = "allow"
35
36	// ActionDeny is to deny traffic
37	ActionDeny Action = "deny"
38
39	// ActionTCP is to reject traffic
40	ActionReject Action = "reject"
41)
42
43// ListOptsBuilder allows extensions to add additional parameters to the
44// List request.
45type ListOptsBuilder interface {
46	ToRuleListQuery() (string, error)
47}
48
49// ListOpts allows the filtering and sorting of paginated collections through
50// the API. Filtering is achieved by passing in struct field values that map to
51// the Firewall rule attributes you want to see returned. SortKey allows you to
52// sort by a particular firewall rule attribute. SortDir sets the direction, and is
53// either `asc' or `desc'. Marker and Limit are used for pagination.
54type ListOpts struct {
55	TenantID             string   `q:"tenant_id"`
56	Name                 string   `q:"name"`
57	Description          string   `q:"description"`
58	Protocol             Protocol `q:"protocol"`
59	Action               Action   `q:"action"`
60	IPVersion            int      `q:"ip_version"`
61	SourceIPAddress      string   `q:"source_ip_address"`
62	DestinationIPAddress string   `q:"destination_ip_address"`
63	SourcePort           string   `q:"source_port"`
64	DestinationPort      string   `q:"destination_port"`
65	Enabled              *bool    `q:"enabled"`
66	ID                   string   `q:"id"`
67	Shared               *bool    `q:"shared"`
68	ProjectID            string   `q:"project_id"`
69	FirewallPolicyID     string   `q:"firewall_policy_id"`
70	Limit                int      `q:"limit"`
71	Marker               string   `q:"marker"`
72	SortKey              string   `q:"sort_key"`
73	SortDir              string   `q:"sort_dir"`
74}
75
76// ToRuleListQuery formats a ListOpts into a query string.
77func (opts ListOpts) ToRuleListQuery() (string, error) {
78	q, err := gophercloud.BuildQueryString(opts)
79	if err != nil {
80		return "", err
81	}
82	return q.String(), nil
83}
84
85// List returns a Pager which allows you to iterate over a collection of
86// firewall rules. It accepts a ListOpts struct, which allows you to filter
87// and sort the returned collection for greater efficiency.
88//
89// Default policy settings return only those firewall rules that are owned by the
90// tenant who submits the request, unless an admin user submits the request.
91func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
92	url := rootURL(c)
93
94	if opts != nil {
95		query, err := opts.ToRuleListQuery()
96		if err != nil {
97			return pagination.Pager{Err: err}
98		}
99		url += query
100	}
101
102	return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
103		return RulePage{pagination.LinkedPageBase{PageResult: r}}
104	})
105}
106
107// CreateOptsBuilder is the interface options structs have to satisfy in order
108// to be used in the main Create operation in this package. Since many
109// extensions decorate or modify the common logic, it is useful for them to
110// satisfy a basic interface in order for them to be used.
111type CreateOptsBuilder interface {
112	ToRuleCreateMap() (map[string]interface{}, error)
113}
114
115// CreateOpts contains all the values needed to create a new firewall rule.
116type CreateOpts struct {
117	Protocol             Protocol              `json:"protocol" required:"true"`
118	Action               Action                `json:"action" required:"true"`
119	TenantID             string                `json:"tenant_id,omitempty"`
120	Name                 string                `json:"name,omitempty"`
121	Description          string                `json:"description,omitempty"`
122	IPVersion            gophercloud.IPVersion `json:"ip_version,omitempty"`
123	SourceIPAddress      string                `json:"source_ip_address,omitempty"`
124	DestinationIPAddress string                `json:"destination_ip_address,omitempty"`
125	SourcePort           string                `json:"source_port,omitempty"`
126	DestinationPort      string                `json:"destination_port,omitempty"`
127	Shared               *bool                 `json:"shared,omitempty"`
128	Enabled              *bool                 `json:"enabled,omitempty"`
129}
130
131// ToRuleCreateMap casts a CreateOpts struct to a map.
132func (opts CreateOpts) ToRuleCreateMap() (map[string]interface{}, error) {
133	b, err := gophercloud.BuildRequestBody(opts, "firewall_rule")
134	if err != nil {
135		return nil, err
136	}
137
138	if m := b["firewall_rule"].(map[string]interface{}); m["protocol"] == "any" {
139		m["protocol"] = nil
140	}
141
142	return b, nil
143}
144
145// Create accepts a CreateOpts struct and uses the values to create a new firewall rule
146func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
147	b, err := opts.ToRuleCreateMap()
148	if err != nil {
149		r.Err = err
150		return
151	}
152	_, r.Err = c.Post(rootURL(c), b, &r.Body, nil)
153	return
154}
155
156// Get retrieves a particular firewall rule based on its unique ID.
157func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
158	_, r.Err = c.Get(resourceURL(c, id), &r.Body, nil)
159	return
160}
161
162// UpdateOptsBuilder is the interface options structs have to satisfy in order
163// to be used in the main Update operation in this package. Since many
164// extensions decorate or modify the common logic, it is useful for them to
165// satisfy a basic interface in order for them to be used.
166type UpdateOptsBuilder interface {
167	ToRuleUpdateMap() (map[string]interface{}, error)
168}
169
170// UpdateOpts contains the values used when updating a firewall rule.
171type UpdateOpts struct {
172	Protocol             *Protocol              `json:"protocol,omitempty"`
173	Action               *Action                `json:"action,omitempty"`
174	Name                 *string                `json:"name,omitempty"`
175	Description          *string                `json:"description,omitempty"`
176	IPVersion            *gophercloud.IPVersion `json:"ip_version,omitempty"`
177	SourceIPAddress      *string                `json:"source_ip_address,omitempty"`
178	DestinationIPAddress *string                `json:"destination_ip_address,omitempty"`
179	SourcePort           *string                `json:"source_port,omitempty"`
180	DestinationPort      *string                `json:"destination_port,omitempty"`
181	Shared               *bool                  `json:"shared,omitempty"`
182	Enabled              *bool                  `json:"enabled,omitempty"`
183}
184
185// ToRuleUpdateMap casts a UpdateOpts struct to a map.
186func (opts UpdateOpts) ToRuleUpdateMap() (map[string]interface{}, error) {
187	return gophercloud.BuildRequestBody(opts, "firewall_rule")
188}
189
190// Update allows firewall policies to be updated.
191func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
192	b, err := opts.ToRuleUpdateMap()
193	if err != nil {
194		r.Err = err
195		return
196	}
197	_, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
198		OkCodes: []int{200},
199	})
200	return
201}
202
203// Delete will permanently delete a particular firewall rule based on its unique ID.
204func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
205	_, r.Err = c.Delete(resourceURL(c, id), nil)
206	return
207}
208