Files
Unraid-AppOps-Gateway-Public/backend/app/services/controller_artifact_helper_spec.py
T

129 lines
4.8 KiB
Python

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"},
},
}