#!/bin/sh
# Обновление агента с платы, с проверкой и откатом.
set -eu

CACHE="${DASHDASH_CACHE_DIR:-/var/lib/dashdash}"
RESULT="$CACHE/update-result.json"
LOG=/var/log/dashdash-update.log
PACKAGE=dashdash-agent
PORT="${SCREEN_PORT:-3000}"
HEALTH_TIMEOUT=90

version_now() {
	dpkg-query -W -f='${Version}' "$PACKAGE" 2>/dev/null || echo ""
}

write_result() {
	mkdir -p "$CACHE"
	cat > "$RESULT" <<JSON
{"ok": $1, "before": "$2", "after": "$3", "message": "$4", "at": "$(date -Is)"}
JSON
}

# Живой агент — это не запущенный юнит, а отвечающий порт.
agent_healthy() {
	i=0
	while [ "$i" -lt "$HEALTH_TIMEOUT" ]; do
		if curl -fsS -o /dev/null "http://127.0.0.1:${PORT}/health"; then
			return 0
		fi
		i=$((i + 1))
		sleep 1
	done
	return 1
}

rollback() {
	previous="$1"
	cached="/var/cache/apt/archives/${PACKAGE}_$(echo "$previous" | tr ':' '%3a')_all.deb"
	echo "откатываюсь на $previous"
	if [ -f "$cached" ] && dpkg -i "$cached"; then
		return 0
	fi
	# Пакета в кэше нет — пробуем репозиторий.
	DEBIAN_FRONTEND=noninteractive apt-get -y --allow-downgrades \
		install "${PACKAGE}=${previous}"
}

exec >>"$LOG" 2>&1
echo "--- $(date -Is) обновление"

BEFORE="$(version_now)"
[ -n "$BEFORE" ] || {
	# Пакета в системе нет вовсе — значит плата собрана не тем образом, что мы думаем.
	write_result false "нет" "нет" "пакет dashdash-agent не установлен, обновлять нечего"
	exit 1
}

# Источник обновлений должен быть прописан.
if [ ! -f /etc/apt/sources.list.d/dashdash.sources ]; then
	write_result false "$BEFORE" "$BEFORE" \
		"репозиторий обновлений не подключён: образ собран без --apt-url/--apt-key"
	exit 1
fi

if ! apt-get -o Acquire::Retries=3 update; then
	write_result false "$BEFORE" "$BEFORE" "не удалось обновить список пакетов"
	exit 1
fi

# Что apt вообще готов поставить.
CANDIDATE="$(apt-cache policy "$PACKAGE" | awk '/Candidate:/{print $2}')"
if [ -z "$CANDIDATE" ] || [ "$CANDIDATE" = "(none)" ]; then
	write_result false "$BEFORE" "$BEFORE" \
		"в репозитории нет пакета $PACKAGE — проверьте адрес репозитория и ключ"
	exit 1
fi

if ! DEBIAN_FRONTEND=noninteractive apt-get -y --only-upgrade install "$PACKAGE"; then
	write_result false "$BEFORE" "$(version_now)" "apt не смог поставить пакет"
	exit 1
fi

AFTER="$(version_now)"
if [ "$BEFORE" = "$AFTER" ]; then
	# Называем версию, которую предлагает репозиторий.
	write_result true "$BEFORE" "$AFTER" "уже последняя версия (в репозитории $CANDIDATE)"
	echo "обновлять нечего, кандидат $CANDIDATE"
	exit 0
fi

if agent_healthy; then
	write_result true "$BEFORE" "$AFTER" "обновлено"
	echo "было $BEFORE, стало $AFTER"
	exit 0
fi

echo "после $AFTER агент не ответил за ${HEALTH_TIMEOUT}с"
if rollback "$BEFORE" && agent_healthy; then
	write_result false "$BEFORE" "$BEFORE" "версия $AFTER не заработала, откатился"
	exit 1
fi

write_result false "$BEFORE" "$(version_now)" \
	"версия $AFTER не заработала, откат тоже не удался — нужна перепрошивка"
exit 1
