211 lines
5.6 KiB
Bash
211 lines
5.6 KiB
Bash
#!/usr/bin/env sh
|
|
set -eu
|
|
|
|
RELEASE_VERSION="${RELEASE_VERSION:-20260518-7b32b21-11}"
|
|
BASE_URL="${BASE_URL:-http://10.8.0.1/ai_deploy}"
|
|
BUNDLE_NAME="${BUNDLE_NAME:-managed-portal-${RELEASE_VERSION}.zip}"
|
|
INSTALL_ROOT="${INSTALL_ROOT:-/opt/managed-portal-releases}"
|
|
TARGET_DIR="${TARGET_DIR:-${INSTALL_ROOT}/managed-portal-${RELEASE_VERSION}}"
|
|
SHARED_ROOT="${SHARED_ROOT:-${INSTALL_ROOT}/shared}"
|
|
DEFAULT_PEOPLE_FLOW_WEIGHTS_DIR="${SHARED_ROOT}/people_flow_project/weights"
|
|
|
|
require_command() {
|
|
if ! command -v "$1" >/dev/null 2>&1; then
|
|
echo "missing required command: $1" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
pull_or_use_local() {
|
|
image="$1"
|
|
|
|
if docker pull "$image"; then
|
|
return 0
|
|
fi
|
|
|
|
echo "docker pull failed for $image, checking local image cache" >&2
|
|
if docker image inspect "$image" >/dev/null 2>&1; then
|
|
echo "using existing local image $image" >&2
|
|
return 0
|
|
fi
|
|
|
|
echo "image unavailable locally after pull failure: $image" >&2
|
|
exit 1
|
|
}
|
|
|
|
run_compose() {
|
|
if command -v docker-compose >/dev/null 2>&1; then
|
|
docker-compose "$@"
|
|
return 0
|
|
fi
|
|
docker compose "$@"
|
|
}
|
|
|
|
dir_has_files() {
|
|
directory="$1"
|
|
[ -d "$directory" ] && [ -n "$(find "$directory" -mindepth 1 -print -quit 2>/dev/null)" ]
|
|
}
|
|
|
|
copy_dir_contents() {
|
|
source_dir="$1"
|
|
target_dir="$2"
|
|
|
|
mkdir -p "$target_dir"
|
|
cp -R "$source_dir"/. "$target_dir"/
|
|
}
|
|
|
|
download_bundle() {
|
|
tmp_dir="$1"
|
|
bundle_zip="$tmp_dir/$BUNDLE_NAME"
|
|
bundle_url="${BASE_URL%/}/$BUNDLE_NAME"
|
|
|
|
echo "downloading $bundle_url" >&2
|
|
curl -fL "$bundle_url" -o "$bundle_zip"
|
|
echo "$bundle_zip"
|
|
}
|
|
|
|
build_overlay_image() {
|
|
overlay_name="$1"
|
|
base_image="$2"
|
|
overlay_root="$3"
|
|
overlay_image="$4"
|
|
overlay_context="$(dirname "$overlay_root")"
|
|
|
|
if [ ! -d "$overlay_root" ]; then
|
|
printf '%s\n' "$base_image"
|
|
return 0
|
|
fi
|
|
|
|
if [ -z "$(find "$overlay_root" -mindepth 1 -print -quit)" ]; then
|
|
printf '%s\n' "$base_image"
|
|
return 0
|
|
fi
|
|
|
|
echo "building runtime overlay for $overlay_name" >&2
|
|
docker build \
|
|
-f "$TARGET_DIR/deploy/Dockerfile.runtime-overlay" \
|
|
--build-arg "BASE_IMAGE=$base_image" \
|
|
-t "$overlay_image" \
|
|
"$overlay_context" >/dev/null
|
|
printf '%s\n' "$overlay_image"
|
|
}
|
|
|
|
clear_stale_runtime_state() {
|
|
people_flow_status="$TARGET_DIR/managed/people_flow_project/outputs/rtsp_stream/worker_status.json"
|
|
|
|
if [ -f "$people_flow_status" ]; then
|
|
rm -f "$people_flow_status"
|
|
fi
|
|
}
|
|
|
|
ensure_runtime_directories() {
|
|
mkdir -p \
|
|
"$TARGET_DIR/managed/store_dwell_alert/config" \
|
|
"$TARGET_DIR/managed/store_dwell_alert/data" \
|
|
"$TARGET_DIR/managed/people_flow_project/config" \
|
|
"$TARGET_DIR/managed/people_flow_project/outputs/rtsp_stream"
|
|
}
|
|
|
|
find_existing_people_flow_weights() {
|
|
if dir_has_files "$MANAGED_PEOPLE_FLOW_WEIGHTS_DIR"; then
|
|
printf '%s\n' "$MANAGED_PEOPLE_FLOW_WEIGHTS_DIR"
|
|
return 0
|
|
fi
|
|
|
|
for candidate in "$INSTALL_ROOT"/managed-portal-*/managed/people_flow_project/weights; do
|
|
if [ "$candidate" = "$TARGET_DIR/managed/people_flow_project/weights" ]; then
|
|
continue
|
|
fi
|
|
|
|
if dir_has_files "$candidate"; then
|
|
printf '%s\n' "$candidate"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
prepare_people_flow_weights() {
|
|
bundle_weights_dir="$TARGET_DIR/managed/people_flow_project/weights"
|
|
source_weights_dir=""
|
|
|
|
if dir_has_files "$bundle_weights_dir"; then
|
|
source_weights_dir="$bundle_weights_dir"
|
|
echo "seeding shared people-flow weights from bundle" >&2
|
|
elif source_weights_dir="$(find_existing_people_flow_weights 2>/dev/null)"; then
|
|
echo "reusing existing people-flow weights from $source_weights_dir" >&2
|
|
else
|
|
echo "people-flow weights not found; seed $MANAGED_PEOPLE_FLOW_WEIGHTS_DIR or include managed/people_flow_project/weights in the release zip" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$source_weights_dir" != "$MANAGED_PEOPLE_FLOW_WEIGHTS_DIR" ]; then
|
|
rm -rf "$MANAGED_PEOPLE_FLOW_WEIGHTS_DIR"
|
|
copy_dir_contents "$source_weights_dir" "$MANAGED_PEOPLE_FLOW_WEIGHTS_DIR"
|
|
fi
|
|
|
|
rm -rf "$bundle_weights_dir"
|
|
mkdir -p "$(dirname "$bundle_weights_dir")"
|
|
ln -s "$MANAGED_PEOPLE_FLOW_WEIGHTS_DIR" "$bundle_weights_dir"
|
|
}
|
|
|
|
require_command curl
|
|
require_command unzip
|
|
require_command docker
|
|
|
|
tmp_dir="$(mktemp -d)"
|
|
trap 'rm -rf "$tmp_dir"' EXIT INT TERM
|
|
|
|
mkdir -p "$INSTALL_ROOT"
|
|
bundle_zip="$(download_bundle "$tmp_dir")"
|
|
rm -rf "$TARGET_DIR"
|
|
unzip -oq "$bundle_zip" -d "$INSTALL_ROOT"
|
|
|
|
if [ ! -f "$TARGET_DIR/release-manifest.env" ]; then
|
|
echo "release-manifest.env not found in $TARGET_DIR" >&2
|
|
exit 1
|
|
fi
|
|
|
|
set -a
|
|
. "$TARGET_DIR/release-manifest.env"
|
|
set +a
|
|
|
|
MANAGED_PEOPLE_FLOW_WEIGHTS_DIR="${MANAGED_PEOPLE_FLOW_WEIGHTS_DIR:-$DEFAULT_PEOPLE_FLOW_WEIGHTS_DIR}"
|
|
|
|
ensure_runtime_directories
|
|
prepare_people_flow_weights
|
|
|
|
clear_stale_runtime_state
|
|
|
|
echo "pulling release images"
|
|
pull_or_use_local "$MANAGED_PORTAL_IMAGE"
|
|
pull_or_use_local "$MANAGED_PORTAL_WEB_IMAGE"
|
|
pull_or_use_local "$PEOPLE_FLOW_PROJECT_IMAGE"
|
|
pull_or_use_local "$STORE_DWELL_ALERT_IMAGE"
|
|
|
|
PEOPLE_FLOW_PROJECT_IMAGE="$(build_overlay_image \
|
|
people-flow-project \
|
|
"$PEOPLE_FLOW_PROJECT_IMAGE" \
|
|
"$TARGET_DIR/runtime-overlays/people-flow-project/rootfs" \
|
|
"managed-portal-runtime/people-flow-project:${RELEASE_VERSION}")"
|
|
|
|
STORE_DWELL_ALERT_IMAGE="$(build_overlay_image \
|
|
store-dwell-alert \
|
|
"$STORE_DWELL_ALERT_IMAGE" \
|
|
"$TARGET_DIR/runtime-overlays/store-dwell-alert/rootfs" \
|
|
"managed-portal-runtime/store-dwell-alert:${RELEASE_VERSION}")"
|
|
|
|
export MANAGED_PORTAL_IMAGE
|
|
export MANAGED_PORTAL_WEB_IMAGE
|
|
export PEOPLE_FLOW_PROJECT_IMAGE
|
|
export STORE_DWELL_ALERT_IMAGE
|
|
export MANAGED_PEOPLE_FLOW_WEIGHTS_DIR
|
|
|
|
cd "$TARGET_DIR/deploy"
|
|
run_compose \
|
|
--env-file managed-portal.release.env \
|
|
-f docker-compose.ota-release.yml \
|
|
up -d
|
|
|
|
echo "release installed under $TARGET_DIR" |