Files
computer-playbook/cli/administration/deploy/development/profile.py
T
kevinveenbirkenbachandClaude Opus 5.5 74d99201e0 feat(cache): share package and tool caches across stacks and release swarm clusters after rescue
Parallel compose slots, swarm lab clusters and GUI lanes each kept their own pip, npm and pacman downloads, and a failed swarm run left its cluster (about 25 GB of node docker data plus the rescue bundle in the act container) on the root filesystem until someone ran make swarm-down. INFINITO_CACHE_SHARED_HOST_PATH (default <DIR_CACHE>/shared) is now mounted read-write at the same path into every compose slot and every swarm lab node, with PIP_CACHE_DIR and npm_config_cache below it; empty, the renders stay byte-identical to before. On a host whose os-release ID is exactly arch running an arch stack, INFINITO_CACHE_HOST_PACMAN_PATH mounts the host pacman cache read-only and scripts/docker/cache/pacman.sh makes it the first CacheDir with <shared>/pacman/ second, so new downloads land in the shared folder and the host cache stays untouched; on Manjaro and every other host pacman uses the shared folder alone.

make swarm-zombie without keep=true now copies the act job's rescue diagnostics and Playwright artefacts to the host and then releases the lab nodes, the lab network, the NFS export volume and the act outer container, on success and on failure; when the copy fails the nodes still go, the act container stays and the run exits naming make swarm-down. make roundtrip passes keep to every swarm step, make clean-cache removes the shared folder, and the disc-space cleanup skips pacman cache directories it cannot write. apt and dnf keep their per-container caches behind the package-cache proxy, and no docker data root is shared between daemons. Requirement 065.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 22:04:38 +01:00

80 lines
3.2 KiB
Python

"""Runtime-context helpers for the dev/CI compose stack."""
from __future__ import annotations
import os
def _declared(name: str) -> bool | None:
"""Explicit capability declaration, or None when it is left to the default."""
raw = (os.environ.get(name) or "").strip()
if raw == "true":
return True
if raw == "false":
return False
return None
class Profile:
"""Runtime identity and the capability decisions derived from it."""
def is_ci(self) -> bool:
"""True when any standard CI signal is set."""
return (
os.environ.get("GITHUB_ACTIONS") == "true"
or os.environ.get("INFINITO_RUNNING_ON_GITHUB") == "true"
or os.environ.get("CI") == "true"
)
def runs_on_github(self) -> bool:
"""True on a real GitHub runner; act and generic CI are not that."""
return os.environ.get("INFINITO_RUNNING_ON_GITHUB") == "true"
def cache_stack_enabled(self) -> bool:
"""True iff the pull-through cache stack should be loaded."""
declared = _declared("INFINITO_CACHE_STACK")
return (not self.is_ci()) if declared is None else declared
def gpu_reservable(self) -> bool:
"""True iff the docker daemon registers an NVIDIA runtime."""
return (os.environ.get("INFINITO_GPU_COUNT") or "0").strip() not in ("", "0")
def image_mirror_enabled(self) -> bool:
"""True iff image references should be rewritten to the GHCR mirror."""
declared = _declared("INFINITO_GHCR_MIRROR")
return self.runs_on_github() if declared is None else declared
def docker_root_ephemeral(self) -> bool:
"""True iff the docker data root may be wiped when the stack goes down."""
return self.runs_on_github()
def instance(self) -> int:
"""Slot index of this checkout; 0 is the primary one.
Bookkeeping only: the compose layering below keys off the concrete
resources a worktree was handed, never off this number, so a stray
slot cannot make compose demand a value nobody set.
"""
raw = (os.environ.get("INFINITO_INSTANCE") or "0").strip()
return int(raw) if raw.isdigit() else 0
def shared_git_dir(self) -> str:
"""Path of the checkout's shared .git directory, empty when it owns one."""
return (os.environ.get("INFINITO_GIT_COMMON_DIR") or "").strip()
def shared_cache_network(self) -> str:
"""Docker network of a cache stack owned elsewhere, empty when unset."""
return (os.environ.get("INFINITO_CACHE_NETWORK") or "").strip()
def owns_cache_stack(self) -> bool:
"""True iff this instance runs the cache stack rather than sharing it."""
return self.cache_stack_enabled() and not self.shared_cache_network()
def shared_package_cache(self) -> str:
"""Shared package and tool cache folder the runner mounts, empty when unset."""
return (os.environ.get("INFINITO_CACHE_SHARED_HOST_PATH") or "").strip()
def host_pacman_cache(self) -> str:
"""Host pacman cache the runner mounts read-only, empty when there is none."""
return (os.environ.get("INFINITO_CACHE_HOST_PACMAN_PATH") or "").strip()