LocalAuthority / scripts / deploy_to_jumper.sh
1 contributor
132 lines | 3.802kb
#!/usr/bin/env bash
# Deploy Madagascar Local Authority application code to jumper.

set -euo pipefail

TARGET_HOST="${TARGET_HOST:-jumper.madagascar.xdev.ro}"
TARGET_DIR="${TARGET_DIR:-/usr/local/xdev-host-manager}"
RESTART=1
ALLOW_DIRTY=0
DRY_RUN=0
INCLUDE_CONFIG=0

usage() {
    cat <<EOF
Usage: $0 [--target host] [--target-dir path] [--no-restart] [--allow-dirty] [--dry-run] [--include-config]

Deploys application code/docs to jumper. Runtime registry data in config/ is not
deployed unless --include-config is explicit.

Environment:
  TARGET_HOST   Default: jumper.madagascar.xdev.ro
  TARGET_DIR    Default: /usr/local/xdev-host-manager
EOF
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        --target)
            TARGET_HOST="$2"
            shift 2
            ;;
        --target-dir)
            TARGET_DIR="$2"
            shift 2
            ;;
        --no-restart)
            RESTART=0
            shift
            ;;
        --allow-dirty)
            ALLOW_DIRTY=1
            shift
            ;;
        --dry-run)
            DRY_RUN=1
            shift
            ;;
        --include-config)
            INCLUDE_CONFIG=1
            shift
            ;;
        --help|-h)
            usage
            exit 0
            ;;
        *)
            echo "Unknown option: $1" >&2
            usage >&2
            exit 2
            ;;
    esac
done

cd "$(dirname "$0")/.."

if [[ "$ALLOW_DIRTY" -ne 1 ]] && [[ -n "$(git status --porcelain)" ]]; then
    echo "Working tree is dirty; commit first or pass --allow-dirty." >&2
    git status --short >&2
    exit 1
fi

command -v rsync >/dev/null 2>&1 || {
    echo "rsync is required for deployment." >&2
    exit 1
}
ssh "$TARGET_HOST" "command -v rsync >/dev/null 2>&1" || {
    echo "rsync is required on $TARGET_HOST." >&2
    exit 1
}

perl -c scripts/host_manager.pl >/dev/null
perl -c scripts/mdns_host_seed.pl >/dev/null
BUILD_REVISION="${BUILD_REVISION:-$(git rev-parse --short=12 HEAD)}"
BUILD_BRANCH="${BUILD_BRANCH:-$(git rev-parse --abbrev-ref HEAD)}"
if [[ -z "${BUILD_DIRTY+x}" ]]; then
    BUILD_DIRTY=0
    if [[ -n "$(git status --porcelain)" ]]; then
        BUILD_DIRTY=1
    fi
fi
BUILD_DEPLOYED_AT="${BUILD_DEPLOYED_AT:-$(date -u '+%Y-%m-%dT%H:%M:%SZ')}"

rsync_args=(-az --delete)
if [[ "$DRY_RUN" -eq 1 ]]; then
    rsync_args+=(--dry-run --itemize-changes)
fi

ssh "$TARGET_HOST" "mkdir -p '$TARGET_DIR/scripts' '$TARGET_DIR/deploy' '$TARGET_DIR/.doc' '$TARGET_DIR/var'"
ssh "$TARGET_HOST" "sudo -n install -d -o host-manager -g host-manager -m 0755 '$TARGET_DIR/var' '$TARGET_DIR/backups'"
rsync "${rsync_args[@]}" scripts/ "$TARGET_HOST:$TARGET_DIR/scripts/"
rsync "${rsync_args[@]}" deploy/ "$TARGET_HOST:$TARGET_DIR/deploy/"
rsync "${rsync_args[@]}" .doc/ "$TARGET_HOST:$TARGET_DIR/.doc/"
rsync "${rsync_args[@]}" README.md "$TARGET_HOST:$TARGET_DIR/README.md"

if [[ "$INCLUDE_CONFIG" -eq 1 ]]; then
    ssh "$TARGET_HOST" "mkdir -p '$TARGET_DIR/config'"
    rsync "${rsync_args[@]}" config/ "$TARGET_HOST:$TARGET_DIR/config/"
fi

if [[ "$DRY_RUN" -eq 1 ]]; then
    exit 0
fi

printf 'revision=%s\nbranch=%s\ndirty=%s\ndeployed_at=%s\n' \
    "$BUILD_REVISION" "$BUILD_BRANCH" "$BUILD_DIRTY" "$BUILD_DEPLOYED_AT" |
    ssh "$TARGET_HOST" "cat > '$TARGET_DIR/BUILD'"

ssh "$TARGET_HOST" "cd '$TARGET_DIR' && perl -c scripts/host_manager.pl >/dev/null && perl -c scripts/mdns_host_seed.pl >/dev/null"

if [[ "$RESTART" -eq 1 ]]; then
    ssh "$TARGET_HOST" "sudo -n systemctl restart host-manager"
fi

ssh "$TARGET_HOST" "for attempt in {1..20}; do
    if systemctl is-active host-manager >/dev/null && curl -fsS http://127.0.0.1:8088/healthz >/dev/null; then
        exit 0
    fi
    sleep 0.5
done
systemctl status host-manager --no-pager
exit 1"
echo "Deployed to $TARGET_HOST:$TARGET_DIR"