Component: container (src/conf_mode/container.py)
Summary:
Committing a container attached to a network with both an IPv4 and an IPv6
address on the same network config node (`container network <name> prefix
<v4-prefix> + prefix <v6-prefix>`) fails with a ConfigSessionError, because
apply() calls systemctl restart vyos-container-<name>.service and that
command exits with code 1. Because the commit fails, the container/systemd
state is left inconsistent, and the smoketest's tearDown() can no longer
clean it up -- which then cascades and fails every subsequent test in
TestContainer (12 failures + 2 errors reported in one run), even though
those tests' own logic is unaffected.
Environment:
Observed in vyos-1x CI (VyOS ISO Integration Test workflow,
test_smoketest_cli job), rolling branch, on two unrelated PRs (confirming
it's not caused by either PR's own diff):
- https://github.com/vyos/vyos-1x/actions/runs/31334885650 (PR #5389)
- https://github.com/vyos/vyos-1x/actions/runs/31336106412 (PR #5390)
Steps to reproduce (from smoketest/scripts/cli/test_container.py::test_dual_stack_network):
set container network net-4-6 prefix 192.0.2.0/24 set container network net-4-6 prefix 2001:db8::/64 set container name dual-stack-2 image busybox:stable set container name dual-stack-2 network net-4-6 address 192.0.2.2 set container name dual-stack-2 network net-4-6 address 2001:db8::2 # (repeat for dual-stack-3..5) commit
Expected: commit succeeds, containers start on the dual-stack network.
Actual: commit raises ConfigSessionError:
File "conf_mode/container.py", line 709, in apply
cmdl(['systemctl', 'restart', f'vyos-container-{name}.service'])
File "vyos/utils/process.py", line 217, in cmdl
raise OSError(code, feedback)
PermissionError: [Errno 1] failed to run command: systemctl restart vyos-container-dual-stack-2.service
returned:
exit code: 1Root cause analysis:
- The vyos-container-<name>.service unit is Type=forking with ExecStart=/usr/bin/podman run --conmon-pidfile ... --cgroups=no-conmon {run_args}. The failure happens within roughly a second (no ~90s TimeoutStartSec wait visible in the timestamps), which points to podman run itself exiting immediately with an error rather than a startup timeout.
- generate_run_arguments() (container.py ~line 522-538) builds, for a network with both an IPv4 and IPv6 address configured, both --ip <v4> and --ip6 <v6> for the *same* --network <name> argument. This dual-stack-on-one-network path is the one specific difference between the failing test (test_dual_stack_network) and the passing single-stack ones (test_ipv4_network, test_ipv6_network), which is why I suspect this specific argument combination as the trigger -- but I have not reproduced this live against podman run directly, so I can't yet confirm which exact flag/value podman rejects.
- Because systemctl restart output isn't captured/logged (returned: is empty in the exception message), the actual podman/systemd error text isn't visible anywhere in the CI log -- someone with a reproducing VyOS instance would need to check journalctl -u vyos-container-dual-stack-2.service (or run the equivalent podman run command by hand) to see the real underlying error.
Secondary issue (error reporting, not the root cause): vyos/utils/process.py:217,
cmdl() raises OSError(code, feedback) passing the process's raw exit code as
the errno argument. Python's OSError.new auto-selects a subclass based
on that value, so an ordinary exit code of 1 gets rendered as PermissionError
(since 1 == errno.EPERM), which is misleading -- it looks like a permissions
problem when it's just "the command exited 1". This makes debugging commands
invoked via cmdl() unnecessarily confusing whenever their exit code happens
to collide with a real errno value. Worth a follow-up fix (e.g. raising a
plain OSError/custom exception without relying on the errno-based subclass
dispatch) independent of the container bug itself.
Impact: Since setUpClass/tearDownClass in TestContainer only run once per
test class, this single failure leaves systemd units/conmon processes
behind that pollute every alphabetically later test in the class, producing
a large, misleading batch of unrelated-looking smoketest failures on any PR
that happens to run the full CLI smoketest suite -- as seen on #5389 and
#5390, neither of which touch container code.