from __future__ import annotations import re from typing import Any SOURCE_REPOSITORY = "jens/unraid-appops-gateway" HELPER_NAME = "itworx-controller-artifact-promoter-modern" CONTROLLER_VERSION = "2.1.14" HELPER_LABEL = "itworx.controller.promoter" _REVISION = re.compile(r"^[0-9a-f]{40}$") _IMAGE_ID = re.compile(r"^sha256:[0-9a-f]{64}$") _CONTAINER_ID = re.compile(r"^[0-9a-f]{64}$") _VERSION = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+(?:[-+][0-9A-Za-z.-]+)?$") def helper_container_spec( *, revision: str, image_id: str, current_controller_id: str | None = None, current_controller_revision: str | None = None, current_controller_tree: str | None = None, current_controller_version: str | None = None, ) -> dict[str, Any]: if not _REVISION.fullmatch(revision): raise ValueError("controller_promoter_revision_invalid") if not _IMAGE_ID.fullmatch(image_id): raise ValueError("controller_promoter_image_invalid") bootstrap_values = ( current_controller_id, current_controller_revision, current_controller_tree, current_controller_version, ) if any(value is not None for value in bootstrap_values): if ( not _CONTAINER_ID.fullmatch(current_controller_id or "") or not _REVISION.fullmatch(current_controller_revision or "") or not _REVISION.fullmatch(current_controller_tree or "") or not _VERSION.fullmatch(current_controller_version or "") ): raise ValueError("controller_promoter_bootstrap_binding_invalid") command = f"""set -Eeuo pipefail umask 077 revision='{revision}' version='{CONTROLLER_VERSION}' image_id='{image_id}' repo='/gitea-repositories/jens/unraid-appops-gateway.git' [[ \"$(stat -c '%a:%u:%g' /tmp)\" == '1777:0:0' ]] work=\"$(mktemp -d -p /tmp itworx-controller-artifact-promoter-{revision[:12]}.XXXXXX)\" [[ -d \"$work\" && ! -L \"$work\" && \"$(stat -c '%u:%a' \"$work\")\" == '0:700' ]] cleanup() {{ rm -rf -- \"$work\"; }} trap cleanup EXIT command -v git >/dev/null command -v docker >/dev/null docker compose version >/dev/null command -v python3 >/dev/null command -v tar >/dev/null command -v curl >/dev/null git --git-dir=\"$repo\" cat-file -e \"$revision^{{commit}}\" tree=\"$(git --git-dir=\"$repo\" rev-parse \"$revision^{{tree}}\")\" git --git-dir=\"$repo\" archive --format=tar \"$revision\" \\ ops/gitea-deploy-broker \\ scripts/prepare_controller_artifact.py \\ scripts/reconcile_controller_state.py \\ scripts/prepare_controller_hub_release_volume.py \\ scripts/vendor \\ scripts/run_repopulse_adoption.py \ scripts/upgrade_deployment_controller.sh > \"$work/controller.tar\" chmod 0600 \"$work/controller.tar\" archive_sha=\"$(sha256sum \"$work/controller.tar\" | cut -d ' ' -f 1)\" git --git-dir=\"$repo\" show \"$revision:scripts/upgrade_deployment_controller.sh\" > \"$work/upgrade.sh\" chmod 0700 \"$work/upgrade.sh\" bash \"$work/upgrade.sh\" \\ --archive \"$work/controller.tar\" \\ --archive-sha256 \"$archive_sha\" \\ --source-repository '{SOURCE_REPOSITORY}' \\ --source-revision \"$revision\" \\ --source-tree \"$tree\" \\ --controller-version \"$version\" \\ --image-id \"$image_id\" \\ --confirm UPGRADE_DEPLOYMENT_CONTROLLER_V2 """ labels = { HELPER_LABEL: "true", "itworx.source.repository": SOURCE_REPOSITORY, "itworx.source.revision": revision, "itworx.controller.version": CONTROLLER_VERSION, } if current_controller_id is not None: labels.update( { "itworx.controller.bootstrap.target.id": current_controller_id, "itworx.controller.bootstrap.target.image": image_id, "itworx.controller.bootstrap.target.revision": current_controller_revision or "", "itworx.controller.bootstrap.target.tree": current_controller_tree or "", "itworx.controller.bootstrap.target.version": current_controller_version or "", } ) return { "Image": image_id, "User": "0:0", "Cmd": ["/bin/bash", "-lc", command], "Labels": labels, "HostConfig": { "Binds": [ "/mnt/cache:/mnt/cache", "/mnt/user:/mnt/user", "/var/lib/docker:/var/lib/docker:ro", "/srv/example/appdata/gitea/git/repositories:/gitea-repositories:ro", "/var/run/docker.sock:/var/run/docker.sock", ], "NetworkMode": "host", "Privileged": False, "ReadonlyRootfs": True, "CpuPeriod": 100000, "CpuQuota": 100000, "Memory": 1024 * 1024 * 1024, "PidsLimit": 128, "Tmpfs": {"/tmp": "rw,nosuid,nodev,size=268435456,mode=1777"}, "SecurityOpt": ["no-new-privileges:true"], "RestartPolicy": {"Name": "no"}, }, }