Полный production-рефакторинг билдера, drift-reconcile и документации по up5
This commit is contained in:
+43
-38
@@ -1,54 +1,59 @@
|
||||
# Build tooling
|
||||
# AWG2 Harness builder
|
||||
|
||||
[`build.sh`](tools/build.sh) — production build gate для [`traffic_core`](traffic_core/Cargo.toml).
|
||||
Основной скрипт: [`build.sh`](build.sh).
|
||||
Целевой crate: [`traffic_core`](../traffic_core/Cargo.toml).
|
||||
Unit: [`awg2-harness.service`](../awg2-harness.service).
|
||||
Пример конфига: [`config.example.toml`](../config.example.toml).
|
||||
|
||||
## Что делает
|
||||
## Supported host
|
||||
|
||||
Скрипт:
|
||||
- Debian/Ubuntu (apt-based)
|
||||
- amd64/x86_64
|
||||
|
||||
1. Проверяет OS и архитектуру (Debian/Ubuntu, amd64/x86_64).
|
||||
2. Проверяет наличие инструментов: `cargo`, `rustc`, `gcc`, `pkg-config`, `file`, `ldd`.
|
||||
3. Проверяет минимальную версию Rust (`rustc >= 1.85.0`).
|
||||
4. Запускает quality gate:
|
||||
- `cargo fmt --check` (если не указан `--skip-fmt`),
|
||||
- `cargo clippy --locked --all-targets -- -D warnings`,
|
||||
- `cargo test --locked --release`,
|
||||
- `cargo build --locked --release`.
|
||||
5. Проверяет собранный бинарь: `file`, `ldd`, `--help`, `sha256sum`.
|
||||
|
||||
## Что НЕ делает
|
||||
|
||||
- Не устанавливает Rust/toolchain автоматически.
|
||||
- Не устанавливает системные зависимости через apt.
|
||||
- Не создаёт production-конфиг автоматически.
|
||||
|
||||
## Использование
|
||||
|
||||
Из корня репозитория:
|
||||
## Default mode
|
||||
|
||||
```bash
|
||||
./tools/build.sh
|
||||
```
|
||||
|
||||
Опции:
|
||||
Дефолтный запуск **не изменяет систему**. Он:
|
||||
|
||||
- `--skip-fmt` — пропустить шаг `cargo fmt --check`.
|
||||
- `--install` — после успешной сборки установить бинарь и systemd unit.
|
||||
- проверяет prereqs;
|
||||
- запускает `fmt/clippy/test/build` в locked-режиме;
|
||||
- печатает `file`, `ldd`, `sha256` для собранного бинаря.
|
||||
|
||||
## Режим `--install`
|
||||
## Flags
|
||||
|
||||
`--install`:
|
||||
- `--prepare-build-env` — установить недостающие build-пакеты;
|
||||
- `--prepare-runtime-env` — установить недостающие runtime-пакеты;
|
||||
- `--bootstrap-rust` — установить rustup и pinned toolchain;
|
||||
- `--install` — установить бинарь + systemd unit (без enable/start);
|
||||
- `--enable` — `systemctl enable --now awg2-harness.service`;
|
||||
- `--yes` — подтверждение системных изменений (apt/rustup);
|
||||
- `--skip-fmt` — пропустить `cargo fmt --check`;
|
||||
- `--help` — справка.
|
||||
|
||||
1. Копирует бинарь в `/usr/local/bin/awg2-harness`.
|
||||
2. Проверяет, что `/etc/awg2-harness/config.toml` уже существует.
|
||||
3. Копирует [`awg2-harness.service`](awg2-harness.service).
|
||||
4. Выполняет `systemd-analyze verify` (если доступно).
|
||||
5. Выполняет `systemctl daemon-reload`.
|
||||
## Typical build machine flow
|
||||
|
||||
Важно:
|
||||
```bash
|
||||
./tools/build.sh --prepare-build-env --bootstrap-rust --yes
|
||||
./tools/build.sh
|
||||
```
|
||||
|
||||
- Если скрипт запущен от root, команды установки выполняются напрямую.
|
||||
- Если не от root — используется `sudo` (и проверяется его наличие).
|
||||
- Скрипт **не** выполняет `systemctl enable --now` автоматически.
|
||||
## Typical production host flow
|
||||
|
||||
Это intentional: включение сервиса и запуск остаются осознанным эксплуатационным шагом.
|
||||
```bash
|
||||
./tools/build.sh --prepare-runtime-env --yes
|
||||
install -d -m 0755 /etc/awg2-harness
|
||||
install -m 0644 config.toml /etc/awg2-harness/config.toml
|
||||
./tools/build.sh
|
||||
./tools/build.sh --install
|
||||
./tools/build.sh --enable
|
||||
```
|
||||
|
||||
## What the script intentionally does not do
|
||||
|
||||
- не устанавливает Docker автоматически;
|
||||
- не генерирует production config из example;
|
||||
- не включает сервис без явного `--enable`;
|
||||
- не управляет установкой AmneziaWG.
|
||||
|
||||
+218
-72
@@ -4,103 +4,249 @@ set -euo pipefail
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
CRATE_MANIFEST="$ROOT_DIR/traffic_core/Cargo.toml"
|
||||
TARGET_BIN="$ROOT_DIR/traffic_core/target/release/awg2-harness"
|
||||
MIN_RUSTC="1.85.0"
|
||||
RUST_TOOLCHAIN_FILE="$ROOT_DIR/rust-toolchain.toml"
|
||||
RUST_TOOLCHAIN_VERSION="1.95.0"
|
||||
|
||||
AUTO_INSTALL=false
|
||||
PREPARE_BUILD_ENV=false
|
||||
PREPARE_RUNTIME_ENV=false
|
||||
BOOTSTRAP_RUST=false
|
||||
INSTALL=false
|
||||
ENABLE=false
|
||||
YES=false
|
||||
SKIP_FMT=false
|
||||
|
||||
RUN_AS_ROOT=()
|
||||
|
||||
BUILD_PACKAGES=(
|
||||
ca-certificates
|
||||
curl
|
||||
build-essential
|
||||
pkg-config
|
||||
file
|
||||
shellcheck
|
||||
)
|
||||
|
||||
RUNTIME_PACKAGES=(
|
||||
iproute2
|
||||
wireguard-tools
|
||||
nftables
|
||||
kmod
|
||||
util-linux
|
||||
procps
|
||||
systemd
|
||||
)
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
./tools/build.sh
|
||||
./tools/build.sh --prepare-build-env --yes
|
||||
./tools/build.sh --prepare-runtime-env --yes
|
||||
./tools/build.sh --bootstrap-rust --yes
|
||||
./tools/build.sh --install
|
||||
./tools/build.sh --enable
|
||||
|
||||
Flags:
|
||||
--prepare-build-env Install missing build dependencies via apt
|
||||
--prepare-runtime-env Install missing runtime dependencies via apt
|
||||
--bootstrap-rust Install rustup/toolchain pinned by this repo
|
||||
--install Install binary and systemd unit (no enable/start)
|
||||
--enable Enable and start awg2-harness.service
|
||||
--yes Confirm system mutations (apt/rustup)
|
||||
--skip-fmt Skip cargo fmt --check
|
||||
--help Show this help
|
||||
EOF
|
||||
}
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--install) AUTO_INSTALL=true ;;
|
||||
--prepare-build-env) PREPARE_BUILD_ENV=true ;;
|
||||
--prepare-runtime-env) PREPARE_RUNTIME_ENV=true ;;
|
||||
--bootstrap-rust) BOOTSTRAP_RUST=true ;;
|
||||
--install) INSTALL=true ;;
|
||||
--enable) ENABLE=true ;;
|
||||
--yes) YES=true ;;
|
||||
--skip-fmt) SKIP_FMT=true ;;
|
||||
*) echo "Unknown arg: $arg"; exit 1 ;;
|
||||
--help|-h) usage; exit 0 ;;
|
||||
*) echo "Unknown arg: $arg"; usage; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || { echo "Missing command: $1"; exit 1; }
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "Missing command: $1"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
version_ge() {
|
||||
local have="$1"
|
||||
local need="$2"
|
||||
[[ "$(printf '%s\n' "$need" "$have" | sort -V | head -n1)" == "$need" ]]
|
||||
}
|
||||
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/os-release
|
||||
case "${ID:-}" in
|
||||
debian|ubuntu) ;;
|
||||
*) echo "Unsupported OS: ${ID:-unknown}. Only Debian/Ubuntu are supported."; exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
ARCH="$(uname -m)"
|
||||
if [[ "$ARCH" != "x86_64" && "$ARCH" != "amd64" ]]; then
|
||||
echo "Unsupported arch: $ARCH. Only amd64/x86_64 is supported."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v cargo >/dev/null 2>&1; then
|
||||
echo "cargo not found. Install rustup first: https://rustup.rs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
require_cmd rustc
|
||||
|
||||
RUSTC_VERSION="$(rustc --version | awk '{print $2}')"
|
||||
if ! version_ge "$RUSTC_VERSION" "$MIN_RUSTC"; then
|
||||
echo "rustc $RUSTC_VERSION is too old. Require >= $MIN_RUSTC"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for cmd in gcc pkg-config; do
|
||||
require_cmd "$cmd"
|
||||
done
|
||||
|
||||
if [[ "$SKIP_FMT" != true ]]; then
|
||||
cargo fmt --manifest-path "$CRATE_MANIFEST" --all --check
|
||||
fi
|
||||
|
||||
cargo clippy --locked --manifest-path "$CRATE_MANIFEST" --all-targets -- -D warnings
|
||||
cargo test --locked --manifest-path "$CRATE_MANIFEST" --release
|
||||
cargo build --locked --manifest-path "$CRATE_MANIFEST" --release
|
||||
|
||||
require_cmd file
|
||||
require_cmd ldd
|
||||
|
||||
file "$TARGET_BIN"
|
||||
ldd "$TARGET_BIN" || true
|
||||
"$TARGET_BIN" --help >/dev/null
|
||||
|
||||
sha256sum "$TARGET_BIN"
|
||||
ls -lh "$TARGET_BIN"
|
||||
|
||||
if [[ "$AUTO_INSTALL" == true ]]; then
|
||||
require_cmd install
|
||||
|
||||
RUN_AS_ROOT=( )
|
||||
setup_root_runner() {
|
||||
if [[ "$(id -u)" -eq 0 ]]; then
|
||||
RUN_AS_ROOT=( )
|
||||
RUN_AS_ROOT=()
|
||||
else
|
||||
require_cmd sudo
|
||||
RUN_AS_ROOT=(sudo)
|
||||
fi
|
||||
}
|
||||
|
||||
"${RUN_AS_ROOT[@]}" install -m 0755 "$TARGET_BIN" /usr/local/bin/awg2-harness
|
||||
"${RUN_AS_ROOT[@]}" mkdir -p /etc/awg2-harness
|
||||
if [[ ! -f /etc/awg2-harness/config.toml ]]; then
|
||||
echo "Missing /etc/awg2-harness/config.toml"
|
||||
echo "Refusing to install example config as production config."
|
||||
echo "Create config manually from $ROOT_DIR/config.example.toml and re-run with --install."
|
||||
ensure_supported_host() {
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/os-release
|
||||
case "${ID:-}" in
|
||||
debian|ubuntu) ;;
|
||||
*) echo "Unsupported OS: ${ID:-unknown}. Only Debian/Ubuntu are supported."; exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
local arch
|
||||
arch="$(uname -m)"
|
||||
if [[ "$arch" != "x86_64" && "$arch" != "amd64" ]]; then
|
||||
echo "Unsupported arch: $arch. Only amd64/x86_64 is supported."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
apt_install_missing() {
|
||||
local packages=("$@")
|
||||
local missing=()
|
||||
|
||||
require_cmd dpkg-query
|
||||
require_cmd apt-get
|
||||
|
||||
for pkg in "${packages[@]}"; do
|
||||
if ! dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null | grep -q "install ok installed"; then
|
||||
missing+=("$pkg")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "${#missing[@]}" -eq 0 ]]; then
|
||||
echo "All required packages already installed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Missing packages: ${missing[*]}"
|
||||
if [[ "$YES" != true ]]; then
|
||||
echo "Re-run with --yes to install them"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
setup_root_runner
|
||||
"${RUN_AS_ROOT[@]}" apt-get update
|
||||
"${RUN_AS_ROOT[@]}" apt-get install -y --no-install-recommends "${missing[@]}"
|
||||
}
|
||||
|
||||
bootstrap_rust() {
|
||||
require_cmd curl
|
||||
|
||||
if [[ "$YES" != true ]]; then
|
||||
echo "This will install rustup and Rust toolchain $RUST_TOOLCHAIN_VERSION"
|
||||
echo "Re-run with --yes to proceed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v rustup >/dev/null 2>&1; then
|
||||
local rustup_script
|
||||
rustup_script="$(mktemp)"
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o "$rustup_script"
|
||||
sh "$rustup_script" -y --profile minimal --default-toolchain "$RUST_TOOLCHAIN_VERSION"
|
||||
rm -f "$rustup_script"
|
||||
fi
|
||||
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
require_cmd rustup
|
||||
rustup toolchain install "$RUST_TOOLCHAIN_VERSION" --profile minimal --component rustfmt --component clippy
|
||||
rustup component add rustfmt clippy --toolchain "$RUST_TOOLCHAIN_VERSION"
|
||||
rustc --version
|
||||
}
|
||||
|
||||
prepare_build_gate() {
|
||||
require_cmd cargo
|
||||
require_cmd rustc
|
||||
require_cmd gcc
|
||||
require_cmd pkg-config
|
||||
require_cmd file
|
||||
require_cmd ldd
|
||||
|
||||
if [[ ! -f "$RUST_TOOLCHAIN_FILE" ]]; then
|
||||
echo "Missing rust toolchain pin file: $RUST_TOOLCHAIN_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$ROOT_DIR/traffic_core/Cargo.lock" ]]; then
|
||||
echo "Missing lockfile: $ROOT_DIR/traffic_core/Cargo.lock"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SKIP_FMT" != true ]]; then
|
||||
cargo fmt --manifest-path "$CRATE_MANIFEST" --all --check
|
||||
fi
|
||||
|
||||
cargo clippy --locked --manifest-path "$CRATE_MANIFEST" --all-targets -- -D warnings
|
||||
cargo test --locked --manifest-path "$CRATE_MANIFEST" --release
|
||||
cargo build --locked --manifest-path "$CRATE_MANIFEST" --release
|
||||
|
||||
file "$TARGET_BIN"
|
||||
ldd "$TARGET_BIN" || true
|
||||
"$TARGET_BIN" --help >/dev/null
|
||||
sha256sum "$TARGET_BIN"
|
||||
ls -lh "$TARGET_BIN"
|
||||
}
|
||||
|
||||
install_artifacts() {
|
||||
require_cmd install
|
||||
require_cmd systemctl
|
||||
|
||||
if [[ ! -f "$TARGET_BIN" ]]; then
|
||||
echo "Binary not found: $TARGET_BIN"
|
||||
echo "Run build first: ./tools/build.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f /etc/awg2-harness/config.toml ]]; then
|
||||
echo "Missing /etc/awg2-harness/config.toml"
|
||||
echo "Refusing to install example config as production config"
|
||||
echo "Create config manually from $ROOT_DIR/config.example.toml and re-run with --install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
setup_root_runner
|
||||
"${RUN_AS_ROOT[@]}" install -m 0755 "$TARGET_BIN" /usr/local/bin/awg2-harness
|
||||
"${RUN_AS_ROOT[@]}" install -m 0644 "$ROOT_DIR/awg2-harness.service" /etc/systemd/system/awg2-harness.service
|
||||
|
||||
if command -v systemd-analyze >/dev/null 2>&1; then
|
||||
"${RUN_AS_ROOT[@]}" systemd-analyze verify /etc/systemd/system/awg2-harness.service
|
||||
fi
|
||||
"${RUN_AS_ROOT[@]}" systemctl daemon-reload
|
||||
}
|
||||
|
||||
enable_service() {
|
||||
require_cmd systemctl
|
||||
setup_root_runner
|
||||
"${RUN_AS_ROOT[@]}" systemctl enable --now awg2-harness.service
|
||||
}
|
||||
|
||||
ensure_supported_host
|
||||
|
||||
if [[ "$PREPARE_BUILD_ENV" == true ]]; then
|
||||
apt_install_missing "${BUILD_PACKAGES[@]}"
|
||||
fi
|
||||
|
||||
if [[ "$PREPARE_RUNTIME_ENV" == true ]]; then
|
||||
apt_install_missing "${RUNTIME_PACKAGES[@]}"
|
||||
fi
|
||||
|
||||
if [[ "$BOOTSTRAP_RUST" == true ]]; then
|
||||
bootstrap_rust
|
||||
fi
|
||||
|
||||
prepare_build_gate
|
||||
|
||||
if [[ "$INSTALL" == true ]]; then
|
||||
install_artifacts
|
||||
fi
|
||||
|
||||
if [[ "$ENABLE" == true ]]; then
|
||||
enable_service
|
||||
fi
|
||||
|
||||
echo "Build completed: $TARGET_BIN"
|
||||
|
||||
Reference in New Issue
Block a user