Skip to content

Commit 5343a4f

Browse files
authored
Merge pull request #148 from Charliekenney23/feat/firewall-rules
add firewall rules methods
2 parents b67652b + c4db7c0 commit 5343a4f

File tree

6 files changed

+577
-0
lines changed

6 files changed

+577
-0
lines changed

client.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type Client struct {
5959
Events *Resource
6060
Firewalls *Resource
6161
FirewallDevices *Resource
62+
FirewallRules *Resource
6263
IPAddresses *Resource
6364
IPv6Pools *Resource
6465
IPv6Ranges *Resource
@@ -263,6 +264,7 @@ func addResources(client *Client) {
263264
eventsName: NewResource(client, eventsName, eventsEndpoint, false, Event{}, EventsPagedResponse{}),
264265
firewallsName: NewResource(client, firewallsName, firewallsEndpoint, false, Firewall{}, FirewallsPagedResponse{}),
265266
firewallDevicesName: NewResource(client, firewallDevicesName, firewallDevicesEndpoint, true, FirewallDevice{}, FirewallDevicesPagedResponse{}),
267+
firewallRulesName: NewResource(client, firewallRulesName, firewallRulesEndpoint, true, FirewallRule{}, nil),
266268
imagesName: NewResource(client, imagesName, imagesEndpoint, false, Image{}, ImagesPagedResponse{}),
267269
instanceConfigsName: NewResource(client, instanceConfigsName, instanceConfigsEndpoint, true, InstanceConfig{}, InstanceConfigsPagedResponse{}),
268270
instanceDisksName: NewResource(client, instanceDisksName, instanceDisksEndpoint, true, InstanceDisk{}, InstanceDisksPagedResponse{}),
@@ -315,6 +317,7 @@ func addResources(client *Client) {
315317
client.Events = resources[eventsName]
316318
client.Firewalls = resources[firewallsName]
317319
client.FirewallDevices = resources[firewallDevicesName]
320+
client.FirewallRules = resources[firewallRulesName]
318321
client.IPAddresses = resources[ipaddressesName]
319322
client.IPv6Pools = resources[ipv6poolsName]
320323
client.IPv6Ranges = resources[ipv6rangesName]

firewall_rules.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package linodego
22

3+
import (
4+
"context"
5+
"encoding/json"
6+
)
7+
38
// NetworkProtocol enum type
49
type NetworkProtocol string
510

@@ -28,3 +33,39 @@ type FirewallRuleSet struct {
2833
Inbound []FirewallRule `json:"inbound,omitempty"`
2934
Outbound []FirewallRule `json:"outbound,omitempty"`
3035
}
36+
37+
// GetFirewallRules gets the FirewallRuleSet for the given Firewall.
38+
func (c *Client) GetFirewallRules(ctx context.Context, firewallID int) (*FirewallRuleSet, error) {
39+
e, err := c.FirewallRules.endpointWithID(firewallID)
40+
if err != nil {
41+
return nil, err
42+
}
43+
44+
r, err := coupleAPIErrors(c.R(ctx).SetResult(&FirewallRuleSet{}).Get(e))
45+
if err != nil {
46+
return nil, err
47+
}
48+
return r.Result().(*FirewallRuleSet), nil
49+
}
50+
51+
// UpdateFirewallRules updates the FirewallRuleSet for the given Firewall
52+
func (c *Client) UpdateFirewallRules(ctx context.Context, firewallID int, rules FirewallRuleSet) (*FirewallRuleSet, error) {
53+
e, err := c.FirewallRules.endpointWithID(firewallID)
54+
if err != nil {
55+
return nil, err
56+
}
57+
58+
var body string
59+
req := c.R(ctx).SetResult(&FirewallRuleSet{})
60+
if bodyData, err := json.Marshal(rules); err == nil {
61+
body = string(bodyData)
62+
} else {
63+
return nil, NewError(err)
64+
}
65+
66+
r, err := coupleAPIErrors(req.SetBody(body).Put(e))
67+
if err != nil {
68+
return nil, err
69+
}
70+
return r.Result().(*FirewallRuleSet), nil
71+
}

resources.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const (
1717
eventsName = "events"
1818
firewallsName = "firewalls"
1919
firewallDevicesName = "firewalldevices"
20+
firewallRulesName = "firewallrules"
2021
imagesName = "images"
2122
instanceConfigsName = "configs"
2223
instanceDisksName = "disks"
@@ -67,6 +68,7 @@ const (
6768
eventsEndpoint = "account/events"
6869
firewallsEndpoint = "networking/firewalls"
6970
firewallDevicesEndpoint = "networking/firewalls/{{ .ID }}/devices"
71+
firewallRulesEndpoint = "networking/firewalls/{{ .ID }}/rules"
7072
imagesEndpoint = "images"
7173
instanceConfigsEndpoint = "linode/instances/{{ .ID }}/configs"
7274
instanceDisksEndpoint = "linode/instances/{{ .ID }}/disks"

test/integration/firewall_rules_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package integration
22

33
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/google/go-cmp/cmp"
8+
"github.com/google/go-cmp/cmp/cmpopts"
49
"github.com/linode/linodego"
510
)
611

@@ -19,3 +24,52 @@ var (
1924
Outbound: []linodego.FirewallRule{testFirewallRule},
2025
}
2126
)
27+
28+
// ignoreNetworkAddresses negates comparing IP addresses. Because of fixture sanitization,
29+
// these addresses will be changed to bogus values when running tests.
30+
var ignoreNetworkAddresses = cmpopts.IgnoreFields(linodego.FirewallRule{}, "Addresses")
31+
32+
func TestGetFirewallRules(t *testing.T) {
33+
client, firewall, teardown, err := setupFirewall(t, []firewallModifier{func(createOpts *linodego.FirewallCreateOptions) {
34+
createOpts.Rules = testFirewallRuleSet
35+
}}, "fixtures/TestGetFirewallRules")
36+
if err != nil {
37+
t.Error(err)
38+
}
39+
defer teardown()
40+
41+
rules, err := client.GetFirewallRules(context.Background(), firewall.ID)
42+
if !cmp.Equal(rules, &testFirewallRuleSet, ignoreNetworkAddresses) {
43+
t.Errorf("expected rules to match test rules, but got diff: %s", cmp.Diff(rules, testFirewallRuleSet, ignoreNetworkAddresses))
44+
}
45+
}
46+
47+
func TestUpdateFirewallRules(t *testing.T) {
48+
client, firewall, teardown, err := setupFirewall(t, []firewallModifier{}, "fixtures/TestUpdateFirewallRules")
49+
if err != nil {
50+
t.Error(err)
51+
}
52+
defer teardown()
53+
54+
newRules := linodego.FirewallRuleSet{
55+
Inbound: []linodego.FirewallRule{
56+
{
57+
Ports: "22",
58+
Protocol: "TCP",
59+
Addresses: linodego.NetworkAddresses{
60+
IPv4: []string{"0.0.0.0/0"},
61+
IPv6: []string{"::0/0"},
62+
},
63+
},
64+
},
65+
}
66+
67+
if _, err := client.UpdateFirewallRules(context.Background(), firewall.ID, newRules); err != nil {
68+
t.Error(err)
69+
}
70+
71+
rules, err := client.GetFirewallRules(context.Background(), firewall.ID)
72+
if !cmp.Equal(rules, &newRules, ignoreNetworkAddresses) {
73+
t.Errorf("expected rules to have been updated but got diff: %s", cmp.Diff(rules, &newRules, ignoreNetworkAddresses))
74+
}
75+
}
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
---
2+
version: 1
3+
interactions:
4+
- request:
5+
body: '{"label":"label","rules":{"inbound":[{"ports":"22","protocol":"TCP","addresses":{"ipv4":["10.20.30.40/0"],"ipv6":["1234::5678/0"]}}],"outbound":[{"ports":"22","protocol":"TCP","addresses":{"ipv4":["10.20.30.40/0"],"ipv6":["1234::5678/0"]}}]},"tags":["testing"],"devices":{}}'
6+
form: {}
7+
headers:
8+
Accept:
9+
- application/json
10+
Content-Type:
11+
- application/json
12+
User-Agent:
13+
- linodego 0.12.0 https://github.com/linode/linodego
14+
url: https://api.linode.com/v4beta/networking/firewalls
15+
method: POST
16+
response:
17+
body: '{"id": 217, "label": "label", "created": "2018-01-02T03:04:05", "updated":
18+
"2018-01-02T03:04:05", "status": "enabled", "rules": {"inbound": [{"ports":
19+
"22", "protocol": "TCP", "addresses": {"ipv4": ["10.20.30.40/0"], "ipv6": ["1234::5678/0"]}}],
20+
"outbound": [{"ports": "22", "protocol": "TCP", "addresses": {"ipv4": ["10.20.30.40/0"],
21+
"ipv6": ["1234::5678/0"]}}]}, "tags": ["testing"]}'
22+
headers:
23+
Access-Control-Allow-Credentials:
24+
- "true"
25+
Access-Control-Allow-Headers:
26+
- Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter
27+
Access-Control-Allow-Methods:
28+
- HEAD, GET, OPTIONS, POST, PUT, DELETE
29+
Access-Control-Allow-Origin:
30+
- '*'
31+
Access-Control-Expose-Headers:
32+
- X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status
33+
Cache-Control:
34+
- private, max-age=60, s-maxage=60
35+
Content-Length:
36+
- "363"
37+
Content-Security-Policy:
38+
- default-src 'none'
39+
Content-Type:
40+
- application/json
41+
Date:
42+
- Tue, 19 May 2020 16:26:33 GMT
43+
Retry-After:
44+
- "119"
45+
Server:
46+
- nginx
47+
Strict-Transport-Security:
48+
- max-age=31536000
49+
Vary:
50+
- Authorization, X-Filter
51+
X-Accepted-Oauth-Scopes:
52+
- firewall:read_write
53+
X-Content-Type-Options:
54+
- nosniff
55+
X-Frame-Options:
56+
- DENY
57+
- DENY
58+
X-Oauth-Scopes:
59+
- '*'
60+
X-Ratelimit-Limit:
61+
- "1600"
62+
X-Ratelimit-Remaining:
63+
- "1599"
64+
X-Ratelimit-Reset:
65+
- "1589905713"
66+
X-Spec-Version:
67+
- 4.65.1
68+
X-Xss-Protection:
69+
- 1; mode=block
70+
status: 200 OK
71+
code: 200
72+
duration: ""
73+
- request:
74+
body: ""
75+
form: {}
76+
headers:
77+
Accept:
78+
- application/json
79+
Content-Type:
80+
- application/json
81+
User-Agent:
82+
- linodego 0.12.0 https://github.com/linode/linodego
83+
url: https://api.linode.com/v4beta/networking/firewalls/217/rules
84+
method: GET
85+
response:
86+
body: '{"inbound": [{"ports": "22", "protocol": "TCP", "addresses": {"ipv4": ["10.20.30.40/0"],
87+
"ipv6": ["1234::5678/0"]}}], "outbound": [{"ports": "22", "protocol": "TCP", "addresses":
88+
{"ipv4": ["10.20.30.40/0"], "ipv6": ["1234::5678/0"]}}]}'
89+
headers:
90+
Access-Control-Allow-Credentials:
91+
- "true"
92+
Access-Control-Allow-Headers:
93+
- Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter
94+
Access-Control-Allow-Methods:
95+
- HEAD, GET, OPTIONS, POST, PUT, DELETE
96+
Access-Control-Allow-Origin:
97+
- '*'
98+
Access-Control-Expose-Headers:
99+
- X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status
100+
Cache-Control:
101+
- private, max-age=0, s-maxage=0, no-cache, no-store
102+
- private, max-age=60, s-maxage=60
103+
Content-Length:
104+
- "213"
105+
Content-Security-Policy:
106+
- default-src 'none'
107+
Content-Type:
108+
- application/json
109+
Date:
110+
- Tue, 19 May 2020 16:26:33 GMT
111+
Retry-After:
112+
- "119"
113+
Server:
114+
- nginx
115+
Strict-Transport-Security:
116+
- max-age=31536000
117+
Vary:
118+
- Authorization, X-Filter
119+
- Authorization, X-Filter
120+
X-Accepted-Oauth-Scopes:
121+
- firewall:read_only
122+
X-Content-Type-Options:
123+
- nosniff
124+
X-Frame-Options:
125+
- DENY
126+
- DENY
127+
X-Oauth-Scopes:
128+
- '*'
129+
X-Ratelimit-Limit:
130+
- "1600"
131+
X-Ratelimit-Remaining:
132+
- "1598"
133+
X-Ratelimit-Reset:
134+
- "1589905713"
135+
X-Spec-Version:
136+
- 4.65.1
137+
X-Xss-Protection:
138+
- 1; mode=block
139+
status: 200 OK
140+
code: 200
141+
duration: ""
142+
- request:
143+
body: ""
144+
form: {}
145+
headers:
146+
Accept:
147+
- application/json
148+
Content-Type:
149+
- application/json
150+
User-Agent:
151+
- linodego 0.12.0 https://github.com/linode/linodego
152+
url: https://api.linode.com/v4beta/networking/firewalls/217
153+
method: DELETE
154+
response:
155+
body: '{}'
156+
headers:
157+
Access-Control-Allow-Credentials:
158+
- "true"
159+
Access-Control-Allow-Headers:
160+
- Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter
161+
Access-Control-Allow-Methods:
162+
- HEAD, GET, OPTIONS, POST, PUT, DELETE
163+
Access-Control-Allow-Origin:
164+
- '*'
165+
Access-Control-Expose-Headers:
166+
- X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status
167+
Cache-Control:
168+
- private, max-age=60, s-maxage=60
169+
Content-Length:
170+
- "2"
171+
Content-Security-Policy:
172+
- default-src 'none'
173+
Content-Type:
174+
- application/json
175+
Date:
176+
- Tue, 19 May 2020 16:26:33 GMT
177+
Retry-After:
178+
- "118"
179+
Server:
180+
- nginx
181+
Strict-Transport-Security:
182+
- max-age=31536000
183+
Vary:
184+
- Authorization, X-Filter
185+
X-Accepted-Oauth-Scopes:
186+
- firewall:read_write
187+
X-Content-Type-Options:
188+
- nosniff
189+
X-Frame-Options:
190+
- DENY
191+
- DENY
192+
X-Oauth-Scopes:
193+
- '*'
194+
X-Ratelimit-Limit:
195+
- "1600"
196+
X-Ratelimit-Remaining:
197+
- "1597"
198+
X-Ratelimit-Reset:
199+
- "1589905712"
200+
X-Spec-Version:
201+
- 4.65.1
202+
X-Xss-Protection:
203+
- 1; mode=block
204+
status: 200 OK
205+
code: 200
206+
duration: ""

0 commit comments

Comments
 (0)