Add multi-architecture Linux system matrix

This commit is contained in:
Ochenstarik 2026-07-19 14:49:15 +07:00
parent 470034f137
commit 08ccda8aa2
8 changed files with 302 additions and 1 deletions

View file

@ -42,9 +42,13 @@ jobs:
bash -n deploy/ochenstarik-server-monitor-manager.sh
bash -n deploy/ochenstarik-smm-policy-apply
bash -n deploy/ochenstarik-smm-emergency
bash -n tests/bootstrap/run-native-systemd-smoke.sh
bash -n tests/bootstrap/run-systemd-container-smoke.sh
shellcheck --severity=error deploy/ochenstarik-server-monitor-manager.sh
shellcheck --severity=error deploy/ochenstarik-smm-policy-apply
shellcheck --severity=error deploy/ochenstarik-smm-emergency
shellcheck --severity=error tests/bootstrap/run-native-systemd-smoke.sh
shellcheck --severity=error tests/bootstrap/run-systemd-container-smoke.sh
bash tests/bootstrap/test-bootstrap-contract.sh
- name: Publish agent amd64

View file

@ -0,0 +1,149 @@
name: Linux platform matrix
on:
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/linux-platform-matrix.yml'
- 'deploy/**'
- 'src/ServerMonitorManager.Agent/**'
- 'src/ServerMonitorManager.Control/**'
- 'src/ServerMonitorManager.Core/**'
- 'tests/bootstrap/**'
push:
branches: [main]
paths:
- '.github/workflows/linux-platform-matrix.yml'
- 'deploy/**'
- 'src/ServerMonitorManager.Agent/**'
- 'src/ServerMonitorManager.Control/**'
- 'src/ServerMonitorManager.Core/**'
- 'tests/bootstrap/**'
permissions:
contents: read
concurrency:
group: linux-platform-matrix-${{ github.ref }}
cancel-in-progress: true
jobs:
release-archive:
name: Release archive (${{ matrix.runtime }})
runs-on: ubuntu-24.04
strategy:
matrix:
runtime: [linux-x64, linux-arm64]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up .NET 10
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x
- name: Publish compatible release
run: |
set -Eeuo pipefail
dotnet publish src/ServerMonitorManager.Agent/ServerMonitorManager.Agent.csproj \
--configuration Release --runtime '${{ matrix.runtime }}' --self-contained true \
-p:PublishSingleFile=true -p:PublishTrimmed=true -o out/agent
dotnet publish src/ServerMonitorManager.Control/ServerMonitorManager.Control.csproj \
--configuration Release --runtime '${{ matrix.runtime }}' --self-contained true \
-p:PublishSingleFile=true -p:PublishTrimmed=true -o out/control
install -d out/deploy out/bootstrap
install -m 0644 deploy/ochenstarik-smm-control.service out/deploy/
install -m 0644 deploy/ochenstarik-smm-agent.service out/deploy/
install -m 0644 deploy/ochenstarik-smm-firewall.service out/deploy/
install -m 0755 deploy/ochenstarik-smm-policy-apply out/deploy/
install -m 0755 deploy/ochenstarik-smm-emergency out/deploy/
install -m 0755 deploy/ochenstarik-server-monitor-manager.sh out/bootstrap/
archive='server-monitor-manager-${{ matrix.runtime }}.tar.gz'
tar -C out -czf "$archive" agent control deploy bootstrap
sha256sum "$archive" >"$archive.sha256"
- name: Upload release archive
uses: actions/upload-artifact@v6
with:
name: server-monitor-manager-${{ matrix.runtime }}-matrix
path: |
server-monitor-manager-${{ matrix.runtime }}.tar.gz
server-monitor-manager-${{ matrix.runtime }}.tar.gz.sha256
ubuntu-vm:
name: ${{ matrix.name }} native VM
needs: release-archive
strategy:
fail-fast: false
matrix:
include:
- name: Ubuntu 22.04 x64
runner: ubuntu-22.04
runtime: linux-x64
- name: Ubuntu 24.04 x64
runner: ubuntu-24.04
runtime: linux-x64
- name: Ubuntu 22.04 arm64
runner: ubuntu-22.04-arm
runtime: linux-arm64
- name: Ubuntu 24.04 arm64
runner: ubuntu-24.04-arm
runtime: linux-arm64
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download release archive
uses: actions/download-artifact@v8
with:
name: server-monitor-manager-${{ matrix.runtime }}-matrix
path: artifacts
- name: Install twice and restart services
run: |
bash tests/bootstrap/run-native-systemd-smoke.sh \
'artifacts/server-monitor-manager-${{ matrix.runtime }}.tar.gz' \
deploy/ochenstarik-server-monitor-manager.sh
debian-systemd:
name: ${{ matrix.name }} systemd restart
needs: release-archive
strategy:
fail-fast: false
matrix:
include:
- name: Debian 12 x64
runner: ubuntu-24.04
runtime: linux-x64
image: debian:12
- name: Debian 13 x64
runner: ubuntu-24.04
runtime: linux-x64
image: debian:13
- name: Debian 12 arm64
runner: ubuntu-24.04-arm
runtime: linux-arm64
image: debian:12
- name: Debian 13 arm64
runner: ubuntu-24.04-arm
runtime: linux-arm64
image: debian:13
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download release archive
uses: actions/download-artifact@v8
with:
name: server-monitor-manager-${{ matrix.runtime }}-matrix
path: artifacts
- name: Install twice and restart systemd container
run: |
bash tests/bootstrap/run-systemd-container-smoke.sh \
'${{ matrix.image }}' \
'artifacts/server-monitor-manager-${{ matrix.runtime }}.tar.gz' \
deploy/ochenstarik-server-monitor-manager.sh

