hololake-system-architecture/product-source/hololake-platform/guanghu-os/scripts/linux-subcontrol-docker-backend.sh

166 lines
5.8 KiB
Shell
Executable file

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
die() {
echo "GUANGHU_LINUX_SUBCONTROL_FAIL_0: $*" >&2
exit 1
}
test_mode=${GH_SUBCONTROL_TEST_MODE:-0}
if [[ "${test_mode}" == 1 ]]; then
config_path=${GH_SUBCONTROL_CONFIG:?test config is required}
docker_bin=${GH_SUBCONTROL_DOCKER:?test docker is required}
dmi_path=${GH_SUBCONTROL_DMI_PATH:?test DMI path is required}
grub_cfg=${GH_SUBCONTROL_GRUB_CFG:?test GRUB path is required}
state_root=${GH_SUBCONTROL_STATE_ROOT:?test state root is required}
receipt_root=${GH_SUBCONTROL_RECEIPT_ROOT:?test receipt root is required}
else
[[ "${EUID}" == 0 ]] || die "root execution is required"
for override in \
GH_SUBCONTROL_CONFIG GH_SUBCONTROL_DOCKER GH_SUBCONTROL_DMI_PATH \
GH_SUBCONTROL_GRUB_CFG GH_SUBCONTROL_STATE_ROOT GH_SUBCONTROL_RECEIPT_ROOT; do
[[ -z "${!override:-}" ]] || die "production path override is forbidden: ${override}"
done
config_path=/etc/guanghu/linux-subcontrol.conf
docker_bin=/usr/bin/docker
dmi_path=/sys/class/dmi/id/product_uuid
grub_cfg=/boot/grub/grub.cfg
state_root=/run/guanghu/linux-subcontrol
receipt_root=/guanghu/receipts/linux-subcontrol
[[ -f "${config_path}" && ! -L "${config_path}" ]] || die "root-owned backend config is missing"
[[ "$(stat -c '%u:%a' "${config_path}")" =~ ^0:(600|640|644)$ ]] ||
die "backend config owner or mode is unsafe"
fi
schema=
node_id=
instance_id=
backend_id=
container_name=
image=
rescue_slot_id=
while IFS='=' read -r key value; do
[[ -n "${key}" ]] || continue
case "${key}" in
schema|node_id|instance_id|backend_id|container_name|image|rescue_slot_id)
printf -v "${key}" '%s' "${value}"
;;
*) die "unknown config field: ${key}" ;;
esac
done <"${config_path}"
[[ "${schema}" == "guanghu.linux-subcontrol-docker-backend/v1" ]] || die "config schema mismatch"
[[ "${node_id}" == "JD-FD-PRIMARY" ]] || die "target node mismatch"
[[ "${instance_id}" =~ ^[0-9a-f-]{36}$ ]] || die "instance id is invalid"
[[ "${backend_id}" =~ ^[a-z0-9-]+$ ]] || die "backend id is invalid"
[[ "${container_name}" =~ ^[a-z0-9-]+$ ]] || die "container name is invalid"
[[ "${image}" =~ ^ubuntu@sha256:[0-9a-f]{64}$ ]] || die "image must use an immutable Ubuntu digest"
[[ "${rescue_slot_id}" =~ ^[A-Za-z0-9._-]+$ ]] || die "rescue slot id is invalid"
[[ -x "${docker_bin}" ]] || die "docker executable is unavailable"
requested_backend=${2:-}
[[ -n "${requested_backend}" && "${requested_backend}" == "${backend_id}" ]] ||
die "backend binding mismatch"
verify_machine() {
local observed
observed=$(tr '[:upper:]' '[:lower:]' <"${dmi_path}")
[[ "${observed}" == "${instance_id}" ]] || die "machine identity mismatch"
}
verify_rescue() {
grep -Fq -- "--id '${rescue_slot_id}'" "${grub_cfg}" ||
die "independent Linux rescue slot is unavailable"
}
container_running() {
[[ "$("${docker_bin}" inspect --format '{{.State.Running}}' "${container_name}" 2>/dev/null || true)" == true ]]
}
observe() {
if container_running; then
echo ready
else
echo dormant
fi
}
action=${1:-}
case "${action}" in
preflight)
verify_machine
verify_rescue
"${docker_bin}" image inspect "${image}" >/dev/null
echo "GUANGHU_LINUX_SUBCONTROL_PREFLIGHT_OK"
;;
observe)
observe
;;
wake)
verify_machine
verify_rescue
[[ "$(observe)" == dormant ]] || die "backend is not dormant before wake"
"${docker_bin}" image inspect "${image}" >/dev/null
mkdir -p "${state_root}" "${receipt_root}"
"${docker_bin}" run \
--detach \
--pull never \
--name "${container_name}" \
--hostname jd-linux-subcontrol \
--label guanghu.owner=GUANGHU_OS \
--label "guanghu.node=${node_id}" \
--label "guanghu.backend=${backend_id}" \
--network none \
--read-only \
--tmpfs /run:rw,nosuid,nodev,noexec,size=16m \
--tmpfs /tmp:rw,nosuid,nodev,noexec,size=16m \
--cap-drop ALL \
--security-opt no-new-privileges \
--pids-limit 64 \
--memory 256m \
--cpus 0.50 \
"${image}" \
/bin/sh -ceu 'trap "exit 0" TERM INT; while :; do sleep 3600 & wait $!; done' \
>/dev/null
container_running || die "backend failed readiness readback"
echo "GUANGHU_LINUX_SUBCONTROL_READY"
;;
execute|verify)
capability=${3:-}
request_id=${4:-}
[[ "${capability}" == runtime-identity-readback ]] || die "capability is not allowlisted"
[[ "${request_id}" =~ ^[A-Za-z0-9._-]+$ ]] || die "request id is invalid"
container_running || die "backend is not ready"
mkdir -p "${state_root}" "${receipt_root}"
target_file="${state_root}/${request_id}.target"
if [[ "${action}" == execute ]]; then
temporary="${target_file}.tmp"
"${docker_bin}" exec "${container_name}" /bin/sh -ceu \
'. /etc/os-release; printf "ID=%s\nVERSION_ID=%s\n" "$ID" "$VERSION_ID"' \
>"${temporary}"
chmod 600 "${temporary}"
mv "${temporary}" "${target_file}"
echo "GUANGHU_LINUX_SUBCONTROL_EXECUTED"
else
[[ -f "${target_file}" ]] || die "target readback is missing"
expected=$'ID=ubuntu\nVERSION_ID=22.04'
stored=$(cat "${target_file}")
live=$("${docker_bin}" exec "${container_name}" /bin/sh -ceu \
'. /etc/os-release; printf "ID=%s\nVERSION_ID=%s\n" "$ID" "$VERSION_ID"')
[[ "${stored}" == "${expected}" && "${live}" == "${expected}" ]] ||
die "target readback mismatch"
echo "GUANGHU_LINUX_SUBCONTROL_TARGET_VERIFIED"
fi
;;
reclaim)
if container_running; then
"${docker_bin}" rm --force "${container_name}" >/dev/null
fi
[[ "$(observe)" == dormant ]] || die "backend reclaim failed"
echo "GUANGHU_LINUX_SUBCONTROL_DORMANT"
;;
*)
die "usage: $0 <preflight|observe|wake|execute|verify|reclaim> <backend-id> [capability] [request-id]"
;;
esac