Files
computer-playbook/cli/administration/deploy/development/up.py
T
kevinveenbirkenbachandClaude Opus 5 0cd7af9a42 feat(deploy): make the pinned platform executable before the stack starts
CI receives its emulation from docker/setup-qemu-action. A workstation received
nothing, so an INFINITO_ARCHITECTURE the host cannot execute surfaced as
`exec /bin/sh: exec format error` inside an Ansible role rather than as a
missing handler, which is a considerably worse place to learn about it.

compose-up is where the platform becomes fixed: DOCKER_DEFAULT_PLATFORM is set
when the container is created and cannot change afterwards. ensure() therefore
runs there, skips an unset platform and the host's own architecture, and
otherwise registers what is missing.

The probe runs a container rather than reading /proc/sys/fs/binfmt_misc,
because that directory reads as empty from a sandboxed shell whether or not a
handler exists, so a file check reports "missing" on a machine that emulates
perfectly well. It probes again after installing, since `--install` reporting
OK is not the same as the platform running.

This is the other half of the preceding commit. That one stops the container
from destroying the host's handlers; without this one, a host that never had
them still fails, only less legibly. Neither is sufficient alone, which is why
an earlier version of this file was worthless: it registered handlers that the
deploy then wiped.

Verified: the no-op paths and the registering path all run, and a negative
control against linux/ppc64le, for which this host had no handler, goes from
False to True across the call.

Known limitation: tonistiigi/binfmt replaces a distribution's persistent
entries with ones pointing into a container image. Restoring the originals
needs `systemctl restart systemd-binfmt`, which wants root the deploy path does
not have.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 06:46:07 +02:00

68 lines
1.6 KiB
Python

from __future__ import annotations
import argparse
import os
from .binfmt import ensure as ensure_binfmt
from .build import handler as build_handler
from .common import make_compose
def add_parser(sub: argparse._SubParsersAction) -> None:
p = sub.add_parser("up", help="Start compose stack (coredns + infinito).")
p.add_argument(
"--skip-entry-init",
action="store_true",
help="Do not run ${INFINITO_SRC_DIR}/scripts/docker/entry.sh true after stack is up.",
)
p.add_argument(
"--when-down",
action="store_true",
help="Only start stack if it is not already running.",
)
p.set_defaults(_handler=handler)
def _maybe_build_missing() -> int:
if os.environ["INFINITO_BUILD"] != "1":
return 0
build_args = argparse.Namespace(
missing=True,
no_cache=False,
target="",
tag="",
push=False,
publish=False,
registry="",
owner="",
repo_prefix="",
version="",
stable="",
)
return int(build_handler(build_args))
def _stack_is_running() -> bool:
compose = make_compose()
r = compose.run(["ps", "-q", "infinito"], check=False, capture=True)
cid = (r.stdout or "").strip()
return bool(cid)
def handler(args: argparse.Namespace) -> int:
if args.when_down and _stack_is_running():
print(">>> Stack already running — skipping up")
return 0
ensure_binfmt()
rc = _maybe_build_missing()
if rc != 0:
return rc
compose = make_compose()
compose.up(run_entry_init=not bool(args.skip_entry_init))
return 0