Skip to content

Commit 0f7fc3f

Browse files
authored
Firewall Integration tests (#777)
1 parent d2bfe4a commit 0f7fc3f

File tree

4 files changed

+239
-119
lines changed

4 files changed

+239
-119
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import json
2+
3+
import pytest
4+
5+
from tests.integration.helpers import (
6+
delete_target_id,
7+
exec_test_command,
8+
get_random_text,
9+
)
10+
11+
BASE_CMD = ["linode-cli", "firewalls"]
12+
13+
14+
@pytest.fixture(scope="function")
15+
def _firewall_id_and_label():
16+
# generate a unique label
17+
label = "fw-" + get_random_text(5)
18+
# create it and capture the ID
19+
result = exec_test_command(
20+
BASE_CMD
21+
+ [
22+
"create",
23+
"--label",
24+
label,
25+
"--rules.outbound_policy",
26+
"ACCEPT",
27+
"--rules.inbound_policy",
28+
"DROP",
29+
"--text",
30+
"--no-headers",
31+
"--format",
32+
"id",
33+
]
34+
)
35+
fw_id = result.stdout.decode().strip()
36+
yield fw_id, label
37+
# cleanup
38+
delete_target_id(target="firewalls", id=fw_id)
39+
40+
41+
@pytest.fixture(scope="function")
42+
def test_firewall_id(_firewall_id_and_label):
43+
"""Only the ID, so old tests keep working."""
44+
return _firewall_id_and_label[0]
45+
46+
47+
@pytest.fixture(scope="function")
48+
def test_firewall_label(_firewall_id_and_label):
49+
"""Only the label, for tests that need it explicitly."""
50+
return _firewall_id_and_label[1]
51+
52+
53+
@pytest.fixture
54+
def restore_firewall_defaults():
55+
# Fetch and store current default firewall settings
56+
result = exec_test_command(BASE_CMD + ["firewall-settings-list", "--json"])
57+
settings = json.loads(result.stdout.decode())
58+
original_defaults = settings[0]["default_firewall_ids"]
59+
60+
yield original_defaults
61+
62+
# Restore the original defaults after test
63+
args = []
64+
for key, val in original_defaults.items():
65+
if val is not None:
66+
args.extend([f"--default_firewall_ids.{key}", str(val)])
67+
68+
if args:
69+
exec_test_command(BASE_CMD + ["firewall-settings-update"] + args)
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import json
2+
3+
import pytest
4+
5+
from tests.integration.helpers import (
6+
exec_test_command,
7+
)
8+
9+
BASE_CMD = ["linode-cli", "firewalls"]
10+
11+
12+
def test_firewall_settings_defaults(test_firewall_id, test_firewall_label):
13+
# list all firewalls and extract the IDs
14+
list_result = (
15+
exec_test_command(
16+
BASE_CMD + ["list", "--no-headers", "--text", "--delimiter", ","]
17+
)
18+
.stdout.decode()
19+
.strip()
20+
)
21+
22+
firewall_lines = list_result.splitlines()
23+
firewall_ids = [
24+
line.split(",")[0].strip() for line in firewall_lines if line
25+
]
26+
27+
assert (
28+
test_firewall_id in firewall_ids
29+
), f"{test_firewall_id} not found in firewall list"
30+
31+
# get the default firewall settings
32+
settings_result = exec_test_command(
33+
BASE_CMD + ["firewall-settings-list", "--json"]
34+
).stdout.decode()
35+
36+
settings = json.loads(settings_result)
37+
assert (
38+
isinstance(settings, list) and len(settings) > 0
39+
), "Unexpected settings format"
40+
41+
default_ids = settings[0]["default_firewall_ids"]
42+
43+
# Validate all expected keys exist and map to a valid firewall ID
44+
expected_keys = [
45+
"linode",
46+
"nodebalancer",
47+
"public_interface",
48+
"vpc_interface",
49+
]
50+
51+
for key in expected_keys:
52+
assert key in default_ids, f"Missing default_firewall_ids key: {key}"
53+
val = default_ids[key]
54+
assert val is None or isinstance(
55+
val, int
56+
), f"{key} value is not None or int: {val}"
57+
if isinstance(val, int):
58+
assert val > 0, f"{key} should be a non-zero firewall ID"
59+
assert (
60+
str(val) in firewall_ids
61+
), f"{key} ID ({val}) not found in firewall list"
62+
63+
64+
def test_update_firewall_defaults(test_firewall_id, restore_firewall_defaults):
65+
# Fetch current default firewall settings
66+
settings = json.loads(
67+
exec_test_command(
68+
BASE_CMD + ["firewall-settings-list", "--json"]
69+
).stdout.decode()
70+
)
71+
default_ids_before = settings[0]["default_firewall_ids"]
72+
73+
# Skip if no default firewall configured at all
74+
if all(v is None for v in default_ids_before.values()):
75+
pytest.skip("Skipping: no default firewall configured for the account.")
76+
77+
old_default_id = (
78+
str(default_ids_before["linode"])
79+
if default_ids_before["linode"]
80+
else None
81+
)
82+
83+
# List all firewalls
84+
firewall_list = (
85+
exec_test_command(
86+
BASE_CMD + ["list", "--no-headers", "--text", "--delimiter", ","]
87+
)
88+
.stdout.decode()
89+
.strip()
90+
)
91+
92+
firewall_ids = [
93+
line.split(",")[0].strip()
94+
for line in firewall_list.splitlines()
95+
if line
96+
]
97+
98+
assert (
99+
test_firewall_id in firewall_ids
100+
), f"{test_firewall_id} not found in firewall list"
101+
102+
new_id = next(
103+
fid
104+
for fid in firewall_ids
105+
if old_default_id is None or fid != old_default_id
106+
)
107+
108+
# Update all default firewall IDs to the new one
109+
exec_test_command(
110+
BASE_CMD
111+
+ [
112+
"firewall-settings-update",
113+
"--default_firewall_ids.linode",
114+
new_id,
115+
"--default_firewall_ids.nodebalancer",
116+
new_id,
117+
"--default_firewall_ids.public_interface",
118+
new_id,
119+
"--default_firewall_ids.vpc_interface",
120+
new_id,
121+
"--json",
122+
]
123+
)
124+
125+
# Verify update
126+
updated_settings = json.loads(
127+
exec_test_command(
128+
BASE_CMD + ["firewall-settings-list", "--json"]
129+
).stdout.decode()
130+
)[0]["default_firewall_ids"]
131+
132+
for key, val in updated_settings.items():
133+
assert (
134+
str(val) == new_id
135+
), f"{key} was not updated (expected {new_id}, got {val})"

tests/integration/firewalls/test_firewalls.py

Lines changed: 12 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -10,51 +10,22 @@
1010
delete_target_id,
1111
exec_failing_test_command,
1212
exec_test_command,
13-
get_random_text,
1413
)
1514

