Skip to content

Commit 4fa9e9d

Browse files
authored
Add support for Firewalls. (#145)
* Add support for Firewalls. * Fix chagelog PR id. * Add link to public api docs.
1 parent 1bbce10 commit 4fa9e9d

File tree

4 files changed

+1115
-1
lines changed

4 files changed

+1115
-1
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Change Log
22

3+
## [v1.1.0] - 2017-06-06
4+
5+
### Added
6+
- #145 Add FirewallsService for managing Firewalls with the DigitalOcean API. - @viola
7+
- #139 Add TTL field to the Domains. - @xmudrii
8+
9+
### Fixed
10+
- #143 Fix oauth2.NoContext depreciation. - @jbowens
11+
- #141 Fix DropletActions on tagged resources. - @xmudrii
12+
313
## [v1.0.0] - 2017-03-10
414

515
### Added

firewalls.go

+263
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
package godo
2+
3+
import (
4+
"path"
5+
"strconv"
6+
7+
"github.com/digitalocean/godo/context"
8+
)
9+
10+
const firewallsBasePath = "/v2/firewalls"
11+
12+
// FirewallsService is an interface for managing Firewalls with the DigitalOcean API.
13+
// See: https://developers.digitalocean.com/documentation/documentation/v2/#firewalls
14+
type FirewallsService interface {
15+
Get(context.Context, string) (*Firewall, *Response, error)
16+
Create(context.Context, *FirewallRequest) (*Firewall, *Response, error)
17+
Update(context.Context, string, *FirewallRequest) (*Firewall, *Response, error)
18+
Delete(context.Context, string) (*Response, error)
19+
List(context.Context, *ListOptions) ([]Firewall, *Response, error)
20+
ListByDroplet(context.Context, int, *ListOptions) ([]Firewall, *Response, error)
21+
AddDroplets(context.Context, string, ...int) (*Response, error)
22+
RemoveDroplets(context.Context, string, ...int) (*Response, error)
23+
AddTags(context.Context, string, ...string) (*Response, error)
24+
RemoveTags(context.Context, string, ...string) (*Response, error)
25+
AddRules(context.Context, string, *FirewallRulesRequest) (*Response, error)
26+
RemoveRules(context.Context, string, *FirewallRulesRequest) (*Response, error)
27+
}
28+
29+
// FirewallsServiceOp handles communication with Firewalls methods of the DigitalOcean API.
30+
type FirewallsServiceOp struct {
31+
client *Client
32+
}
33+
34+
// Firewall represents a DigitalOcean Firewall configuration.
35+
type Firewall struct {
36+
ID string `json:"id"`
37+
Name string `json:"name"`
38+
Status string `json:"status"`
39+
InboundRules []InboundRule `json:"inbound_rules"`
40+
OutboundRules []OutboundRule `json:"outbound_rules"`
41+
DropletIDs []int `json:"droplet_ids"`
42+
Tags []string `json:"tags"`
43+
Created string `json:"created_at"`
44+
PendingChanges []PendingChange `json:"pending_changes"`
45+
}
46+
47+
// String creates a human-readable description of a Firewall.
48+
func (fw Firewall) String() string {
49+
return Stringify(fw)
50+
}
51+
52+
// FirewallRequest represents the configuration to be applied to an existing or a new Firewall.
53+
type FirewallRequest struct {
54+
Name string `json:"name"`
55+
InboundRules []InboundRule `json:"inbound_rules"`
56+
OutboundRules []OutboundRule `json:"outbound_rules"`
57+
DropletIDs []int `json:"droplet_ids"`
58+
Tags []string `json:"tags"`
59+
}
60+
61+
// FirewallRulesRequest represents rules configuration to be applied to an existing Firewall.
62+
type FirewallRulesRequest struct {
63+
InboundRules []InboundRule `json:"inbound_rules"`
64+
OutboundRules []OutboundRule `json:"outbound_rules"`
65+
}
66+
67+
// InboundRule represents a DigitalOcean Firewall inbound rule.
68+
type InboundRule struct {
69+
Protocol string `json:"protocol,omitempty"`
70+
PortRange string `json:"ports,omitempty"`
71+
Sources *Sources `json:"sources"`
72+
}
73+
74+
// OutboundRule represents a DigitalOcean Firewall outbound rule.
75+
type OutboundRule struct {
76+
Protocol string `json:"protocol,omitempty"`
77+
PortRange string `json:"ports,omitempty"`
78+
Destinations *Destinations `json:"destinations"`
79+
}
80+
81+
// Sources represents a DigitalOcean Firewall InboundRule sources.
82+
type Sources struct {
83+
Addresses []string `json:"addresses,omitempty"`
84+
Tags []string `json:"tags,omitempty"`
85+
DropletIDs []int `json:"droplet_ids,omitempty"`
86+
LoadBalancerUIDs []string `json:"load_balancer_uids,omitempty"`
87+
}
88+
89+
// PendingChange represents a DigitalOcean Firewall status details.
90+
type PendingChange struct {
91+
DropletID int `json:"droplet_id,omitempty"`
92+
Removing bool `json:"removing,omitempty"`
93+
Status string `json:"status,omitempty"`
94+
}
95+
96+
// Destinations represents a DigitalOcean Firewall OutboundRule destinations.
97+
type Destinations struct {
98+
Addresses []string `json:"addresses,omitempty"`
99+
Tags []string `json:"tags,omitempty"`
100+
DropletIDs []int `json:"droplet_ids,omitempty"`
101+
LoadBalancerUIDs []string `json:"load_balancer_uids,omitempty"`
102+
}
103+
104+
var _ FirewallsService = &FirewallsServiceOp{}
105+
106+
// Get an existing Firewall by its identifier.
107+
func (fw *FirewallsServiceOp) Get(ctx context.Context, fID string) (*Firewall, *Response, error) {
108+
path := path.Join(firewallsBasePath, fID)
109+
110+
req, err := fw.client.NewRequest(ctx, "GET", path, nil)
111+
if err != nil {
112+
return nil, nil, err
113+
}
114+
115+
root := new(firewallRoot)
116+
resp, err := fw.client.Do(ctx, req, root)
117+
if err != nil {
118+
return nil, resp, err
119+
}
120+
121+
return root.Firewall, resp, err
122+
}
123+
124+
// Create a new Firewall with a given configuration.
125+
func (fw *FirewallsServiceOp) Create(ctx context.Context, fr *FirewallRequest) (*Firewall, *Response, error) {
126+
req, err := fw.client.NewRequest(ctx, "POST", firewallsBasePath, fr)
127+
if err != nil {
128+
return nil, nil, err
129+
}
130+
131+
root := new(firewallRoot)
132+
resp, err := fw.client.Do(ctx, req, root)
133+
if err != nil {
134+
return nil, resp, err
135+
}
136+
137+
return root.Firewall, resp, err
138+
}
139+
140+
// Update an existing Firewall with new configuration.
141+
func (fw *FirewallsServiceOp) Update(ctx context.Context, fID string, fr *FirewallRequest) (*Firewall, *Response, error) {
142+
path := path.Join(firewallsBasePath, fID)
143+
144+
req, err := fw.client.NewRequest(ctx, "PUT", path, fr)
145+
if err != nil {
146+
return nil, nil, err
147+
}
148+
149+
root := new(firewallRoot)
150+
resp, err := fw.client.Do(ctx, req, root)
151+
if err != nil {
152+
return nil, resp, err
153+
}
154+
155+
return root.Firewall, resp, err
156+
}
157+
158+
// Delete a Firewall by its identifier.
159+
func (fw *FirewallsServiceOp) Delete(ctx context.Context, fID string) (*Response, error) {
160+
path := path.Join(firewallsBasePath, fID)
161+
return fw.createAndDoReq(ctx, "DELETE", path, nil)
162+
}
163+
164+
// List Firewalls.
165+
func (fw *FirewallsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Firewall, *Response, error) {
166+
path, err := addOptions(firewallsBasePath, opt)
167+
if err != nil {
168+
return nil, nil, err
169+
}
170+
171+
return fw.listHelper(ctx, path)
172+
}
173+
174+
// ListByDroplet Firewalls.
175+
func (fw *FirewallsServiceOp) ListByDroplet(ctx context.Context, dID int, opt *ListOptions) ([]Firewall, *Response, error) {
176+
basePath := path.Join(dropletBasePath, strconv.Itoa(dID), "firewalls")
177+
path, err := addOptions(basePath, opt)
178+
if err != nil {
179+
return nil, nil, err
180+
}
181+
182+
return fw.listHelper(ctx, path)
183+
}
184+
185+
// AddDroplets to a Firewall.
186+
func (fw *FirewallsServiceOp) AddDroplets(ctx context.Context, fID string, dropletIDs ...int) (*Response, error) {
187+
path := path.Join(firewallsBasePath, fID, "droplets")
188+
return fw.createAndDoReq(ctx, "POST", path, &dropletsRequest{IDs: dropletIDs})
189+
}
190+
191+
// RemoveDroplets from a Firewall.
192+
func (fw *FirewallsServiceOp) RemoveDroplets(ctx context.Context, fID string, dropletIDs ...int) (*Response, error) {
193+
path := path.Join(firewallsBasePath, fID, "droplets")
194+
return fw.createAndDoReq(ctx, "DELETE", path, &dropletsRequest{IDs: dropletIDs})
195+
}
196+
197+
// AddTags to a Firewall.
198+
func (fw *FirewallsServiceOp) AddTags(ctx context.Context, fID string, tags ...string) (*Response, error) {
199+
path := path.Join(firewallsBasePath, fID, "tags")
200+
return fw.createAndDoReq(ctx, "POST", path, &tagsRequest{Tags: tags})
201+
}
202+
203+
// RemoveTags from a Firewall.
204+
func (fw *FirewallsServiceOp) RemoveTags(ctx context.Context, fID string, tags ...string) (*Response, error) {
205+
path := path.Join(firewallsBasePath, fID, "tags")
206+
return fw.createAndDoReq(ctx, "DELETE", path, &tagsRequest{Tags: tags})
207+
}
208+
209+
// AddRules to a Firewall.
210+
func (fw *FirewallsServiceOp) AddRules(ctx context.Context, fID string, rr *FirewallRulesRequest) (*Response, error) {
211+
path := path.Join(firewallsBasePath, fID, "rules")
212+
return fw.createAndDoReq(ctx, "POST", path, rr)
213+
}
214+
215+
// RemoveRules from a Firewall.
216+
func (fw *FirewallsServiceOp) RemoveRules(ctx context.Context, fID string, rr *FirewallRulesRequest) (*Response, error) {
217+
path := path.Join(firewallsBasePath, fID, "rules")
218+
return fw.createAndDoReq(ctx, "DELETE", path, rr)
219+
}
220+
221+
type dropletsRequest struct {
222+
IDs []int `json:"droplet_ids"`
223+
}
224+
225+
type tagsRequest struct {
226+
Tags []string `json:"tags"`
227+
}
228+
229+
type firewallRoot struct {
230+
Firewall *Firewall `json:"firewall"`
231+
}
232+
233+
type firewallsRoot struct {
234+
Firewalls []Firewall `json:"firewalls"`
235+
Links *Links `json:"links"`
236+
}
237+
238+
func (fw *FirewallsServiceOp) createAndDoReq(ctx context.Context, method, path string, v interface{}) (*Response, error) {
239+
req, err := fw.client.NewRequest(ctx, method, path, v)
240+
if err != nil {
241+
return nil, err
242+
}
243+
244+
return fw.client.Do(ctx, req, nil)
245+
}
246+
247+
func (fw *FirewallsServiceOp) listHelper(ctx context.Context, path string) ([]Firewall, *Response, error) {
248+
req, err := fw.client.NewRequest(ctx, "GET", path, nil)
249+
if err != nil {
250+
return nil, nil, err
251+
}
252+
253+
root := new(firewallsRoot)
254+
resp, err := fw.client.Do(ctx, req, root)
255+
if err != nil {
256+
return nil, resp, err
257+
}
258+
if l := root.Links; l != nil {
259+
resp.Links = l
260+
}
261+
262+
return root.Firewalls, resp, err
263+
}

0 commit comments

Comments
 (0)