Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion scripts/raspberry-pi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ APK を確認せずサーバーだけ更新したい場合は --skip-apk を付

同じ配布物には e-Paper 表示サービスのコード(raspberry-pi-display)も含まれており、/opt/kidspos-display が存在すればそちらも同時に差し替え、稼働中なら kidspos-display を再起動します。
表示サービスを導入していない Pi では何も行いません。差し替えたくない場合は --skip-display を付けてください。
なお install.sh と install-display.sh と systemd ユニットは daemon-reload を伴うため自動更新の対象外です。変更があった場合はリポジトリを取得し直して各インストールスクリプトを実行してください。
systemd ユニットも配布物と毎回突き合わせ、差があれば入れ替えて daemon-reload と再起動を行います。新しいユニットで起動を確認できなければ元のユニットに戻します。起動待ちは 2 秒間隔で最大 20 分、KIDSPOS_UNIT_HEALTH_RETRIES で調整できます。install.sh と install-display.sh は自動更新の対象外なので、変更があった場合はリポジトリを取得し直して各インストールスクリプトを実行してください。

### オフライン時(jar を持ち込む場合)

Expand Down Expand Up @@ -174,6 +174,7 @@ Flyway は前進専用のため、DB を戻さずに jar だけ旧バージョ
| KIDSPOS_UPLOAD_TIMEOUT | 600 | upload-apk |
| KIDSPOS_REQUIRED_JAVA_MAJOR | 21 | install / doctor |
| KIDSPOS_HEALTH_RETRIES | update は 600、install は 300 | install / update |
| KIDSPOS_UNIT_HEALTH_RETRIES | 600 | update |
| KIDSPOS_HEALTH_TIMEOUT | 10 | install / update |
| KIDSPOS_BACKUP_KEEP | 5 | update |
| KIDSPOS_SERVICE_USER | pi | install |
Expand Down
23 changes: 20 additions & 3 deletions scripts/raspberry-pi/test-update-app.sh
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ test_health_check_uses_timeout() {
run_update "${WORK}/new.jar"

assert_eq 0 "$RC" "終了コードが 0"
assert_contains "$CALL_LOG" "curl -fsS --max-time 10 -o /dev/null http://localhost:8080/api/status" "既定のタイムアウトが渡される"
assert_contains "$CALL_LOG" "curl -fs --max-time 10 -o /dev/null http://localhost:8080/api/status" "既定のタイムアウトが渡される"

: > "$CALL_LOG"
set +e
Expand All @@ -383,7 +383,7 @@ test_health_check_uses_timeout() {
set -e

assert_eq 0 "$RC" "タイムアウト指定時の終了コードが 0"
assert_contains "$CALL_LOG" "curl -fsS --max-time 3 -o /dev/null http://localhost:8080/api/status" "環境変数でタイムアウトを変更できる"
assert_contains "$CALL_LOG" "curl -fs --max-time 3 -o /dev/null http://localhost:8080/api/status" "環境変数でタイムアウトを変更できる"
teardown
}

Expand All @@ -392,7 +392,7 @@ test_health_check_timeout_applies_while_retrying() {
run_update "${WORK}/new.jar"

assert_eq 1 "$RC" "終了コードが 1"
assert_eq 2 "$(grep -c "curl -fsS --max-time 10 -o /dev/null http://localhost:8080/api/status" "$CALL_LOG")" "リトライ回数の上限で打ち切られる"
assert_eq 2 "$(grep -c "curl -fs --max-time 10 -o /dev/null http://localhost:8080/api/status" "$CALL_LOG")" "リトライ回数の上限で打ち切られる"
teardown
}

Expand Down Expand Up @@ -587,6 +587,21 @@ test_self_update_runs_even_when_scripts_version_matches() {
teardown
}

test_self_update_skips_identical_script() {
setup "配布物のスクリプトが配置済みのものと同一内容なら更新ログを出さない"
touch "$HEALTH_OK_FILE"
write_release_json_with_scripts "v9.9.9"
make_scripts_tarball
cp "${WORK}/scripts-src/raspberry-pi/update-app.sh" "${APP_DIR}/update-app.sh"
chmod +x "${APP_DIR}/update-app.sh"
run_update

assert_eq 0 "$RC" "終了コードが 0"
assert_not_contains "${WORK}/out.log" "更新しました: ${APP_DIR}/update-app.sh" "同一内容のスクリプトは更新ログを出さない"
assert_eq "v9.9.9" "$(cat "${APP_DIR}/.installed-scripts-version")" "スクリプトのバージョンが記録される"
teardown
}

test_unit_is_replaced_and_service_restarted() {
setup "取り残された systemd ユニットが差し替えられ再起動される"
touch "$HEALTH_OK_FILE"
Expand Down Expand Up @@ -645,6 +660,7 @@ test_unit_rolls_back_when_service_fails_to_start() {

assert_eq 0 "$RC" "サーバーの更新は成功扱いになる"
assert_contains "${WORK}/out.log" "元のユニットに戻します" "巻き戻した旨が出力される"
assert_contains "${WORK}/out.log" "元のユニットでサービスが起動しました" "巻き戻し後の起動確認ログが出力される"
assert_eq "$before" "$(cat "$UNIT_PATH")" "ユニットが元に戻る"
if [ -e "${APP_DIR}/.installed-scripts-version" ]; then
fail_assert "スクリプトのバージョンは記録されない"
Expand Down Expand Up @@ -955,6 +971,7 @@ test_self_update_replaces_scripts
test_self_update_runs_before_apk_sync
test_self_update_when_jar_already_latest
test_self_update_runs_even_when_scripts_version_matches
test_self_update_skips_identical_script
test_unit_is_replaced_and_service_restarted
test_unit_keeps_service_user
test_unit_untouched_when_identical
Expand Down
17 changes: 13 additions & 4 deletions scripts/raspberry-pi/update-app.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ JAR_NAME="${KIDSPOS_JAR_NAME:-app.jar}"
SERVICE="${KIDSPOS_SERVICE:-kidspos-server}"
HEALTH_URL="${KIDSPOS_HEALTH_URL:-http://localhost:8080/api/status}"
HEALTH_RETRIES="${KIDSPOS_HEALTH_RETRIES:-600}"
UNIT_HEALTH_RETRIES="${KIDSPOS_UNIT_HEALTH_RETRIES:-150}"
UNIT_HEALTH_RETRIES="${KIDSPOS_UNIT_HEALTH_RETRIES:-600}"
HEALTH_TIMEOUT="${KIDSPOS_HEALTH_TIMEOUT:-10}"
BACKUP_KEEP="${KIDSPOS_BACKUP_KEEP:-5}"
SERVER_URL="${KIDSPOS_SERVER_URL:-http://localhost:8080}"
Expand Down Expand Up @@ -66,8 +66,9 @@ done

wait_for_health() {
local retries="${1:-$HEALTH_RETRIES}"
log "起動を待っています(最大 $((retries * 2 / 60)) 分): $HEALTH_URL"
for _ in $(seq 1 "$retries"); do
if curl -fsS --max-time "$HEALTH_TIMEOUT" -o /dev/null "$HEALTH_URL"; then
if curl -fs --max-time "$HEALTH_TIMEOUT" -o /dev/null "$HEALTH_URL" 2>/dev/null; then
return 0
fi
sleep 2
Expand Down Expand Up @@ -125,10 +126,15 @@ update_unit() {
return 0
fi

log "WARN: 新しいユニットで起動できなかったため元のユニットに戻します"
log "WARN: 新しいユニットで起動を確認できなかったため元のユニットに戻します"
cp "$backup" "$UNIT_PATH" || true
sudo systemctl daemon-reload || true
sudo systemctl restart "$SERVICE" || true
if wait_for_health "$UNIT_HEALTH_RETRIES"; then
log "元のユニットでサービスが起動しました: $SERVICE"
else
log "WARN: 元のユニットでも起動を確認できませんでした: $SERVICE"
fi
return 1
}

Expand Down Expand Up @@ -231,6 +237,10 @@ self_update() {
continue
fi
chmod +x "$src"
if cmp -s "$src" "${APP_DIR}/${script}"; then
rm -f "$src"
continue
fi
# 実行中の自分自身を上書きすると bash の読み込みが壊れるため、
# 同一ファイルシステム上に展開してから mv で差し替える
if mv -f "$src" "${APP_DIR}/${script}"; then
Expand Down Expand Up @@ -365,7 +375,6 @@ cp "$NEW_JAR" "$JAR_PATH"
log "サービスを起動します(Flyway マイグレーションが自動適用されます)"
sudo systemctl start "$SERVICE"

log "ヘルスチェック中: $HEALTH_URL"
wait_for_health || rollback

trap - ERR
Expand Down
Loading