1615
BASE_CMD = ["linode-cli", "firewalls"]
17-
FIREWALL_LABEL = "fw-" + get_random_text(5)
18-
19-
20-
@pytest.fixture
21-
def test_firewall_id():
22-
firewall_id = (
23-
exec_test_command(
24-
BASE_CMD
25-
+ [
26-
"create",
27-
"--label",
28-
FIREWALL_LABEL,
29-
"--rules.outbound_policy",
30-
"ACCEPT",
31-
"--rules.inbound_policy",
32-
"DROP",
33-
"--text",
34-
"--no-headers",
35-
"--format",
36-
"id",
37-
]
38-
)
39-
.stdout.decode()
40-
.rstrip()
41-
)
42-
43-
yield firewall_id
44-
45-
delete_target_id(target="firewalls", id=firewall_id)
4616

4717

4818
@pytest.mark.smoke
49-
def test_view_firewall(test_firewall_id):
50-
firewall_id = test_firewall_id
19+
def test_view_firewall(test_firewall_id, test_firewall_label):
20+
fw_id = test_firewall_id
21+
fw_label = test_firewall_label
5122

5223
result = (
5324
exec_test_command(
5425
BASE_CMD
5526
+ [
5627
"view",
57-
firewall_id,
28+
fw_id,
5829
"--no-headers",
5930
"--text",
6031
"--delimiter",
@@ -65,12 +36,12 @@ def test_view_firewall(test_firewall_id):
6536
.rstrip()
6637
)
6738

68-
assert re.search(firewall_id + "," + FIREWALL_LABEL + ",enabled", result)
39+
assert f"{fw_id},{fw_label},enabled" in result
6940

7041

71-
def test_list_firewall(test_firewall_id):
72-
firewall_id = test_firewall_id
73-
42+
def test_list_firewall(test_firewall_id, test_firewall_label):
43+
fw_id = test_firewall_id
44+
fw_label = test_firewall_label
7445
result = (
7546
exec_test_command(
7647
BASE_CMD + ["list", "--no-headers", "--text", "--delimiter", ","]
@@ -79,7 +50,7 @@ def test_list_firewall(test_firewall_id):
7950
.rstrip()
8051
)
8152

82-
assert re.search(firewall_id + "," + FIREWALL_LABEL + ",enabled", result)
53+
assert f"{fw_id},{fw_label},enabled" in result
8354

8455

8556
@pytest.mark.smoke
@@ -166,14 +137,15 @@ def test_fails_to_create_firewall_without_outbound_policy():
166137
assert "outbound_policy is required" in result
167138

168139

169-
def test_firewall_label_must_be_unique_upon_creation(test_firewall_id):
140+
def test_firewall_label_must_be_unique_upon_creation(test_firewall_label):
141+
fw_label = test_firewall_label
170142
result = (
171143
exec_failing_test_command(
172144
BASE_CMD
173145
+ [
174146
"create",
175147
"--label",
176-
FIREWALL_LABEL,
148+
fw_label,
177149
"--rules.outbound_policy",
178150
"ACCEPT",
179151
"--rules.inbound_policy",
@@ -258,39 +230,6 @@ def test_update_firewall(test_firewall_id):
258230
assert re.search(firewall_id + "," + updated_label + ",enabled", result)
259231

260232

261-
@pytest.mark.skip("skip until there is a way to delete default firewall")
262-
def test_firewall_settings_update_and_list(test_firewall_id):
263-
for cmd in [
264-
BASE_CMD
265-
+ [
266-
"firewall-settings-update",
267-
"--default_firewall_ids.vpc_interfac",
268-
test_firewall_id,
269-
"--default_firewall_ids.public_interface",
270-
test_firewall_id,
271-
"--default_firewall_ids.nodebalancer",
272-
test_firewall_id,
273-
"--default_firewall_ids.linode",
274-
test_firewall_id,
275-
"--json",
276-
],
277-
BASE_CMD
278-
+ [
279-
"firewall-settings-list",
280-
"--json",
281-
],
282-
]:
283-
data = json.loads(exec_test_command(cmd).stdout.decode().rstrip())
284-
firewall_ids = data[0]["default_firewall_ids"]
285-
for key in [
286-
"linode",
287-
"nodebalancer",
288-
"public_interface",
289-
"vpc_interface",
290-
]:
291-
assert firewall_ids[key] == int(test_firewall_id)
292-
293-
294233
def test_firewall_templates_list(monkeypatch: MonkeyPatch):
295234
monkeypatch.setenv("LINODE_CLI_API_VERSION", "v4beta")
296235
data = json.loads(

0 commit comments

Comments
 (0)