-
Notifications
You must be signed in to change notification settings - Fork 0
blue-green 슬롯 판정·전환 공용 블록 신설 #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # 공통 배포 블록: blue-green 슬롯 판정 | ||
| # | ||
| # nginx upstream 상태 파일(현재 서빙 슬롯의 single source, 예: "server 127.0.0.1:18090;")을 | ||
| # 읽어 ACTIVE(서빙 중)/INACTIVE(이번 배포 대상) 슬롯을 판정한다. | ||
| # 실행 위치 중립 - 순수 bash 만 쓴다. transport 는 호출자 소관 (conventions/blocks.md 1번). | ||
| # | ||
| # 포트 추출은 콜론 뒤 숫자만 문다 - "server 127.0.0.1:18090;" 처럼 host 에 숫자가 섞이면 | ||
| # 무차별 숫자 추출은 "127" 을 먼저 물어 슬롯 판정이 조용히 어긋난다 (extractor 실측 함정. | ||
| # "server localhost:8080;" 류는 우연히 무사해서 복제 구현에 잠복해 있었다). | ||
| # | ||
| # 상태 파일이 없거나 포트가 두 슬롯 어느 쪽도 아니면 부트스트랩으로 본다: | ||
| # ACTIVE 는 빈 값, INACTIVE 는 --slot-a (첫 배포는 a 슬롯으로 간다). | ||
| # | ||
| # 출력: eval 가능한 한 줄 (stdout) | ||
| # ACTIVE=blue ACTIVE_PORT=18090 INACTIVE=green INACTIVE_PORT=18091 | ||
| # 호출자는 2단계로 소비한다 - eval "$(...)" 직결은 치환 실패가 빈 문자열 eval(성공)로 | ||
| # 위장되므로, 할당으로 실패를 먼저 드러낸 뒤 eval 한다: | ||
| # DECIDED=$(bash slot_decide.sh --state-file ... --slot-a blue:18090 --slot-b green:18091) | ||
| # eval "$DECIDED" | ||
| # | ||
| # 인자: | ||
| # --state-file (필수) upstream 상태 파일 경로 | ||
| # --slot-a (필수) 첫 슬롯 NAME:PORT (예: blue:18090). 부트스트랩의 배포 대상 | ||
| # --slot-b (필수) 둘째 슬롯 NAME:PORT (예: green:18091) | ||
| # | ||
| # 종료 코드: 성공 0, 인자 오류 2 (판정 자체는 실패하지 않는다 - 모르는 상태는 부트스트랩) | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| STATE_FILE="" | ||
| SLOT_A="" | ||
| SLOT_B="" | ||
|
|
||
| while [ $# -gt 0 ]; do | ||
| case "$1" in | ||
| --state-file) STATE_FILE="${2:-}"; shift 2;; | ||
| --slot-a) SLOT_A="${2:-}"; shift 2;; | ||
| --slot-b) SLOT_B="${2:-}"; shift 2;; | ||
| *) echo "unknown arg: $1" >&2; exit 2;; | ||
| esac | ||
| done | ||
|
|
||
| [ -n "$STATE_FILE" ] || { echo "--state-file is required" >&2; exit 2; } | ||
| [ -n "$SLOT_A" ] || { echo "--slot-a is required" >&2; exit 2; } | ||
| [ -n "$SLOT_B" ] || { echo "--slot-b is required" >&2; exit 2; } | ||
|
|
||
| parse_slot() { | ||
| # NAME:PORT 를 검증하며 분해한다. 전역 PARSED_NAME/PARSED_PORT 로 반환. | ||
| local arg_name="$1" value="$2" | ||
| PARSED_NAME="${value%%:*}" | ||
| PARSED_PORT="${value##*:}" | ||
| if [ "$value" = "$PARSED_NAME" ] || [ -z "$PARSED_NAME" ] || [ -z "$PARSED_PORT" ]; then | ||
| echo "$arg_name must be NAME:PORT (got: $value)" >&2 | ||
| exit 2 | ||
| fi | ||
| case "$PARSED_PORT" in | ||
| *[!0-9]*) echo "$arg_name port must be numeric (got: $value)" >&2; exit 2;; | ||
| esac | ||
|
Comment on lines
+52
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win eval 출력에 슬롯 이름을 안전하게 직렬화하십시오.
모든 출력 값을 Bash 안전 형식으로 인코딩하십시오. 예를 들어 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| } | ||
|
|
||
| parse_slot "--slot-a" "$SLOT_A" | ||
| NAME_A="$PARSED_NAME" PORT_A="$PARSED_PORT" | ||
| parse_slot "--slot-b" "$SLOT_B" | ||
| NAME_B="$PARSED_NAME" PORT_B="$PARSED_PORT" | ||
|
Comment on lines
+63
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 두 슬롯의 이름과 포트가 서로 다르도록 검증하십시오.
🤖 Prompt for AI Agents |
||
|
|
||
| CURRENT_PORT="" | ||
| if [ -f "$STATE_FILE" ]; then | ||
| CURRENT_PORT=$(grep -oE ':[0-9]+' "$STATE_FILE" | head -1 | tr -d ':' || true) | ||
| fi | ||
|
|
||
| if [ "$CURRENT_PORT" = "$PORT_A" ]; then | ||
| echo "ACTIVE=$NAME_A ACTIVE_PORT=$PORT_A INACTIVE=$NAME_B INACTIVE_PORT=$PORT_B" | ||
| elif [ "$CURRENT_PORT" = "$PORT_B" ]; then | ||
| echo "ACTIVE=$NAME_B ACTIVE_PORT=$PORT_B INACTIVE=$NAME_A INACTIVE_PORT=$PORT_A" | ||
| else | ||
| echo "ACTIVE= ACTIVE_PORT= INACTIVE=$NAME_A INACTIVE_PORT=$PORT_A" | ||
| fi | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # blocks/slot_decide.sh 셀프 테스트 | ||
| # | ||
| # 상태 파일 케이스(부트스트랩·a 활성·b 활성·모르는 포트)와 인자 오류, 그리고 이 블록의 | ||
| # 존재 이유인 포트 추출 함정(host 의 127 이 먼저 잡히는 것) 회귀를 실측한다. | ||
| # conventions/blocks.md 5번 원칙(셀프 검증 가능)의 실행체. | ||
| # | ||
| # 실행: ./blocks/slot_decide.test.sh | ||
|
|
||
| set -uo pipefail | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| DECIDE="$SCRIPT_DIR/slot_decide.sh" | ||
|
|
||
| WORKDIR=$(mktemp -d) | ||
| cleanup() { rm -rf "$WORKDIR"; } | ||
| trap cleanup EXIT | ||
|
|
||
| FAILURES=0 | ||
|
|
||
| check() { | ||
| local desc="$1" expected="$2" actual="$3" | ||
| if [ "$expected" = "$actual" ]; then | ||
| echo "PASS: $desc" | ||
| else | ||
| echo "FAIL: $desc (expected=[$expected] actual=[$actual])" >&2 | ||
| FAILURES=$((FAILURES + 1)) | ||
| fi | ||
| } | ||
|
|
||
| # 1. 필수 인자 누락 | ||
| "$DECIDE" --slot-a blue:18090 --slot-b green:18091 >/dev/null 2>&1 | ||
| check "state-file 없음 -> exit 2" 2 "$?" | ||
| "$DECIDE" --state-file "$WORKDIR/up.conf" --slot-a blue:18090 >/dev/null 2>&1 | ||
| check "slot-b 없음 -> exit 2" 2 "$?" | ||
|
|
||
| # 2. 알 수 없는 인자 | ||
| "$DECIDE" --state-file "$WORKDIR/up.conf" --slot-a blue:18090 --slot-b green:18091 --bogus x >/dev/null 2>&1 | ||
| check "알 수 없는 인자 -> exit 2" 2 "$?" | ||
|
|
||
| # 3. 슬롯 형식 위반 | ||
| "$DECIDE" --state-file "$WORKDIR/up.conf" --slot-a blue18090 --slot-b green:18091 >/dev/null 2>&1 | ||
| check "콜론 없는 슬롯 -> exit 2" 2 "$?" | ||
| "$DECIDE" --state-file "$WORKDIR/up.conf" --slot-a blue:1809x --slot-b green:18091 >/dev/null 2>&1 | ||
| check "비숫자 포트 -> exit 2" 2 "$?" | ||
|
|
||
| # 4. 부트스트랩: 상태 파일 없음 -> INACTIVE = slot-a | ||
| OUT=$("$DECIDE" --state-file "$WORKDIR/none.conf" --slot-a blue:18090 --slot-b green:18091) | ||
| check "부트스트랩 판정" "ACTIVE= ACTIVE_PORT= INACTIVE=blue INACTIVE_PORT=18090" "$OUT" | ||
|
|
||
| # 5. 포트 추출 함정 회귀: host 에 숫자(127.0.0.1)가 있어도 콜론 뒤 포트만 문다 | ||
| echo "server 127.0.0.1:18090;" >"$WORKDIR/up.conf" | ||
| OUT=$("$DECIDE" --state-file "$WORKDIR/up.conf" --slot-a blue:18090 --slot-b green:18091) | ||
| check "127.0.0.1 host 에서 a 활성 판정" "ACTIVE=blue ACTIVE_PORT=18090 INACTIVE=green INACTIVE_PORT=18091" "$OUT" | ||
|
|
||
| # 6. b 활성 (core 의 localhost 표기도 같은 추출 규칙으로 동작) | ||
| echo "server localhost:8081;" >"$WORKDIR/up.conf" | ||
| OUT=$("$DECIDE" --state-file "$WORKDIR/up.conf" --slot-a blue:8080 --slot-b green:8081) | ||
| check "localhost 표기에서 b 활성 판정" "ACTIVE=green ACTIVE_PORT=8081 INACTIVE=blue INACTIVE_PORT=8080" "$OUT" | ||
|
|
||
| # 7. 모르는 포트 -> 부트스트랩 | ||
| echo "server 127.0.0.1:9999;" >"$WORKDIR/up.conf" | ||
| OUT=$("$DECIDE" --state-file "$WORKDIR/up.conf" --slot-a blue:18090 --slot-b green:18091) | ||
| check "모르는 포트 -> 부트스트랩" "ACTIVE= ACTIVE_PORT= INACTIVE=blue INACTIVE_PORT=18090" "$OUT" | ||
|
|
||
| # 8. 출력이 eval 가능한 계약인지 (문서의 2단계 소비 패턴 그대로) | ||
| echo "server 127.0.0.1:18091;" >"$WORKDIR/up.conf" | ||
| DECIDED=$("$DECIDE" --state-file "$WORKDIR/up.conf" --slot-a blue:18090 --slot-b green:18091) | ||
| eval "$DECIDED" | ||
| check "eval 소비: ACTIVE" "green" "${ACTIVE:-}" | ||
| check "eval 소비: INACTIVE_PORT" "18090" "${INACTIVE_PORT:-}" | ||
|
|
||
| if [ "$FAILURES" -gt 0 ]; then | ||
| echo "$FAILURES case(s) failed" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "all slot_decide.sh cases passed" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # 공통 배포 블록: blue-green upstream 전환 (실패 시 원복) | ||
| # | ||
| # upstream 상태 파일을 새 슬롯으로 갱신하고 nginx 검증(-t)·reload 를 수행한다. | ||
| # 어느 단계가 실패해도(구성 검증, reload, 사후 검증) 이전 상태 파일을 원복해 | ||
| # "상태 파일만 새 슬롯을 가리키고 실제 서빙은 옛 슬롯"인 괴리를 남기지 않는다. | ||
| # 이 괴리는 다음 배포의 슬롯 판정(slot_decide.sh)을 뒤집어, 실제 서빙 중인 슬롯을 | ||
| # 비활성으로 오판·제거하게 만든다 (extractor 이행 배포 실사고의 일반화). | ||
| # | ||
| # 실행 위치 중립 - root 가 아니면 sudo 를 앞에 붙인다 (SSH runner 비루트 / SSM root 양쪽). | ||
| # reload 는 systemctl reload -> 실패 시 restart 폴백이라 nginx 가 정지 상태여도 전환된다. | ||
| # | ||
| # 사용 예: | ||
| # slot_switch.sh --state-file /etc/nginx/piki-extractor-upstream.conf --server 127.0.0.1:18091 \ | ||
| # --verify-cmd "bash /tmp/piki-blocks/healthcheck.sh --url http://localhost:8090/actuator/health --interval 2 --attempts 10" | ||
| # | ||
| # 인자: | ||
| # --state-file (필수) upstream 상태 파일 경로. "server <값>;" 한 줄로 덮어쓴다 | ||
| # --server (필수) 새 upstream server 값 (예: 127.0.0.1:18091) | ||
| # --verify-cmd (선택) reload 후 실행할 검증 명령(bash -c 로 실행). 비-0 이면 원복 후 실패. | ||
| # 전환 후 프론트 경유 헬스체크(healthcheck.sh 호출)가 대표 소비자 - 검증까지 | ||
| # 원복 경계 안에 있어야 "전환됐지만 안 서빙되는" 상태가 남지 않는다 | ||
| # | ||
| # 부트스트랩(이전 상태 파일 없음)은 원복 대상이 없다 - 실패해도 새 값이 남고 exit 1 로만 | ||
| # 알린다 (되돌아갈 서빙 슬롯 자체가 없는 1회성 창이라 호출자·운영자가 수동 개입). | ||
| # | ||
| # 종료 코드: 성공 0, 전환 실패(가능하면 원복 수행) 1, 인자 오류 2 | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| STATE_FILE="" | ||
| SERVER="" | ||
| VERIFY_CMD="" | ||
|
|
||
| while [ $# -gt 0 ]; do | ||
| case "$1" in | ||
| --state-file) STATE_FILE="${2:-}"; shift 2;; | ||
| --server) SERVER="${2:-}"; shift 2;; | ||
| --verify-cmd) VERIFY_CMD="${2:-}"; shift 2;; | ||
| *) echo "unknown arg: $1" >&2; exit 2;; | ||
| esac | ||
| done | ||
|
|
||
| [ -n "$STATE_FILE" ] || { echo "--state-file is required" >&2; exit 2; } | ||
| [ -n "$SERVER" ] || { echo "--server is required" >&2; exit 2; } | ||
|
|
||
| run_priv() { | ||
| if [ "$(id -u)" = "0" ]; then "$@"; else sudo "$@"; fi | ||
| } | ||
|
|
||
| PREV="" | ||
| [ -f "$STATE_FILE" ] && PREV=$(cat "$STATE_FILE") | ||
|
|
||
| restore() { | ||
| local stage="$1" | ||
| if [ -z "$PREV" ]; then | ||
| echo "switch FAILED at $stage - no previous state to restore (bootstrap)" >&2 | ||
| return 0 | ||
| fi | ||
| printf '%s\n' "$PREV" | run_priv tee "$STATE_FILE" >/dev/null | ||
| run_priv systemctl reload nginx 2>/dev/null || true | ||
| echo "switch FAILED at $stage - restored previous upstream" >&2 | ||
|
Comment on lines
+61
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win nginx 원복 실패를 성공으로 처리하지 마십시오. verify 실패 경로에서는 새 upstream이 이미 Line 72에서 적용되었습니다. 이후 Line 62의 reload가 실패하면 상태 파일만 이전 값으로 돌아가고 nginx는 새 upstream을 계속 사용할 수 있습니다. 그러나 현재 코드는 실패를 무시하고 원복 상태 파일을 쓴 뒤 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| printf 'server %s;\n' "$SERVER" | run_priv tee "$STATE_FILE" >/dev/null | ||
|
|
||
| if ! run_priv nginx -t; then | ||
| restore "nginx -t" | ||
| exit 1 | ||
| fi | ||
| if ! { run_priv systemctl reload nginx || run_priv systemctl restart nginx; }; then | ||
| restore "reload/restart" | ||
| exit 1 | ||
| fi | ||
| if [ -n "$VERIFY_CMD" ] && ! bash -c "$VERIFY_CMD"; then | ||
| restore "verify" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "switched upstream -> server $SERVER; ($STATE_FILE)" | ||
| exit 0 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # blocks/slot_switch.sh 셀프 테스트 | ||
| # | ||
| # nginx·systemctl·sudo 를 PATH 스텁으로 대체해 전환·원복 계약(종료 코드 + 상태 파일 내용)을 | ||
| # 실측한다. 이 블록의 존재 이유가 "실패 시 원복"이므로, 각 실패 지점(-t·reload·verify)마다 | ||
| # 상태 파일이 이전 값으로 돌아오는지를 검사한다. conventions/blocks.md 5번 원칙의 실행체. | ||
| # | ||
| # 실행: ./blocks/slot_switch.test.sh | ||
|
|
||
| set -uo pipefail | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| SWITCH="$SCRIPT_DIR/slot_switch.sh" | ||
|
|
||
| WORKDIR=$(mktemp -d) | ||
| cleanup() { rm -rf "$WORKDIR"; } | ||
| trap cleanup EXIT | ||
|
|
||
| # ── PATH 스텁: 실패 주입은 FAKE_DIR 의 마커 파일로 제어한다 ── | ||
| mkdir -p "$WORKDIR/bin" | ||
| export FAKE_DIR="$WORKDIR" | ||
| cat >"$WORKDIR/bin/sudo" <<'EOF' | ||
| #!/usr/bin/env bash | ||
| exec "$@" | ||
| EOF | ||
| cat >"$WORKDIR/bin/nginx" <<'EOF' | ||
| #!/usr/bin/env bash | ||
| [ -f "$FAKE_DIR/nginx_t_fail" ] && exit 1 | ||
| exit 0 | ||
| EOF | ||
| cat >"$WORKDIR/bin/systemctl" <<'EOF' | ||
| #!/usr/bin/env bash | ||
| echo "$*" >>"$FAKE_DIR/systemctl.log" | ||
| [ -f "$FAKE_DIR/systemctl_fail" ] && exit 1 | ||
| exit 0 | ||
| EOF | ||
| chmod +x "$WORKDIR/bin/sudo" "$WORKDIR/bin/nginx" "$WORKDIR/bin/systemctl" | ||
| export PATH="$WORKDIR/bin:$PATH" | ||
|
|
||
| STATE="$WORKDIR/upstream.conf" | ||
|
|
||
| FAILURES=0 | ||
|
|
||
| check() { | ||
| local desc="$1" expected="$2" actual="$3" | ||
| if [ "$expected" = "$actual" ]; then | ||
| echo "PASS: $desc" | ||
| else | ||
| echo "FAIL: $desc (expected=[$expected] actual=[$actual])" >&2 | ||
| FAILURES=$((FAILURES + 1)) | ||
| fi | ||
| } | ||
|
|
||
| reset_fakes() { | ||
| rm -f "$FAKE_DIR/nginx_t_fail" "$FAKE_DIR/systemctl_fail" "$FAKE_DIR/systemctl.log" | ||
| } | ||
|
|
||
| # 1. 필수 인자 누락 / 알 수 없는 인자 | ||
| "$SWITCH" --server 127.0.0.1:18091 >/dev/null 2>&1 | ||
| check "state-file 없음 -> exit 2" 2 "$?" | ||
| "$SWITCH" --state-file "$STATE" >/dev/null 2>&1 | ||
| check "server 없음 -> exit 2" 2 "$?" | ||
| "$SWITCH" --state-file "$STATE" --server x --bogus y >/dev/null 2>&1 | ||
| check "알 수 없는 인자 -> exit 2" 2 "$?" | ||
|
|
||
| # 2. 정상 전환: 상태 파일 갱신 + reload 수행 | ||
| reset_fakes | ||
| echo "server 127.0.0.1:18090;" >"$STATE" | ||
| "$SWITCH" --state-file "$STATE" --server 127.0.0.1:18091 >/dev/null 2>&1 | ||
| check "정상 전환 -> exit 0" 0 "$?" | ||
| check "정상 전환 -> 상태 파일 갱신" "server 127.0.0.1:18091;" "$(cat "$STATE")" | ||
| grep -q "reload nginx" "$FAKE_DIR/systemctl.log" | ||
| check "정상 전환 -> reload 호출" 0 "$?" | ||
|
|
||
| # 3. nginx -t 실패 -> 원복 | ||
| reset_fakes | ||
| echo "server 127.0.0.1:18090;" >"$STATE" | ||
| touch "$FAKE_DIR/nginx_t_fail" | ||
| "$SWITCH" --state-file "$STATE" --server 127.0.0.1:18091 >/dev/null 2>&1 | ||
| check "-t 실패 -> exit 1" 1 "$?" | ||
| check "-t 실패 -> 상태 파일 원복" "server 127.0.0.1:18090;" "$(cat "$STATE")" | ||
|
|
||
| # 4. reload·restart 모두 실패 -> 원복 | ||
| reset_fakes | ||
| echo "server 127.0.0.1:18090;" >"$STATE" | ||
| touch "$FAKE_DIR/systemctl_fail" | ||
| "$SWITCH" --state-file "$STATE" --server 127.0.0.1:18091 >/dev/null 2>&1 | ||
| check "reload/restart 실패 -> exit 1" 1 "$?" | ||
| check "reload/restart 실패 -> 상태 파일 원복" "server 127.0.0.1:18090;" "$(cat "$STATE")" | ||
|
|
||
| # 5. verify 실패 -> 원복 + 원복 반영 reload | ||
| reset_fakes | ||
| echo "server 127.0.0.1:18090;" >"$STATE" | ||
| "$SWITCH" --state-file "$STATE" --server 127.0.0.1:18091 --verify-cmd "false" >/dev/null 2>&1 | ||
| check "verify 실패 -> exit 1" 1 "$?" | ||
| check "verify 실패 -> 상태 파일 원복" "server 127.0.0.1:18090;" "$(cat "$STATE")" | ||
| check "verify 실패 -> reload 2회(전환+원복)" 2 "$(grep -c "reload nginx" "$FAKE_DIR/systemctl.log")" | ||
|
|
||
| # 6. verify 성공 -> 전환 유지 | ||
| reset_fakes | ||
| echo "server 127.0.0.1:18090;" >"$STATE" | ||
| "$SWITCH" --state-file "$STATE" --server 127.0.0.1:18091 --verify-cmd "true" >/dev/null 2>&1 | ||
| check "verify 성공 -> exit 0" 0 "$?" | ||
| check "verify 성공 -> 상태 파일 유지" "server 127.0.0.1:18091;" "$(cat "$STATE")" | ||
|
|
||
| # 7. 부트스트랩(-t 실패, 이전 상태 없음) -> 원복 대상 없음, 새 값 유지 + exit 1 | ||
| reset_fakes | ||
| rm -f "$STATE" | ||
| touch "$FAKE_DIR/nginx_t_fail" | ||
| "$SWITCH" --state-file "$STATE" --server 127.0.0.1:18090 >/dev/null 2>&1 | ||
| check "부트스트랩 -t 실패 -> exit 1" 1 "$?" | ||
| check "부트스트랩 -t 실패 -> 새 값 유지(원복 대상 없음)" "server 127.0.0.1:18090;" "$(cat "$STATE")" | ||
|
|
||
| if [ "$FAILURES" -gt 0 ]; then | ||
| echo "$FAILURES case(s) failed" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "all slot_switch.sh cases passed" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
값이 없는 옵션의 종료 코드 계약을 두 스크립트에서 통일하십시오.
두 스크립트는 옵션 값이 없을 때
shift 2를 실행합니다. 이 동작은set -e로 인해 문서화한 인자 오류 코드 2를 보장하지 않습니다.blocks/slot_decide.sh#L38-L40: 각 옵션에서shift 2전에 인자 개수를 확인하고, 값이 없으면 오류 메시지와 함께exit 2하십시오.blocks/slot_switch.sh#L38-L40: 동일한 검사를 적용하고,--verify-cmd가 마지막 인자인 경우도 종료 코드 2로 처리하십시오.📍 Affects 2 files
blocks/slot_decide.sh#L38-L40(this comment)blocks/slot_switch.sh#L38-L40🤖 Prompt for AI Agents