View file

@ -21,9 +21,13 @@ jobs:
bash -n deploy/ochenstarik-server-monitor-manager.sh
bash -n deploy/ochenstarik-smm-policy-apply
bash -n deploy/ochenstarik-smm-emergency
bash -n tests/bootstrap/run-native-systemd-smoke.sh
bash -n tests/bootstrap/run-systemd-container-smoke.sh
shellcheck --severity=error deploy/ochenstarik-server-monitor-manager.sh
shellcheck --severity=error deploy/ochenstarik-smm-policy-apply
shellcheck --severity=error deploy/ochenstarik-smm-emergency
shellcheck --severity=error tests/bootstrap/run-native-systemd-smoke.sh
shellcheck --severity=error tests/bootstrap/run-systemd-container-smoke.sh
bash tests/bootstrap/test-bootstrap-contract.sh
- name: Package bootstrap

View file

@ -0,0 +1,20 @@
# Linux platform matrix
Workflow `linux-platform-matrix.yml` собирает те же self-contained release-архивы, которые устанавливает production bootstrap, отдельно для `linux-x64` и `linux-arm64`.
## Реальные Ubuntu VM
На GitHub-hosted VM проверяются:
- Ubuntu 22.04 x64;
- Ubuntu 24.04 x64;
- Ubuntu 22.04 arm64;
- Ubuntu 24.04 arm64.
Каждая VM выполняет `preflight`, проверяет checksum и содержимое архива, дважды устанавливает Control, проверяет emergency-команду, перезапускает systemd service и обращается к HTTPS `/healthz` через созданный CA.
## Debian systemd containers
Debian 12/13 проверяются для x64 и arm64 в privileged systemd-контейнерах на соответствующей архитектуре runner. Тест выполняет чистую и повторную установку, затем полностью перезапускает контейнер и проверяет автоматический запуск Control и HTTPS healthcheck после нового systemd boot.
Systemd-контейнер проверяет дистрибутив, users, permissions, units, certificates, SQLite state и service lifecycle, но не считается полноценной Debian VM. Отдельным незакрытым критерием остаётся reboot настоящих Debian VM с собственным kernel. Физическая проверка WireGuard/nftables также выполняется по `three-server-acceptance.md`, поскольку GitHub runners не моделируют внешний NAT и cloud firewall.

View file

@ -2,6 +2,8 @@
Подробные требования к собственному bootstrap, управляемой настройке Linux и Xray находятся в [ТЗ Provisioning и Xray VPN](provisioning-vpn-requirements.md). Все компоненты Server Monitor Manager разрабатываются, версионируются и выпускаются только в этом репозитории.
Текущее автоматическое покрытие поддерживаемых Linux-платформ описано в [Linux platform matrix](linux-platform-matrix.md).
## Этап 0 — граница и базовая архитектура
- [x] переименовать проект в Server Monitor Manager;
@ -99,7 +101,9 @@
- [x] локально создавать Agent key/CSR, выполнять mTLS enrollment и не сохранять token;
- [x] добавить собственную установку WireGuard Hub/Node и выдачу внутренних адресов;
- [x] реализовать nftables policy helper вместо временного deny-by-default helper;
- [ ] добавить VM CI matrix, повторную установку и reboot;
- [x] добавить native Ubuntu 22.04/24.04 x64/arm64 VM CI и повторную установку;
- [x] добавить Debian 12/13 x64/arm64 systemd-container restart matrix;
- [ ] добавить полный reboot настоящих Debian VM;
- [x] добавить локальную emergency recovery command для текущих Mesh/firewall-компонентов.
## Этап 8 — Provisioning control plane

View file

