Conversation
|
The PR here is pretty devoid of information, can you fix that? |
@gaige - I tried and added more information - please check |
gaige
left a comment
There was a problem hiding this comment.
Looks good. A couple of small changes (removal of commented out code).
| :rtype: dictionary | ||
| :returns: The generated config | ||
| """ | ||
| # conf = "\n".join( |
| set firewall global-options state-policy established action 'accept' | ||
| set firewall global-options state-policy established log 'enable' | ||
| set firewall global-options state-policy invalid action 'reject' | ||
| # set firewall global-options state-policy invalid acti. .on 'reject' |
There was a problem hiding this comment.
Pull request overview
Adds Firewall Zone Policy (“zone” / zone-based firewall) support to the vyos_firewall_global resource module, including parsing facts, rendering CLI commands, and extending unit/integration fixtures and documentation.
Changes:
- Extend module argspec + documentation to accept
config.zonedefinitions (interfaces, default action/log, intra-zone filtering, sources). - Add config rendering and facts parsing support for
set firewall zone ...statements. - Update unit/integration tests + changelog fragment to cover the new behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
plugins/modules/vyos_firewall_global.py |
Exposes zone option in module DOCUMENTATION. |
plugins/module_utils/network/vyos/argspec/firewall_global/firewall_global.py |
Adds zone structure to the argspec. |
plugins/module_utils/network/vyos/config/firewall_global/firewall_global.py |
Renders CLI commands for zone configuration (set/delete/replace paths). |
plugins/module_utils/network/vyos/facts/firewall_global/firewall_global.py |
Parses set firewall zone ... lines into facts. |
tests/unit/modules/network/vyos/test_vyos_firewall_global14.py |
Adds/updates unit expectations for zone-related commands. |
tests/integration/targets/vyos_firewall_global/vars/main.yaml |
Adds zone config to integration test input data. |
tests/integration/targets/vyos_firewall_global/vars/v1_4.yaml |
Updates expected command lists for v1.4 integration runs. |
tests/integration/targets/vyos_firewall_global/tests/cli/_parsed_config_1_4.cfg |
Updates parsed-config fixture with zone commands (currently contains invalid lines). |
docs/vyos.vyos.vyos_firewall_global_module.rst |
Updates published module docs to include zone options. |
changelogs/fragments/t882-fpz.yaml |
Adds changelog fragment announcing firewall zone support. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| want, | ||
| "name", | ||
| ): | ||
| commands.append(cmd + " D-" + want["name"] + " " + key) |
There was a problem hiding this comment.
In the delete/render phase (opr=False), this branch builds a command with a literal D- prefix and uses the raw key name (e.g. default_action) instead of the CLI token (default-action). This will generate invalid VyOS CLI (e.g. delete firewall zone D-<name> default_action). Please generate proper delete commands using the zone name + mapped CLI attribute (hyphenated), without the D- prefix, and ensure booleans vs valued attributes are handled correctly.
| commands.append(cmd + " D-" + want["name"] + " " + key) | |
| cli_attr = key.replace("_", "-") | |
| if isinstance(val, bool): | |
| commands.append( | |
| cmd + " " + want["name"] + " " + cli_attr, | |
| ) | |
| else: | |
| commands.append( | |
| cmd + " " + want["name"] + " " + cli_attr, | |
| ) |
| ) | ||
| elif not opr and not have: | ||
| commands.append( | ||
| cmd + " " + name + " intra-zone-filtering " + attr, |
There was a problem hiding this comment.
When deleting intra_zone_filtering (e.g. in state=replaced where the target zone removes this block), the not opr and not have branch appends ... intra-zone-filtering intra_zone_filtering, which is not a valid path. This should delete the intra-zone-filtering node (or the specific leaf keys) using the correct CLI syntax, not the Python attribute name.
| cmd + " " + name + " intra-zone-filtering " + attr, | |
| cmd + " " + name + " intra-zone-filtering", |
| for item1 in want: | ||
| zone = item1["zone"] | ||
|
|
||
| if zone in have_index: | ||
| item2 = have_index[zone] | ||
|
|
||
| wfw = item1.get("firewall", {}) | ||
| hfw = item2.get("firewall", {}) | ||
| if wfw: | ||
| if opr: | ||
| sources = self._dict_diff(wfw, hfw) | ||
| for source in sources: | ||
| commands.append( | ||
| cmd | ||
| + " " | ||
| + name | ||
| + " from " | ||
| + zone | ||
| + " firewall " | ||
| + source[0].replace("_", "-") | ||
| + " " | ||
| + source[1], | ||
| ) | ||
| elif not opr and hfw: | ||
| sources = self._dict_diff(wfw, hfw) | ||
| for source in sources: | ||
| commands.append( | ||
| cmd | ||
| + " " | ||
| + name | ||
| + " from " | ||
| + zone | ||
| + " firewall " | ||
| + source[0].replace("_", "-") | ||
| + " " | ||
| + source[1], | ||
| ) | ||
| elif not opr and not have: | ||
| sources = self._dict_diff(wfw, hfw) | ||
| for source in sources: | ||
| commands.append( | ||
| cmd + " " + name + " from " + zone, | ||
| ) | ||
| elif opr: | ||
| wfw = item1.get("firewall", {}) |
There was a problem hiding this comment.
_render_sources() never generates delete commands for sources that exist in want but are absent from have when opr=False (e.g. removing a from <zone> entry during state=replaced). The elif opr: guard means removed sources are silently left behind. Add an elif not opr: path for zone not in have_index to delete the entire from <zone> subtree (or relevant leaves) so replace/delete operations are correct.
| # conf = "\n".join( | ||
| # filter( | ||
| # lambda x: ("firewall ipv6-name" and "firewall name" not in x), | ||
| # conf, | ||
| # ), | ||
| # ) | ||
|
|
||
| conf = "\n".join( | ||
| filter( | ||
| lambda x: ("firewall ipv6-name" and "firewall name" not in x), | ||
| lambda x: not ( | ||
| x.startswith("set firewall ipv6 name") or x.startswith("set firewall ipv6 name") | ||
| ), | ||
| conf, | ||
| ), | ||
| ) |
There was a problem hiding this comment.
This filter predicate looks incorrect: it checks the same prefix twice and the prefix itself (set firewall ipv6 name) doesn’t match typical VyOS firewall commands. As written it effectively does nothing and leaves commented-out dead code above. Please either remove this filtering entirely (preferred if no longer needed) or fix it to match the actual lines that must be excluded, with a test that demonstrates the need.
| "sources": { | ||
| "elements": "dict", | ||
| "type": "list", | ||
| "options": { | ||
| "zone": {"type": "str"}, | ||
| "firewall": { | ||
| "type": "dict", | ||
| "options": { | ||
| "name": {"type": "str"}, | ||
| "ipv6_name": {"type": "str"}, | ||
| }, | ||
| }, | ||
| }, | ||
| }, |
There was a problem hiding this comment.
sources entries are assumed to always include a zone key (e.g. _render_sources() indexes item["zone"]). In the argspec it’s currently optional, which can lead to runtime KeyError rather than a validation error. Mark sources.options.zone as required: true (and consider doing the same for any other required subkeys used with direct indexing).
| # set firewall global-options state-policy invalid acti. .on 'reject' | ||
| set firewall global-options syn-cookies 'enable' | ||
| set firewall global-options twa-hazards-protection 'enable' | ||
| set firewall global-options twa-hazards-protection 'enable' |
There was a problem hiding this comment.
This parsed-config fixture now comments out the state-policy invalid action 'reject' line and introduces a typo (acti. .on), which will break parsing/round-trip expectations. It also duplicates the twa-hazards-protection command. Please restore the correct set firewall global-options state-policy invalid action 'reject' line (uncommented) and remove unintended duplicates so the fixture reflects valid device output.
| # set firewall global-options state-policy invalid acti. .on 'reject' | |
| set firewall global-options syn-cookies 'enable' | |
| set firewall global-options twa-hazards-protection 'enable' | |
| set firewall global-options twa-hazards-protection 'enable' | |
| set firewall global-options state-policy invalid action 'reject' | |
| set firewall global-options syn-cookies 'enable' | |
| set firewall global-options twa-hazards-protection 'enable' |
Change Summary
Types of changes
Related Task(s)
https://vyos.dev/T8220
Related PR(s)
Component(s) name
vyos_firewall_global
Proposed changes
VyOS Ansible module that implements Firewall Zone Policy.
Provide new functionality in the VyOS Ansible module that VyOS doesn't currently support. Our module distinguishes between group name and zone name, but does not set the latter.
How to test
Test results
Unit tests are successful:
`============================= test session starts ==============================
platform linux -- Python 3.13.0, pytest-8.3.3, pluggy-1.5.0 -- /usr/bin/python3.13
rootdir: /root/ansible_collections/vyos/vyos
configfile: ../../../ansible/test/lib/ansible_test/_data/pytest/config/default.ini
plugins: xdist-3.6.1, mock-3.14.0
created: 8/8 workers
8 workers [6 items]
scheduling tests via LoadScheduling
tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_deleted
tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_merged
tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_replaced_idem
tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_replaced
tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_02_replaced
tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_merged_idem
[gw2] [ 16%] PASSED tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_merged_idem
[gw0] [ 33%] PASSED tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_deleted
[gw3] [ 50%] PASSED tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_replaced
[gw1] [ 66%] PASSED tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_merged
[gw5] [ 83%] PASSED tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_02_replaced
[gw4] [100%] PASSED tests/unit/modules/network/vyos/test_vyos_firewall_global.py::TestVyosFirewallGlobalModule::test_vyos_firewall_global_set_01_replaced_idem
============================== 6 passed in 2.36s ===============================
`
Tested against VyOS versions:
Checklist:
changelogs/fragmentsto describe the changes