Optimize firewall state collection and improve daemon shutdown
- Replace per-zone --list-all calls with single --list-all-zones in _collect_firewall - Add _parse_all_zones_output() parser with rich rules/rich-rules normalization - Convert daemon shutdown to async with proper runner cleanup and socket unlink - Add TimeoutStopSec=15 to vacuum-walld.service for graceful stop - Fix exception handling in _collect_dnsmasq - Remove management badge from proxy path rows
This commit is contained in:
@@ -542,3 +542,89 @@ class TestLibParseForwardPorts:
|
||||
|
||||
def test_empty_string(self):
|
||||
assert firewall._parse_forward_ports("") == []
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# lib/firewall.py — parse all zones output (--list-all-zones)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestParseAllZonesOutput:
|
||||
def test_parses_single_zone(self):
|
||||
result = firewall._parse_all_zones_output(
|
||||
"public\n"
|
||||
" target: default\n"
|
||||
" interfaces: eth0\n"
|
||||
" services: ssh http\n"
|
||||
" masquerade: yes\n"
|
||||
" rich rules: \n"
|
||||
)
|
||||
assert "public" in result
|
||||
assert result["public"]["name"] == "public"
|
||||
assert result["public"]["interfaces"] == ["eth0"]
|
||||
assert result["public"]["services"] == ["ssh", "http"]
|
||||
assert result["public"]["masquerade"] is True
|
||||
assert result["public"]["rich-rules"] == []
|
||||
|
||||
def test_parses_multiple_zones(self):
|
||||
result = firewall._parse_all_zones_output(
|
||||
"public (default, active)\n"
|
||||
" target: default\n"
|
||||
" interfaces: eth0\n"
|
||||
" services: ssh\n"
|
||||
" masquerade: no\n"
|
||||
" rich rules: \n"
|
||||
"internal (active)\n"
|
||||
" target: ACCEPT\n"
|
||||
" interfaces: eth1\n"
|
||||
" services: dhcp\n"
|
||||
" masquerade: no\n"
|
||||
" rich rules: \n"
|
||||
"trusted\n"
|
||||
" target: ACCEPT\n"
|
||||
" interfaces: \n"
|
||||
" services: \n"
|
||||
" masquerade: no\n"
|
||||
" rich rules: \n"
|
||||
)
|
||||
assert set(result.keys()) == {"public", "internal", "trusted"}
|
||||
assert result["public"]["interfaces"] == ["eth0"]
|
||||
assert result["internal"]["target"] == "ACCEPT"
|
||||
assert result["trusted"]["services"] == []
|
||||
|
||||
def test_empty_output(self):
|
||||
assert firewall._parse_all_zones_output("") == {}
|
||||
assert firewall._parse_all_zones_output("\n \n") == {}
|
||||
|
||||
def test_handles_blank_lines_between_zones(self):
|
||||
result = firewall._parse_all_zones_output(
|
||||
"public\n"
|
||||
" target: default\n"
|
||||
" interfaces: eth0\n"
|
||||
" rich rules: \n"
|
||||
"\n"
|
||||
"internal\n"
|
||||
" target: ACCEPT\n"
|
||||
" interfaces: eth1\n"
|
||||
" rich rules: \n"
|
||||
)
|
||||
assert "public" in result
|
||||
assert "internal" in result
|
||||
assert result["public"]["interfaces"] == ["eth0"]
|
||||
assert result["internal"]["interfaces"] == ["eth1"]
|
||||
|
||||
def test_all_default_fields_present(self):
|
||||
result = firewall._parse_all_zones_output(
|
||||
"dmz\n"
|
||||
" target: default\n"
|
||||
" interfaces: \n"
|
||||
" services: \n"
|
||||
" rich rules: \n"
|
||||
)
|
||||
zone = result["dmz"]
|
||||
for field in (
|
||||
"interfaces", "sources", "services", "ports", "protocols",
|
||||
"forward-ports", "masquerade", "ics", "icmp-blocks", "module",
|
||||
"target", "rich-rules",
|
||||
):
|
||||
assert field in zone, f"Missing field: {field}"
|
||||
|
||||
+32
-14
@@ -35,8 +35,6 @@ class TestCollectAll:
|
||||
from lib.state import _collect_firewall
|
||||
|
||||
def run_side(args, **kwargs):
|
||||
if "--get-zones" in args:
|
||||
return "public\ninternal"
|
||||
if "--get-active-zones" in args:
|
||||
return "public\n eth0"
|
||||
if "--get-services" in args:
|
||||
@@ -45,9 +43,18 @@ class TestCollectAll:
|
||||
if "link" in args:
|
||||
return "1: lo: <LOOPBACK> mtu 65536\n2: eth0: <UP> mtu 1500 link/ether aa:bb\n"
|
||||
return ""
|
||||
if "--list-all" in args:
|
||||
return "target: default\ninterfaces: eth0\nsources: \nservices: \nports: \nprotocols: \nforward-ports: \nmasquerade: no\nics: no\nrich-rules: \nicmp-blocks: \nmodule: \n"
|
||||
return ""
|
||||
if "--list-all-zones" in args:
|
||||
return (
|
||||
"public\n"
|
||||
" target: default\n"
|
||||
" interfaces: eth0\n"
|
||||
" services: \n"
|
||||
" ports: \n"
|
||||
" protocols: \n"
|
||||
" forward-ports: \n"
|
||||
" masquerade: no\n"
|
||||
" rich rules: \n"
|
||||
)
|
||||
|
||||
mock_run.side_effect = run_side
|
||||
result = _collect_firewall()
|
||||
@@ -62,10 +69,8 @@ class TestCollectAll:
|
||||
from lib.state import _collect_firewall
|
||||
|
||||
def run_side(args, **kwargs):
|
||||
if "--get-zones" in args:
|
||||
return "public\ninternal"
|
||||
if "--get-active-zones" in args:
|
||||
return "public\n eth0\ninternal eth0.100"
|
||||
return "public\n eth0\ninternal\n eth0.100"
|
||||
if "--get-services" in args:
|
||||
return "ssh http"
|
||||
if "ip" in args[0]:
|
||||
@@ -81,14 +86,27 @@ class TestCollectAll:
|
||||
"3: eth0.100@if100 inet 10.0.0.1/24\n"
|
||||
)
|
||||
return ""
|
||||
if "--list-all" in args:
|
||||
if "--list-all-zones" in args:
|
||||
return (
|
||||
"target: default\ninterfaces: eth0\nsources: "
|
||||
"services: \nports: \nprotocols: \nforward-ports: "
|
||||
"masquerade: no\nics: no\nrich-rules: "
|
||||
"icmp-blocks: \nmodule: \n"
|
||||
"public\n"
|
||||
" target: default\n"
|
||||
" interfaces: eth0\n"
|
||||
" services: \n"
|
||||
" ports: \n"
|
||||
" protocols: \n"
|
||||
" forward-ports: \n"
|
||||
" masquerade: no\n"
|
||||
" rich rules: \n"
|
||||
"internal\n"
|
||||
" target: ACCEPT\n"
|
||||
" interfaces: eth0.100\n"
|
||||
" services: \n"
|
||||
" ports: \n"
|
||||
" protocols: \n"
|
||||
" forward-ports: \n"
|
||||
" masquerade: no\n"
|
||||
" rich rules: \n"
|
||||
)
|
||||
return ""
|
||||
|
||||
mock_run.side_effect = run_side
|
||||
result = _collect_firewall()
|
||||
|
||||
Reference in New Issue
Block a user