Skip to content

Commit

Permalink
Merge pull request linode#148 from Charliekenney23/feat/firewall-rules
Browse files Browse the repository at this point in the history
add firewall rules methods
  • Loading branch information
0xch4z authored May 19, 2020
2 parents d9b9762 + 43e32f6 commit 89de5d7
Show file tree
Hide file tree
Showing 6 changed files with 577 additions and 0 deletions.
3 changes: 3 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type Client struct {
Events *Resource
Firewalls *Resource
FirewallDevices *Resource
FirewallRules *Resource
IPAddresses *Resource
IPv6Pools *Resource
IPv6Ranges *Resource
Expand Down Expand Up @@ -263,6 +264,7 @@ func addResources(client *Client) {
eventsName: NewResource(client, eventsName, eventsEndpoint, false, Event{}, EventsPagedResponse{}),
firewallsName: NewResource(client, firewallsName, firewallsEndpoint, false, Firewall{}, FirewallsPagedResponse{}),
firewallDevicesName: NewResource(client, firewallDevicesName, firewallDevicesEndpoint, true, FirewallDevice{}, FirewallDevicesPagedResponse{}),
firewallRulesName: NewResource(client, firewallRulesName, firewallRulesEndpoint, true, FirewallRule{}, nil),
imagesName: NewResource(client, imagesName, imagesEndpoint, false, Image{}, ImagesPagedResponse{}),
instanceConfigsName: NewResource(client, instanceConfigsName, instanceConfigsEndpoint, true, InstanceConfig{}, InstanceConfigsPagedResponse{}),
instanceDisksName: NewResource(client, instanceDisksName, instanceDisksEndpoint, true, InstanceDisk{}, InstanceDisksPagedResponse{}),
Expand Down Expand Up @@ -315,6 +317,7 @@ func addResources(client *Client) {
client.Events = resources[eventsName]
client.Firewalls = resources[firewallsName]
client.FirewallDevices = resources[firewallDevicesName]
client.FirewallRules = resources[firewallRulesName]
client.IPAddresses = resources[ipaddressesName]
client.IPv6Pools = resources[ipv6poolsName]
client.IPv6Ranges = resources[ipv6rangesName]
Expand Down
41 changes: 41 additions & 0 deletions firewall_rules.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package linodego

import (
"context"
"encoding/json"
)

// NetworkProtocol enum type
type NetworkProtocol string

Expand Down Expand Up @@ -28,3 +33,39 @@ type FirewallRuleSet struct {
Inbound []FirewallRule `json:"inbound,omitempty"`
Outbound []FirewallRule `json:"outbound,omitempty"`
}

// GetFirewallRules gets the FirewallRuleSet for the given Firewall.
func (c *Client) GetFirewallRules(ctx context.Context, firewallID int) (*FirewallRuleSet, error) {
e, err := c.FirewallRules.endpointWithID(firewallID)
if err != nil {
return nil, err
}

r, err := coupleAPIErrors(c.R(ctx).SetResult(&FirewallRuleSet{}).Get(e))
if err != nil {
return nil, err
}
return r.Result().(*FirewallRuleSet), nil
}

// UpdateFirewallRules updates the FirewallRuleSet for the given Firewall
func (c *Client) UpdateFirewallRules(ctx context.Context, firewallID int, rules FirewallRuleSet) (*FirewallRuleSet, error) {
e, err := c.FirewallRules.endpointWithID(firewallID)
if err != nil {
return nil, err
}

var body string
req := c.R(ctx).SetResult(&FirewallRuleSet{})
if bodyData, err := json.Marshal(rules); err == nil {
body = string(bodyData)
} else {
return nil, NewError(err)
}

r, err := coupleAPIErrors(req.SetBody(body).Put(e))
if err != nil {
return nil, err
}
return r.Result().(*FirewallRuleSet), nil
}
2 changes: 2 additions & 0 deletions resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const (
eventsName = "events"
firewallsName = "firewalls"
firewallDevicesName = "firewalldevices"
firewallRulesName = "firewallrules"
imagesName = "images"
instanceConfigsName = "configs"
instanceDisksName = "disks"
Expand Down Expand Up @@ -67,6 +68,7 @@ const (
eventsEndpoint = "account/events"
firewallsEndpoint = "networking/firewalls"
firewallDevicesEndpoint = "networking/firewalls/{{ .ID }}/devices"
firewallRulesEndpoint = "networking/firewalls/{{ .ID }}/rules"
imagesEndpoint = "images"
instanceConfigsEndpoint = "linode/instances/{{ .ID }}/configs"
instanceDisksEndpoint = "linode/instances/{{ .ID }}/disks"
Expand Down
54 changes: 54 additions & 0 deletions test/integration/firewall_rules_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package integration

import (
"context"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/linode/linodego"
)

Expand All @@ -19,3 +24,52 @@ var (
Outbound: []linodego.FirewallRule{testFirewallRule},
}
)

// ignoreNetworkAddresses negates comparing IP addresses. Because of fixture sanitization,
// these addresses will be changed to bogus values when running tests.
var ignoreNetworkAddresses = cmpopts.IgnoreFields(linodego.FirewallRule{}, "Addresses")

func TestGetFirewallRules(t *testing.T) {
client, firewall, teardown, err := setupFirewall(t, []firewallModifier{func(createOpts *linodego.FirewallCreateOptions) {
createOpts.Rules = testFirewallRuleSet
}}, "fixtures/TestGetFirewallRules")
if err != nil {
t.Error(err)
}
defer teardown()

rules, err := client.GetFirewallRules(context.Background(), firewall.ID)
if !cmp.Equal(rules, &testFirewallRuleSet, ignoreNetworkAddresses) {
t.Errorf("expected rules to match test rules, but got diff: %s", cmp.Diff(rules, testFirewallRuleSet, ignoreNetworkAddresses))
}
}

func TestUpdateFirewallRules(t *testing.T) {
client, firewall, teardown, err := setupFirewall(t, []firewallModifier{}, "fixtures/TestUpdateFirewallRules")
if err != nil {
t.Error(err)
}
defer teardown()

newRules := linodego.FirewallRuleSet{
Inbound: []linodego.FirewallRule{
{
Ports: "22",
Protocol: "TCP",
Addresses: linodego.NetworkAddresses{
IPv4: []string{"0.0.0.0/0"},
IPv6: []string{"::0/0"},
},
},
},
}

if _, err := client.UpdateFirewallRules(context.Background(), firewall.ID, newRules); err != nil {
t.Error(err)
}

rules, err := client.GetFirewallRules(context.Background(), firewall.ID)
if !cmp.Equal(rules, &newRules, ignoreNetworkAddresses) {
t.Errorf("expected rules to have been updated but got diff: %s", cmp.Diff(rules, &newRules, ignoreNetworkAddresses))
}
}
206 changes: 206 additions & 0 deletions test/integration/fixtures/TestGetFirewallRules.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
---
version: 1
interactions:
- request:
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":{}}'
form: {}
headers:
Accept:
- application/json
Content-Type:
- application/json
User-Agent:
- linodego 0.12.0 https://github.com/linode/linodego
url: https://api.linode.com/v4beta/networking/firewalls
method: POST
response:
body: '{"id": 217, "label": "label", "created": "2018-01-02T03:04:05", "updated":
"2018-01-02T03:04:05", "status": "enabled", "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"]}'
headers:
Access-Control-Allow-Credentials:
- "true"
Access-Control-Allow-Headers:
- Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter
Access-Control-Allow-Methods:
- HEAD, GET, OPTIONS, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Access-Control-Expose-Headers:
- X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status
Cache-Control:
- private, max-age=60, s-maxage=60
Content-Length:
- "363"
Content-Security-Policy:
- default-src 'none'
Content-Type:
- application/json
Date:
- Tue, 19 May 2020 16:26:33 GMT
Retry-After:
- "119"
Server:
- nginx
Strict-Transport-Security:
- max-age=31536000
Vary:
- Authorization, X-Filter
X-Accepted-Oauth-Scopes:
- firewall:read_write
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
- DENY
X-Oauth-Scopes:
- '*'
X-Ratelimit-Limit:
- "1600"
X-Ratelimit-Remaining:
- "1599"
X-Ratelimit-Reset:
- "1589905713"
X-Spec-Version:
- 4.65.1
X-Xss-Protection:
- 1; mode=block
status: 200 OK
code: 200
duration: ""
- request:
body: ""
form: {}
headers:
Accept:
- application/json
Content-Type:
- application/json
User-Agent:
- linodego 0.12.0 https://github.com/linode/linodego
url: https://api.linode.com/v4beta/networking/firewalls/217/rules
method: GET
response:
body: '{"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"]}}]}'
headers:
Access-Control-Allow-Credentials:
- "true"
Access-Control-Allow-Headers:
- Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter
Access-Control-Allow-Methods:
- HEAD, GET, OPTIONS, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Access-Control-Expose-Headers:
- X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status
Cache-Control:
- private, max-age=0, s-maxage=0, no-cache, no-store
- private, max-age=60, s-maxage=60
Content-Length:
- "213"
Content-Security-Policy:
- default-src 'none'
Content-Type:
- application/json
Date:
- Tue, 19 May 2020 16:26:33 GMT
Retry-After:
- "119"
Server:
- nginx
Strict-Transport-Security:
- max-age=31536000
Vary:
- Authorization, X-Filter
- Authorization, X-Filter
X-Accepted-Oauth-Scopes:
- firewall:read_only
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
- DENY
X-Oauth-Scopes:
- '*'
X-Ratelimit-Limit:
- "1600"
X-Ratelimit-Remaining:
- "1598"
X-Ratelimit-Reset:
- "1589905713"
X-Spec-Version:
- 4.65.1
X-Xss-Protection:
- 1; mode=block
status: 200 OK
code: 200
duration: ""
- request:
body: ""
form: {}
headers:
Accept:
- application/json
Content-Type:
- application/json
User-Agent:
- linodego 0.12.0 https://github.com/linode/linodego
url: https://api.linode.com/v4beta/networking/firewalls/217
method: DELETE
response:
body: '{}'
headers:
Access-Control-Allow-Credentials:
- "true"
Access-Control-Allow-Headers:
- Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter
Access-Control-Allow-Methods:
- HEAD, GET, OPTIONS, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Access-Control-Expose-Headers:
- X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status
Cache-Control:
- private, max-age=60, s-maxage=60
Content-Length:
- "2"
Content-Security-Policy:
- default-src 'none'
Content-Type:
- application/json
Date:
- Tue, 19 May 2020 16:26:33 GMT
Retry-After:
- "118"
Server:
- nginx
Strict-Transport-Security:
- max-age=31536000
Vary:
- Authorization, X-Filter
X-Accepted-Oauth-Scopes:
- firewall:read_write
X-Content-Type-Options:
- nosniff
X-Frame-Options:
- DENY
- DENY
X-Oauth-Scopes:
- '*'
X-Ratelimit-Limit:
- "1600"
X-Ratelimit-Remaining:
- "1597"
X-Ratelimit-Reset:
- "1589905712"
X-Spec-Version:
- 4.65.1
X-Xss-Protection:
- 1; mode=block
status: 200 OK
code: 200
duration: ""
Loading

0 comments on commit 89de5d7

Please sign in to comment.