66 lines
2.9 KiB
Bash
66 lines
2.9 KiB
Bash
#!/usr/bin/env bash
|
|
# Generic test-server image switch: rollback tag first, 0600 runtime.env backup,
|
|
# post-edit verification (exactly 1 DOBOTAI_IMAGE line, unchanged line count),
|
|
# container recreate, then read-only readback incl. binary literal presence.
|
|
# Usage: bash test_switch_image.sh <image:tag> <label>
|
|
set -euo pipefail
|
|
NEW_IMAGE="${1:?usage: test_switch_image.sh <image:tag> <label>}"
|
|
LABEL="${2:?usage: test_switch_image.sh <image:tag> <label>}"
|
|
RUNTIME_ENV=/opt/dobotai/container/runtime.env
|
|
OLD_IMAGE="$(grep -m1 '^DOBOTAI_IMAGE=' "$RUNTIME_ENV" | cut -d= -f2-)"
|
|
ROLLBACK_TAG="dobotai-dingtalk:rollback-$(echo "$OLD_IMAGE" | sed 's/.*://')-before-$LABEL"
|
|
STAMP="$(date +%Y%m%dT%H%M%S)"
|
|
BACKUP_DIR=/opt/dobotai/container/backups
|
|
BACKUP="$BACKUP_DIR/runtime.env.before-$LABEL.$STAMP"
|
|
|
|
echo "== preflight =="
|
|
docker image inspect "$NEW_IMAGE" >/dev/null
|
|
[ "$OLD_IMAGE" != "$NEW_IMAGE" ] || { echo "ABORT: runtime.env already points at $NEW_IMAGE" >&2; exit 1; }
|
|
[ "$(grep -c '^DOBOTAI_IMAGE=' "$RUNTIME_ENV")" = "1" ] || { echo "ABORT: DOBOTAI_IMAGE line count != 1" >&2; exit 1; }
|
|
echo "old_image=$OLD_IMAGE"
|
|
echo "new_image=$NEW_IMAGE"
|
|
echo "rollback_tag=$ROLLBACK_TAG"
|
|
|
|
echo "== tag rollback target =="
|
|
if docker image inspect "$ROLLBACK_TAG" >/dev/null 2>&1; then
|
|
echo "rollback tag already exists, keeping it (no overwrite)"
|
|
else
|
|
docker tag "$OLD_IMAGE" "$ROLLBACK_TAG"
|
|
echo "tagged $OLD_IMAGE -> $ROLLBACK_TAG"
|
|
fi
|
|
|
|
echo "== backup runtime.env =="
|
|
mkdir -p "$BACKUP_DIR"
|
|
install -m 0600 "$RUNTIME_ENV" "$BACKUP"
|
|
echo "backup=$BACKUP"
|
|
|
|
echo "== rewrite DOBOTAI_IMAGE =="
|
|
tmp="$(mktemp /opt/dobotai/container/.runtime.env.XXXXXX)"
|
|
awk -v new="$NEW_IMAGE" '/^DOBOTAI_IMAGE=/ { sub(/^DOBOTAI_IMAGE=.*/, "DOBOTAI_IMAGE=" new) } { print }' "$RUNTIME_ENV" >"$tmp"
|
|
after_count="$(grep -c "^DOBOTAI_IMAGE=$NEW_IMAGE\$" "$tmp")"
|
|
if [ "$after_count" != "1" ] || [ "$(wc -l <"$tmp")" != "$(wc -l <"$RUNTIME_ENV")" ]; then
|
|
rm -f "$tmp"
|
|
echo "ABORT: post-edit verification failed (match=$after_count)" >&2
|
|
exit 1
|
|
fi
|
|
chmod 0644 "$tmp"
|
|
mv "$tmp" "$RUNTIME_ENV"
|
|
grep -n '^DOBOTAI_IMAGE=' "$RUNTIME_ENV"
|
|
|
|
echo "== recreate container =="
|
|
cd /opt/dobotai/container
|
|
docker compose --env-file runtime.env -f compose.yaml up -d --no-deps --force-recreate dobotai-dingtalk
|
|
|
|
echo "== readback =="
|
|
sleep 3
|
|
curl -fsS http://127.0.0.1:8090/healthz; echo
|
|
docker inspect dobotai-dingtalk --format 'image={{.Config.Image}} status={{.State.Status}} started={{.State.StartedAt}}'
|
|
for lit in PartialFeed autoLayout 智能推理模式; do
|
|
if docker exec dobotai-dingtalk grep -aqF "$lit" /proc/1/root/usr/local/bin/dobotai; then
|
|
echo "literal $lit: PRESENT"
|
|
else
|
|
echo "literal $lit: ABSENT"
|
|
fi
|
|
done
|
|
docker logs dobotai-dingtalk --since 60s 2>&1 | tail -8
|
|
echo "rollback: set DOBOTAI_IMAGE=$OLD_IMAGE in $RUNTIME_ENV (backup $BACKUP) then: docker compose --env-file runtime.env -f compose.yaml up -d --no-deps --force-recreate dobotai-dingtalk" |