mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
Workers failed 'docker build: no Dockerfile': the build context, compose file, .env and runner binary were staged on the stack host only while every node deploys its own node-local runner stack. Build and push the image once on the manager (RUNNER_IMAGE_REF via the swarm registry, 04_image.yml) and let workers pull it; render compose.yml (template with lstrip_blocks, matching the replaced stack_host_template action), .env and the extracted run.sh on every node. Add a node_local kwarg to the compose_networks/container_networks/compose_restart/compose_only lookups so this node-local compose stack renders a bridge default network (workers cannot create overlays), keeps restart: unless-stopped (ephemeral runners died after one job) and keeps container_name under swarm; default is unchanged for every other role. Treat build/install.stamp as stale when the venv is missing and exclude ./build from the nested-src copy, closing the nested-e2e ruamel failure class. Regression tests for the node_local render paths; the network include tests now accept lookup kwargs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
73 lines
2.4 KiB
Python
73 lines
2.4 KiB
Python
"""Lookup `compose_restart`: emit `restart: <policy>` only in compose mode.
|
|
|
|
In swarm mode the `restart:` top-level service key is silently ignored
|
|
because swarm replaces it with `deploy.restart_policy` (rendered by
|
|
`roles/sys-svc-container/templates/deploy.yml.j2`). Emitting `restart:`
|
|
under swarm produces an "Ignoring unsupported options" warning at
|
|
`docker stack deploy` time and double-declares the intent.
|
|
|
|
Default call site:
|
|
|
|
{{ lookup('compose_restart') }}
|
|
|
|
resolves to the global `DOCKER_RESTART_POLICY` from
|
|
`group_vars/all/00_general.yml`. That covers every caller whose intent
|
|
is "use the operator-wide default policy".
|
|
|
|
When a template needs a per-call override (either via Jinja-scope
|
|
``{% set docker_restart_policy = '...' %}`` or a hardcoded literal),
|
|
the caller passes the policy explicitly:
|
|
|
|
{{ lookup('compose_restart', docker_restart_policy | default(DOCKER_RESTART_POLICY)) }}
|
|
{{ lookup('compose_restart', 'on-failure') }}
|
|
|
|
The override path lives at the caller because Jinja-scope `{% set %}`
|
|
bindings are visible only in the rendering template, never in the
|
|
Ansible variable context that the lookup sees.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import contextlib
|
|
from typing import Any
|
|
|
|
from ansible.errors import AnsibleError
|
|
from ansible.plugins.lookup import LookupBase
|
|
|
|
_DEFAULT_POLICY = "unless-stopped"
|
|
|
|
|
|
class LookupModule(LookupBase):
|
|
def run(
|
|
self,
|
|
terms: list[Any] | None,
|
|
variables: dict[str, Any] | None = None,
|
|
**kwargs: Any,
|
|
) -> list[str]:
|
|
if terms and len(terms) > 1:
|
|
raise AnsibleError(
|
|
"compose_restart lookup accepts at most one term: an explicit policy override"
|
|
)
|
|
|
|
vars_ = variables or getattr(self._templar, "available_variables", {}) or {}
|
|
raw_mode = vars_.get("DEPLOYMENT_MODE", "compose")
|
|
templar = getattr(self, "_templar", None)
|
|
if templar is not None:
|
|
with contextlib.suppress(Exception):
|
|
raw_mode = templar.template(raw_mode)
|
|
|
|
if str(raw_mode).strip() == "swarm" and not bool(
|
|
kwargs.get("node_local", False)
|
|
):
|
|
return [""]
|
|
|
|
if terms:
|
|
policy = terms[0]
|
|
else:
|
|
policy = vars_.get("DOCKER_RESTART_POLICY", _DEFAULT_POLICY)
|
|
if templar is not None:
|
|
with contextlib.suppress(Exception):
|
|
policy = templar.template(policy)
|
|
|
|
return [f'restart: "{policy}"']
|