Some checks failed
Run Check Script / check (pull_request) Failing after -42s
193 lines
7.0 KiB
Bash
Executable File
193 lines
7.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Publish Fleet operator, NATS callout, and fleet-agent images.
|
|
Does not provision a tenant and does not patch Devices.
|
|
|
|
Usage:
|
|
fleet/scripts/release.sh [options]
|
|
|
|
At least one release version is required:
|
|
--control-version VERSION Operator and NATS callout version
|
|
--agent-version VERSION Standalone fleet-agent version
|
|
--agent-arch ARCH x86_64 (default) or aarch64
|
|
|
|
Registry:
|
|
--registry HOST Default: hub.nationtech.io
|
|
--repository PATH Default: harmony
|
|
|
|
--publish-only Accepted; this script only publishes
|
|
-h, --help
|
|
|
|
HARMONY_ZITADEL_KEY_JSON: Fleet bot → OpenBao harmony/harmony-fleet
|
|
RegistryCredentials. Fallback: REGISTRY_USER / REGISTRY_TOKEN.
|
|
|
|
Tenant provision and device upgrades: docs/guides/fleet-products.md
|
|
EOF
|
|
}
|
|
|
|
fail() {
|
|
printf 'error: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
require_command() {
|
|
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
|
|
}
|
|
|
|
validate_version() {
|
|
[[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]] ||
|
|
fail "version must be SemVer without a leading v or build metadata: $1"
|
|
}
|
|
|
|
# The on-device updater runs `<candidate> --self-test --expected-version <tag>`.
|
|
# The agent exits 1 if VERSION (from HARMONY_FLEET_AGENT_VERSION via build.rs)
|
|
# does not match. Publishing a binary with the workspace crate version baked in
|
|
# is how 0.6.7 sat on the Pi as a failed upgrade. Prefer `--version` when we
|
|
# can run the binary; if this host cannot execute aarch64, search the image
|
|
# bytes (do not `strings | grep -q` under `pipefail` — grep -q SIGPIPEs).
|
|
assert_agent_version() {
|
|
local binary="$1"
|
|
local version="$2"
|
|
local reported
|
|
if [[ "$(uname -m)" == "x86_64" && "$agent_arch" == "x86_64" ]]; then
|
|
reported="$("$binary" --version)"
|
|
[[ "${reported##* }" == "$version" ]] ||
|
|
fail "built agent reports the wrong version: $reported"
|
|
elif command -v qemu-aarch64 >/dev/null 2>&1 && [[ "$agent_arch" == "aarch64" ]]; then
|
|
reported="$(qemu-aarch64 "$binary" --version)"
|
|
[[ "${reported##* }" == "$version" ]] ||
|
|
fail "built agent reports the wrong version: $reported"
|
|
else
|
|
require_command python3
|
|
python3 - "$binary" "$version" <<'PY' || fail "cross-built agent does not contain version $version"
|
|
import re, sys
|
|
data = open(sys.argv[1], "rb").read()
|
|
version = sys.argv[2].encode()
|
|
if not re.search(rb"(?<![0-9])" + re.escape(version) + rb"(?![0-9])", data):
|
|
sys.exit(1)
|
|
PY
|
|
fi
|
|
}
|
|
|
|
digest_line() {
|
|
local key="$1"
|
|
local file="$2"
|
|
local matches
|
|
matches="$(grep -E "^${key}=(oci://)?hub\\.nationtech\\.io/harmony/[^[:space:]]+@sha256:[0-9a-f]{64}$" "$file" || true)"
|
|
[[ "$(printf '%s\n' "$matches" | grep -c .)" -eq 1 ]] ||
|
|
fail "expected one ${key}= digest line in release output"
|
|
printf '%s\n' "${matches#*=}"
|
|
}
|
|
|
|
control_version="${CONTROL_VERSION:-}"
|
|
agent_version="${AGENT_VERSION:-}"
|
|
agent_arch="${AGENT_ARCH:-x86_64}"
|
|
registry="${FLEET_REGISTRY:-hub.nationtech.io}"
|
|
repository="${FLEET_REGISTRY_REPOSITORY:-harmony}"
|
|
|
|
while (($#)); do
|
|
case "$1" in
|
|
--control-version) control_version="${2:?missing control version}"; shift 2 ;;
|
|
--agent-version) agent_version="${2:?missing agent version}"; shift 2 ;;
|
|
--agent-arch) agent_arch="${2:?missing agent architecture}"; shift 2 ;;
|
|
--registry) registry="${2:?missing registry}"; shift 2 ;;
|
|
--repository) repository="${2:?missing repository}"; shift 2 ;;
|
|
--publish-only) shift ;;
|
|
--deploy-manifest|--deploy-bin|--context|--namespace|--device|--kube-context)
|
|
fail "release.sh does not provision or operate a tenant; see docs/guides/fleet-products.md"
|
|
;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) fail "unknown argument: $1" ;;
|
|
esac
|
|
done
|
|
|
|
[[ -n "$control_version" || -n "$agent_version" ]] || fail "set a control or agent version"
|
|
[[ -z "$control_version" ]] || validate_version "$control_version"
|
|
[[ -z "$agent_version" ]] || validate_version "$agent_version"
|
|
[[ "$agent_arch" == "x86_64" || "$agent_arch" == "aarch64" ]] ||
|
|
fail "agent architecture must be x86_64 or aarch64"
|
|
if [[ "$registry" != "hub.nationtech.io" || "$repository" != "harmony" ]]; then
|
|
fail "Fleet releases publish to hub.nationtech.io/harmony"
|
|
fi
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd "$script_dir/../.." && pwd)"
|
|
cd "$repo_root"
|
|
|
|
require_command cargo
|
|
require_command sha256sum
|
|
require_command stat
|
|
[[ -z "$control_version" ]] || require_command docker
|
|
|
|
if [[ -z "${HARMONY_ZITADEL_KEY_JSON:-}" ]]; then
|
|
: "${REGISTRY_USER:?REGISTRY_USER is required for publication}"
|
|
: "${REGISTRY_TOKEN:?REGISTRY_TOKEN is required for publication}"
|
|
fi
|
|
|
|
tmp="$(mktemp -d)"
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
|
|
agent_binary=""
|
|
agent_size=""
|
|
agent_sha256=""
|
|
agent_tag_ref=""
|
|
agent_oci_ref=""
|
|
|
|
if [[ -n "$agent_version" ]]; then
|
|
printf '==> Building fleet agent %s for %s\n' "$agent_version" "$agent_arch"
|
|
export HARMONY_FLEET_AGENT_VERSION="$agent_version"
|
|
if [[ "$agent_arch" == "x86_64" ]]; then
|
|
[[ "$(uname -m)" == "x86_64" ]] || fail "x86_64 agent build requires an x86_64 host"
|
|
cargo build --release --locked -p harmony-fleet-agent
|
|
agent_binary="$repo_root/target/release/harmony-fleet-agent"
|
|
else
|
|
require_command rustup
|
|
rustup target add aarch64-unknown-linux-gnu
|
|
cargo build --release --locked --target aarch64-unknown-linux-gnu \
|
|
-p harmony-fleet-agent
|
|
agent_binary="$repo_root/target/aarch64-unknown-linux-gnu/release/harmony-fleet-agent"
|
|
fi
|
|
[[ -x "$agent_binary" ]] || fail "agent binary not produced: $agent_binary"
|
|
assert_agent_version "$agent_binary" "$agent_version"
|
|
agent_size="$(stat -c %s "$agent_binary")"
|
|
agent_sha256="$(sha256sum "$agent_binary" | cut -d' ' -f1)"
|
|
agent_tag_ref="$registry/$repository/harmony-fleet-agent:$agent_version-$agent_arch"
|
|
fi
|
|
|
|
operator_ref=""
|
|
callout_ref=""
|
|
if [[ -n "$agent_version" ]]; then
|
|
printf '==> Publishing %s\n' "$agent_tag_ref"
|
|
agent_refs="$tmp/agent-refs"
|
|
RUST_LOG="${RUST_LOG:-info}" \
|
|
cargo run --release -p harmony-fleet-deploy --bin harmony-fleet-release -- \
|
|
agent --binary "$agent_binary" --reference "$agent_tag_ref" \
|
|
--version "$agent_version" >"$agent_refs"
|
|
cat "$agent_refs"
|
|
agent_oci_ref="$(digest_line agent "$agent_refs")"
|
|
fi
|
|
|
|
if [[ -n "$control_version" ]]; then
|
|
printf '==> Resolving or publishing Fleet control plane %s\n' "$control_version"
|
|
control_refs="$tmp/control-refs"
|
|
RUST_LOG="${RUST_LOG:-info}" \
|
|
cargo run --release -p harmony-fleet-deploy --bin harmony-fleet-release -- \
|
|
control --version "$control_version" --push >"$control_refs"
|
|
cat "$control_refs"
|
|
operator_ref="$(digest_line operator "$control_refs")"
|
|
callout_ref="$(digest_line callout "$control_refs")"
|
|
fi
|
|
|
|
printf '\nRelease outputs:\n'
|
|
[[ -z "$operator_ref" ]] || printf ' operator=%s\n callout=%s\n' "$operator_ref" "$callout_ref"
|
|
if [[ -n "$agent_oci_ref" ]]; then
|
|
printf ' agent.version=%s\n' "$agent_version"
|
|
printf ' agent.architecture=%s\n' "$agent_arch"
|
|
printf ' agent.artifactUrl=%s\n' "$agent_oci_ref"
|
|
printf ' agent.maxBytes=%s\n' "$agent_size"
|
|
printf ' agent.sha256=%s\n' "$agent_sha256"
|
|
fi
|