@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -Eeuo pipefail
IFS=$'\n\t'
archive="${1:?usage: run-native-systemd-smoke.sh ARCHIVE BOOTSTRAP}"
bootstrap="${2:?usage: run-native-systemd-smoke.sh ARCHIVE BOOTSTRAP}"
port="${SMM_SMOKE_PORT:-17443}"
cleanup() {
sudo "$bootstrap" uninstall-control --confirm-destroy-control >/dev/null 2>&1 || true
}
trap cleanup EXIT
sudo "$bootstrap" preflight
sudo "$bootstrap" verify-release "$archive"
sudo "$bootstrap" install-control "$archive" 127.0.0.1 "$port"
sudo test -x /usr/local/sbin/ochenstarik-smm-emergency
sudo /usr/local/sbin/ochenstarik-smm-emergency status
for _ in {1..30}; do
if sudo curl --fail --silent \
--cacert /etc/ochenstarik-server-monitor-manager/control-ca.crt \
"https://127.0.0.1:$port/healthz" >/dev/null; then
break
fi
sleep 1
done
sudo curl --fail --silent --show-error \
--cacert /etc/ochenstarik-server-monitor-manager/control-ca.crt \
"https://127.0.0.1:$port/healthz"
sudo "$bootstrap" install-control "$archive" 127.0.0.1 "$port"
sudo systemctl restart ochenstarik-smm-control.service
sudo systemctl is-active --quiet ochenstarik-smm-control.service
sudo curl --fail --silent --show-error --retry 15 --retry-all-errors --retry-delay 1 \
--cacert /etc/ochenstarik-server-monitor-manager/control-ca.crt \
"https://127.0.0.1:$port/healthz"
printf '%s\n' "NATIVE_SYSTEMD_SMOKE=PASS"

View file

@ -0,0 +1,67 @@
#!/usr/bin/env bash
set -Eeuo pipefail
IFS=$'\n\t'
root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
base_image="${1:?usage: run-systemd-container-smoke.sh BASE_IMAGE ARCHIVE BOOTSTRAP}"
archive="$(realpath "${2:?archive is required}")"
bootstrap="$(realpath "${3:?bootstrap is required}")"
name="smm-systemd-${RANDOM}-${RANDOM}"
image="smm-systemd-smoke:${base_image//[:\/]/-}"
port="17443"
cleanup() {
docker rm -f "$name" >/dev/null 2>&1 || true
}
trap cleanup EXIT
docker build \
--build-arg "BASE_IMAGE=$base_image" \
-f "$root/tests/bootstrap/systemd-container.Dockerfile" \
-t "$image" \
"$root"
docker run --detach --privileged --cgroupns=private \
--tmpfs /run --tmpfs /run/lock --name "$name" "$image" >/dev/null
for _ in {1..30}; do
if docker exec "$name" systemctl is-system-running >/dev/null 2>&1; then
break
fi
state="$(docker exec "$name" systemctl is-system-running 2>/dev/null || true)"
[[ "$state" == "degraded" ]] && break
sleep 1
done
state="$(docker exec "$name" systemctl is-system-running 2>/dev/null || true)"
[[ "$state" == "running" || "$state" == "degraded" ]] || {
docker exec "$name" systemctl --failed --no-pager || true
printf '%s\n' "container systemd did not finish booting: $state" >&2
exit 1
}
docker cp "$archive" "$name:/tmp/release.tar.gz"
docker cp "${archive}.sha256" "$name:/tmp/release.tar.gz.sha256"
docker cp "$bootstrap" "$name:/tmp/ochenstarik-server-monitor-manager.sh"
docker exec "$name" chmod 0700 /tmp/ochenstarik-server-monitor-manager.sh
docker exec "$name" /tmp/ochenstarik-server-monitor-manager.sh preflight
docker exec "$name" /tmp/ochenstarik-server-monitor-manager.sh install-control \
/tmp/release.tar.gz 127.0.0.1 "$port"
docker exec "$name" curl --fail --silent --show-error --retry 15 --retry-all-errors --retry-delay 1 \
--cacert /etc/ochenstarik-server-monitor-manager/control-ca.crt \
"https://127.0.0.1:$port/healthz"
docker exec "$name" /tmp/ochenstarik-server-monitor-manager.sh install-control \
/tmp/release.tar.gz 127.0.0.1 "$port"
docker restart "$name" >/dev/null
for _ in {1..60}; do
if docker exec "$name" systemctl is-active --quiet ochenstarik-smm-control.service; then
break
fi
sleep 1
done
docker exec "$name" systemctl is-active --quiet ochenstarik-smm-control.service
docker exec "$name" curl --fail --silent --show-error --retry 15 --retry-all-errors --retry-delay 1 \
--cacert /etc/ochenstarik-server-monitor-manager/control-ca.crt \
"https://127.0.0.1:$port/healthz"
docker exec "$name" /usr/local/sbin/ochenstarik-smm-emergency status
printf '%s\n' "SYSTEMD_CONTAINER_SMOKE=PASS image=$base_image"

View file

@ -0,0 +1,14 @@
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
ENV container=docker
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates curl iproute2 openssl procps sudo systemd systemd-sysv \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
STOPSIGNAL SIGRTMIN+3
CMD ["/sbin/init"]