Krikri::PluginHelpers::FirewalldCommand
FirewalldCommand - pure logic for building firewall-offline-cmd
command lines. No I/O here - the plugin itself runs the resulting
commands.
--zone=<zone> --query-<thing>=<value> exits 0/prints "yes" if
present, exits 1/prints "no" if absent - verified empirically
against a real firewall-offline-cmd (firewalld 2.1.1) in a real
container, since this behavior isn't documented in ansible-doc at
all (it belongs to firewall-offline-cmd itself, a companion CLI
tool, not the Ansible module).
service removal is a real, confirmed quirk: --remove-service
(no -from-zone suffix) is a legacy "lokkit" option that can't be
combined with --zone= at all (real, verified error: "Can't use
lokkit options with other options") - the zone-scoped removal form
is --remove-service-from-zone=. port/rich-rule/source/
masquerade don't have this quirk; their plain --remove-<thing>=
forms work fine with --zone=.
The ZoneXml section below is the direct zone-config-file backend for offline mode: real ansible.posix.firewalld's offline mode does NOT shell out to firewall-offline-cmd at all - it uses firewalld's own Python Firewall(offline=True), which loads the /usr/lib/ firewalld + /etc/firewalld zone XML into memory and writes changes back to /etc/firewalld/zones/<zone>.xml. firewall-offline-cmd, by contrast, dies entirely in environments where its protocol validation can't resolve entries like 'esp' (getprotobyname('esp') fails in a slim container), so a CLI-based offline backend diverges from real Ansible in exactly the containerized hosts this project targets. These helpers operate on the XML file CONTENT only - the plugin owns the reads/writes/paths.
Constants
Things whose add/remove/query flags take NO value at all
(--add-masquerade, not --add-masquerade=true) - verified
empirically against a real firewall-offline-cmd (firewalld
2.3.1) in a real container for icmp_block_inversion/forward too,
the same way masquerade originally was.
Class methods
A <forward-port> element's identifying attributes for a port_forward entry dict (port/proto required, toport required, toaddr optional and simply absent from the element when not given - matching the compound-value shape ForwardPortTransaction builds).
Builds the compound port=X:proto=Y:toport=Z[:toaddr=W] value
real Ansible's own ForwardPortTransaction builds from a
port_forward: entry (a dict with port/proto/toport
required, toaddr optional and simply omitted from the value
when absent - verified against the real module's own source and
live against a real firewall-offline-cmd, firewalld 1.3.3).
Returns {value: nil, error: "..."} with the exact error message
real Ansible raises (checked in the same port/proto/toport order
the real module checks them) when a required key is missing, or
{value: "port=...", error: nil} on success.
binary selects the runtime/live-daemon CLI (firewall-cmd,
talking to a running firewalld over D-Bus) vs the on-disk XML
editor (firewall-offline-cmd, no daemon needed) - the flags
after the binary are identical between the two.
Returns nil if none or more than one "thing" param is present - matches real Ansible's own mutually_exclusive constraint (exactly one of service/port/rich_rule/source/masquerade/etc per task).
Serialized zone XML with the element added, or nil if it's already present (query-then-add stays the caller's idempotency primitive, mirroring the CLI path's query exit code).
The XML element name + identifying attributes each "thing" serializes to inside a zone config file. The compound value shapes are firewalld's own file format: port is "N/proto" split across the port/protocol attributes, everything else maps attribute-for-attribute. rich_rule is absent here on purpose: its string form parses through firewalld's own Rich_Rule into arbitrarily nested <rule> XML, and a hand-rolled subset would break query canonicalization (attribute order/equivalence), so it stays on the firewall-offline-cmd path.
Does the zone XML already contain the element? (the query step - exactly one element matching name + every identifying attribute)
Serialized zone XML with the element removed, or nil if it wasn't present.