Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions linode_api4/objects/networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,37 @@ def get_rules(self):
"{}/rules".format(self.api_endpoint), model=self
)

@property
def rule_versions(self):
"""
Gets the JSON rule versions for this Firewall.

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-firewall-rule-versions

:returns: Lists the current and historical rules of the firewall (that is not deleted),
using version. Whenever the rules update, the version increments from 1.
:rtype: dict
"""
return self._client.get(
"{}/history".format(self.api_endpoint), model=self
)

def get_rule_version(self, version):
"""
Gets the JSON for a specific rule version for this Firewall.

API Documentation: https://techdocs.akamai.com/linode-api/reference/get-firewall-rule-version

:param version: The firewall rule version to view.
:type version: int

:returns: Gets a specific firewall rule version for an enabled or disabled firewall.
:rtype: dict
"""
return self._client.get(
"{}/history/rules/{}".format(self.api_endpoint, version), model=self
)

def device_create(self, id, type="linode", **kwargs):
"""
Creates and attaches a device to this Firewall
Expand Down
21 changes: 21 additions & 0 deletions test/fixtures/networking_firewalls_123_history.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"data": [
{
"updated": "2025-03-07T17:06:36",
"status": "enabled",
"rules": {
"version": 1
}
},
{
"updated": "2025-03-07T17:06:36",
"status": "enabled",
"rules": {
"version": 2
}
}
],
"page": 1,
"pages": 1,
"results": 2
}
24 changes: 24 additions & 0 deletions test/fixtures/networking_firewalls_123_history_rules_2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"inbound": [
{
"action": "ACCEPT",
"addresses": {
"ipv4": [
"0.0.0.0/0"
],
"ipv6": [
"ff00::/8"
]
},
"description": "A really cool firewall rule.",
"label": "really-cool-firewall-rule",
"ports": "80",
"protocol": "TCP"
}
],
"inbound_policy": "ACCEPT",
"outbound": [],
"outbound_policy": "DROP",
"version": 2,
"fingerprint": "96c9568c"
}
54 changes: 54 additions & 0 deletions test/integration/models/networking/test_networking.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
from test.integration.conftest import (
get_api_ca_file,
get_api_url,
Expand Down Expand Up @@ -72,6 +73,59 @@ def test_get_networking_rules(test_linode_client, test_firewall):
assert "outbound_policy" in str(rules)


def test_get_networking_rule_versions(test_linode_client, test_firewall):
firewall = test_linode_client.load(Firewall, test_firewall.id)

# Update the firewall's rules
new_rules = {
"inbound": [
{
"action": "ACCEPT",
"addresses": {
"ipv4": ["0.0.0.0/0"],
"ipv6": ["ff00::/8"],
},
"description": "A really cool firewall rule.",
"label": "really-cool-firewall-rule",
"ports": "80",
"protocol": "TCP",
}
],
"inbound_policy": "ACCEPT",
"outbound": [],
"outbound_policy": "DROP",
}
firewall.update_rules(new_rules)
time.sleep(1)

rule_versions = firewall.rule_versions

# Original firewall rules
old_rule_version = firewall.get_rule_version(1)

# Updated firewall rules
new_rule_version = firewall.get_rule_version(2)

assert "rules" in str(rule_versions)
assert "version" in str(rule_versions)
assert rule_versions["results"] == 2

assert old_rule_version["inbound"] == []
assert old_rule_version["inbound_policy"] == "ACCEPT"
assert old_rule_version["outbound"] == []
assert old_rule_version["outbound_policy"] == "DROP"
assert old_rule_version["version"] == 1

assert (
new_rule_version["inbound"][0]["description"]
== "A really cool firewall rule."
)
assert new_rule_version["inbound_policy"] == "ACCEPT"
assert new_rule_version["outbound"] == []
assert new_rule_version["outbound_policy"] == "DROP"
assert new_rule_version["version"] == 2


@pytest.mark.smoke
def test_ip_addresses_share(
test_linode_client,
Expand Down
48 changes: 48 additions & 0 deletions test/unit/objects/networking_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,54 @@ def test_get_rules(self):
self.assertEqual(result["inbound_policy"], "DROP")
self.assertEqual(result["outbound_policy"], "DROP")

def test_get_rule_versions(self):
"""
Tests that you can submit a correct firewall rule versions view api request.
"""

firewall = Firewall(self.client, 123)

with self.mock_get("/networking/firewalls/123/history") as m:
result = firewall.rule_versions
self.assertEqual(m.call_url, "/networking/firewalls/123/history")
self.assertEqual(result["data"][0]["status"], "enabled")
self.assertEqual(result["data"][0]["rules"]["version"], 1)
self.assertEqual(result["data"][0]["status"], "enabled")
self.assertEqual(result["data"][1]["rules"]["version"], 2)

def test_get_rule_version(self):
"""
Tests that you can submit a correct firewall rule version view api request.
"""

firewall = Firewall(self.client, 123)

with self.mock_get("/networking/firewalls/123/history/rules/2") as m:
result = firewall.get_rule_version(2)
self.assertEqual(
m.call_url, "/networking/firewalls/123/history/rules/2"
)
self.assertEqual(result["inbound"][0]["action"], "ACCEPT")
self.assertEqual(
result["inbound"][0]["addresses"]["ipv4"][0], "0.0.0.0/0"
)
self.assertEqual(
result["inbound"][0]["addresses"]["ipv6"][0], "ff00::/8"
)
self.assertEqual(
result["inbound"][0]["description"],
"A really cool firewall rule.",
)
self.assertEqual(
result["inbound"][0]["label"], "really-cool-firewall-rule"
)
self.assertEqual(result["inbound"][0]["ports"], "80")
self.assertEqual(result["inbound"][0]["protocol"], "TCP")
self.assertEqual(result["outbound"], [])
self.assertEqual(result["inbound_policy"], "ACCEPT")
self.assertEqual(result["outbound_policy"], "DROP")
self.assertEqual(result["version"], 2)

def test_rdns_reset(self):
"""
Tests that the RDNS of an IP and be reset using an explicit null value.
Expand Down