Krikri::PluginHelpers::IptablesCommand
Pure rule-construction/command-building/validation logic for
plugins/iptables.cr, split out so it can be unit-tested without a
real iptables binary/root (-C/-A/-D all require
CAP_NET_ADMIN, unavailable in the spec sandbox - see
plugins/iptables.cr's own doc comment). Mirrors Ansible's
construct_rule() flag-for-flag, including its exact ordering
(matters for -C to actually match what -A would insert), its
push_arguments() command framing (rule_num only on -I, -w
after the action, --numeric only on the -L call sites), and its
argument-spec validation messages (mutually_exclusive /
required_if / required_by wording from
the Ansible module).
construct_rule() returns RAW tokens, exactly like Ansible's own:
values as given, no quoting - the registered rule string is
Ansible's ' '.join(construct_rule(params)) (probe-verified:
a comment value reaches it unquoted, words joined with plain
spaces). Quoting exists only when the exec command string is
built (push_arguments shell-quotes each token so the
/bin/bash -c framing keeps every value ONE argument, the way
Ansible's run_command passes its argv list); push_arguments
with for_display: true returns the raw space-join that
Ansible's _clean_args puts in a failure's cmd.
Constants
Ansible's argument-spec validation for this module, message-for-message (the Ansible module wording), in its own evaluation order: mutually_exclusive (which Ansible checks BEFORE applying defaults, so only an explicitly passed flush: counts), then the per-parameter choices, then required_if, then required_by. Returns the failure message, or nil when everything passes.
CHOICES_BY_PARAM: the argument_spec's own choices lists, in the module's declaration order (the failure message echoes that order). Real-Ansible position pinned empirically: a mutually-exclusive pair fires before choices (flush + policy=DENY reports the mutual exclusion), but choices fire before required_if (state=enabled with no chain reports the choice, not the missing chain).
Class methods
Real-Ansible parameter order, flag-for-flag (construct_rule()). Returns the flag list, or a real-Ansible failure message when building it raises the way Python does - see the two quirks noted inline below.
Ansible's push_arguments(): everything it builds (the -C
check, -A/-I/-D applies, the -F/-P/-L/-N/-X
chain/policy operations) shares this framing - -t table,
action, chain, the insert position (only on -I), then -w
wait, then the rule flags. numeric is appended only by the
-L call sites (get_chain_policy/check_chain_present).
The rule tokens arrive RAW (see construct_rule); the exec
string shell-quotes each one with Shell.quote_arg - unlike
quote_if_needed it treats whitespace as unsafe, so a
multi-word value (comment, set_counters "10 20") stays ONE
argument, matching Ansible's run_command argv list (which
passes each value as a single element, whatever it contains).
With for_display the raw tokens are space-joined instead,
byte-identical to Ansible's ' '.join(...) rule string and
_clean_args failure cmd.