init deploy.sh
This commit is contained in:
1 parent
7ccf9e1bc3
commit
c23836e5fe
2 files changed
+184
No files matched your search
@@ -23,3 +23,8 @@ ELASTIC_PASSWORD=
|
||||
# --- Backend ---
|
||||
# Keycloak client id (resource) the bearer-only backend expects.
|
||||
KEYCLOAK_RESOURCE=
|
||||
|
||||
# --- Gitea registry (used by deploy.sh to download config.tar.gz) ---
|
||||
# User + access token with package read scope for gitea.tail276105.ts.net.
|
||||
GITEA_USER=
|
||||
GITEA_TOKEN=
|
||||
Executable
+179
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Boxit/Remsly prod deployment helper.
|
||||
#
|
||||
# One script, two modes:
|
||||
# * Bootstrap (`deploy <version>`): downloads config-<version>.tar.gz from the
|
||||
# Gitea generic package registry into ./config, extracts it to a staging dir
|
||||
# and re-executes the deploy.sh *from the tarball* in install mode. The install
|
||||
# logic therefore always comes from the deployed version (self-updating), which
|
||||
# is what lets a release carry its own migration/special steps.
|
||||
# * Install (`__install`, internal): syncs the staged config into the deploy
|
||||
# directory (never touching .env or ./config) and runs docker compose.
|
||||
#
|
||||
# The deploy directory is the folder this script lives in; it also holds .env
|
||||
# (secrets, host-only) and docker-compose.yml. Ship this script once to the host,
|
||||
# afterwards every deploy refreshes it from the tarball.
|
||||
#
|
||||
# Usage:
|
||||
# ./deploy.sh <version> deploy a specific version (e.g. 2026.07-A0-6)
|
||||
# ./deploy.sh deploy <version> same, explicit
|
||||
# ./deploy.sh list-remote [n] list the last n versions in the registry (default 10)
|
||||
# ./deploy.sh list-local list downloaded config archives
|
||||
# ./deploy.sh help
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
# --- Constants ---------------------------------------------------------------
|
||||
GITEA_HOST="gitea.tail276105.ts.net"
|
||||
OWNER="remsly"
|
||||
PKG="prod-config"
|
||||
|
||||
DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONFIG_DIR="${DEPLOY_DIR}/config"
|
||||
INSTALLED_FILE="${DEPLOY_DIR}/.installed-version"
|
||||
|
||||
# --- Helpers -----------------------------------------------------------------
|
||||
die() { echo "ERROR: $*" >&2; exit 1; }
|
||||
|
||||
# Read a single key from .env without sourcing it (values are unquoted KEY=value).
|
||||
read_env() {
|
||||
local key="$1" val
|
||||
[ -f "${DEPLOY_DIR}/.env" ] || return 1
|
||||
val="$(grep -E "^${key}=" "${DEPLOY_DIR}/.env" | head -n1 | cut -d= -f2-)" || return 1
|
||||
# strip trailing CR (CRLF files) and surrounding quotes
|
||||
val="${val%$'\r'}"; val="${val%\"}"; val="${val#\"}"; val="${val%\'}"; val="${val#\'}"
|
||||
printf '%s' "$val"
|
||||
}
|
||||
|
||||
# Basic-auth curl against Gitea, using GITEA_USER/GITEA_TOKEN from .env.
|
||||
gitea_curl() {
|
||||
local user token
|
||||
user="$(read_env GITEA_USER || true)"
|
||||
token="$(read_env GITEA_TOKEN || true)"
|
||||
[ -n "$user" ] && [ -n "$token" ] || die "GITEA_USER/GITEA_TOKEN missing in ${DEPLOY_DIR}/.env"
|
||||
curl -fsSL --user "${user}:${token}" "$@"
|
||||
}
|
||||
|
||||
# Resolve the docker compose command (v2 plugin preferred, v1 fallback).
|
||||
compose() {
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
docker compose "$@"
|
||||
elif command -v docker-compose >/dev/null 2>&1; then
|
||||
docker-compose "$@"
|
||||
else
|
||||
die "neither 'docker compose' nor 'docker-compose' found"
|
||||
fi
|
||||
}
|
||||
|
||||
tarball_url() { printf 'https://%s/api/packages/%s/generic/%s/%s/config.tar.gz' "$GITEA_HOST" "$OWNER" "$PKG" "$1"; }
|
||||
|
||||
# --- Commands ----------------------------------------------------------------
|
||||
cmd_list_remote() {
|
||||
local n="${1:-10}"
|
||||
echo "Last ${n} remote version(s) of ${PKG}:"
|
||||
gitea_curl "https://${GITEA_HOST}/api/v1/packages/${OWNER}?type=generic&q=${PKG}" \
|
||||
| grep -o '"version":"[^"]*"' | cut -d'"' -f4 \
|
||||
| sort -Vr | head -n "$n" \
|
||||
| sed 's/^/ /'
|
||||
}
|
||||
|
||||
cmd_list_local() {
|
||||
local current="" f v
|
||||
[ -f "$INSTALLED_FILE" ] && current="$(cat "$INSTALLED_FILE")"
|
||||
echo "Local config archives in ${CONFIG_DIR}:"
|
||||
if ! ls "${CONFIG_DIR}"/config-*.tar.gz >/dev/null 2>&1; then
|
||||
echo " (none)"
|
||||
return 0
|
||||
fi
|
||||
for f in "${CONFIG_DIR}"/config-*.tar.gz; do
|
||||
v="$(basename "$f")"; v="${v#config-}"; v="${v%.tar.gz}"
|
||||
if [ "$v" = "$current" ]; then
|
||||
echo " ${v} <- installed"
|
||||
else
|
||||
echo " ${v}"
|
||||
fi
|
||||
done | sort -Vr
|
||||
}
|
||||
|
||||
cmd_deploy() {
|
||||
local version="${1:-}"
|
||||
[ -n "$version" ] || die "version required (e.g. ${0##*/} 2026.07-A0-6)"
|
||||
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
local archive="${CONFIG_DIR}/config-${version}.tar.gz"
|
||||
if [ -f "$archive" ]; then
|
||||
echo "Using cached ${archive}"
|
||||
else
|
||||
echo "Downloading ${version} ..."
|
||||
gitea_curl -o "$archive" "$(tarball_url "$version")" \
|
||||
|| { rm -f "$archive"; die "download of ${version} failed"; }
|
||||
fi
|
||||
|
||||
local stage
|
||||
stage="$(mktemp -d)"
|
||||
tar -xzf "$archive" -C "$stage"
|
||||
[ -f "${stage}/deploy.sh" ] || die "tarball has no deploy.sh"
|
||||
|
||||
# Hand off to the deploy.sh shipped in this version (self-updating install logic).
|
||||
# The running host copy is not overwritten because we exec the staged copy.
|
||||
exec bash "${stage}/deploy.sh" __install "$version" "$DEPLOY_DIR" "$stage"
|
||||
}
|
||||
|
||||
cmd_install() {
|
||||
local version="$1" deploydir="$2" stage="$3"
|
||||
echo "Installing ${version} into ${deploydir} ..."
|
||||
|
||||
# Sync staged config into the deploy dir; never clobber secrets or downloads.
|
||||
if command -v rsync >/dev/null 2>&1; then
|
||||
rsync -a --exclude='.env' --exclude='config/' "${stage}/" "${deploydir}/"
|
||||
else
|
||||
# cp fallback: copy everything except .env / config (tarball has neither, but be safe)
|
||||
( cd "$stage" && find . -mindepth 1 -maxdepth 1 \
|
||||
! -name '.env' ! -name 'config' \
|
||||
-exec cp -a {} "${deploydir}/" \; )
|
||||
fi
|
||||
|
||||
( cd "$deploydir" && compose pull && compose up -d )
|
||||
|
||||
# Optional per-version migration/special-task hook shipped inside the tarball.
|
||||
if [ -f "${deploydir}/post-deploy.sh" ]; then
|
||||
echo "Running post-deploy.sh hook ..."
|
||||
bash "${deploydir}/post-deploy.sh" "$version"
|
||||
fi
|
||||
|
||||
printf '%s\n' "$version" > "${deploydir}/.installed-version"
|
||||
rm -rf "$stage"
|
||||
echo "Deployed ${version}."
|
||||
}
|
||||
|
||||
usage() {
|
||||
local me="${0##*/}"
|
||||
cat <<EOF
|
||||
${me} - Boxit/Remsly prod deployment helper
|
||||
|
||||
Usage:
|
||||
${me} <version> deploy a specific version (e.g. 2026.07-A0-6)
|
||||
${me} deploy <version> same, explicit
|
||||
${me} list-remote [n] list the last n versions in the registry (default 10)
|
||||
${me} list-local list downloaded config archives under ./config
|
||||
${me} help
|
||||
|
||||
Requires GITEA_USER/GITEA_TOKEN in ./.env for registry access.
|
||||
EOF
|
||||
}
|
||||
|
||||
# --- Dispatch ----------------------------------------------------------------
|
||||
main() {
|
||||
local cmd="${1:-help}"
|
||||
case "$cmd" in
|
||||
list-remote) shift; cmd_list_remote "$@" ;;
|
||||
list-local) cmd_list_local ;;
|
||||
deploy) shift; cmd_deploy "$@" ;;
|
||||
__install) shift; cmd_install "$@" ;;
|
||||
help|-h|--help) usage ;;
|
||||
*) cmd_deploy "$cmd" ;; # bare version shorthand
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||