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.18" 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 phase=shell_setup work='' diagnostic_emitted=0 emit_failure() {{ local exit_code="$1" if (( diagnostic_emitted == 0 )); then printf 'APPOPS_CONTROLLER_PROMOTION_DIAGNOSTIC code=helper_failed phase=%s exitCode=%s\\n' "$phase" "$exit_code" >&2 diagnostic_emitted=1 fi }} on_error() {{ local exit_code=$? trap - ERR emit_failure "$exit_code" exit "$exit_code" }} cleanup() {{ local exit_code=$? local cleanup_exit_code=0 trap - EXIT phase=cleanup if [[ -n "$work" ]]; then if rm -rf -- "$work"; then : else cleanup_exit_code=$? emit_failure "$cleanup_exit_code" if (( exit_code == 0 )); then exit_code=$cleanup_exit_code; fi fi fi exit "$exit_code" }} trap on_error ERR umask 077 revision='{revision}' version='{CONTROLLER_VERSION}' image_id='{image_id}' repo='/gitea-repositories/jens/unraid-appops-gateway.git' phase=tmp_root [[ \"$(trap - ERR; stat -c '%a:%u:%g' /tmp)\" == '1777:0:0' ]] phase=workspace_create work=\"$(trap - ERR; mktemp -d -p /tmp itworx-controller-artifact-promoter-{revision[:12]}.XXXXXX)\" phase=workspace_validate [[ -d \"$work\" && ! -L \"$work\" && \"$(stat -c '%u:%a' \"$work\")\" == '0:700' ]] trap cleanup EXIT phase=tool_git command -v git >/dev/null phase=tool_docker command -v docker >/dev/null phase=tool_compose docker compose version >/dev/null phase=tool_python command -v python3 >/dev/null phase=tool_tar command -v tar >/dev/null phase=tool_curl command -v curl >/dev/null phase=source_commit git --git-dir=\"$repo\" cat-file -e \"$revision^{{commit}}\" phase=source_tree tree=\"$(trap - ERR; git --git-dir=\"$repo\" rev-parse \"$revision^{{tree}}\")\" phase=source_archive 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\" phase=archive_permissions chmod 0600 \"$work/controller.tar\" phase=archive_digest archive_sha=\"$(trap - ERR; sha256sum \"$work/controller.tar\" | cut -d ' ' -f 1)\" phase=upgrade_script git --git-dir=\"$repo\" show \"$revision:scripts/upgrade_deployment_controller.sh\" > \"$work/upgrade.sh\" phase=upgrade_permissions chmod 0700 \"$work/upgrade.sh\" phase=upgrade 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"}, }, }