feat: yakcloud domain check + 승격/init 도메인 사전검사 (v0.30.0)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
71
bin/yakcloud
71
bin/yakcloud
@ -16,7 +16,7 @@ set -uo pipefail # -e 미사용: 'test && action' 관용구가 값 없을 때
|
|||||||
|
|
||||||
REPO="${YAKCLOUD_STARTER_REPO:-https://gitea.yakenator.io/yakenator/yakcloud-starter}"
|
REPO="${YAKCLOUD_STARTER_REPO:-https://gitea.yakenator.io/yakenator/yakcloud-starter}"
|
||||||
BRANCH="${YAKCLOUD_STARTER_BRANCH:-main}"
|
BRANCH="${YAKCLOUD_STARTER_BRANCH:-main}"
|
||||||
VERSION="0.29.0"
|
VERSION="0.30.0"
|
||||||
# 로컬 개발 클러스터(kind) — 개발 후 운영까지 '직선 배포'의 dev 구간.
|
# 로컬 개발 클러스터(kind) — 개발 후 운영까지 '직선 배포'의 dev 구간.
|
||||||
DEV_CTX="${YAK_DEV_CONTEXT:-kind-yak-dev}"
|
DEV_CTX="${YAK_DEV_CONTEXT:-kind-yak-dev}"
|
||||||
DEV_CLUSTER="${YAK_DEV_CLUSTER:-yak-dev}"
|
DEV_CLUSTER="${YAK_DEV_CLUSTER:-yak-dev}"
|
||||||
@ -263,6 +263,14 @@ _init_wizard() {
|
|||||||
printf "검증 클러스터(관리형, 선택, 엔터=생략): "; read -r valc
|
printf "검증 클러스터(관리형, 선택, 엔터=생략): "; read -r valc
|
||||||
printf "운영 클러스터(관리형, 선택, 엔터=생략): "; read -r prodc
|
printf "운영 클러스터(관리형, 선택, 엔터=생략): "; read -r prodc
|
||||||
printf "운영 도메인(선택, 예 app.example.com): "; read -r pdom
|
printf "운영 도메인(선택, 예 app.example.com): "; read -r pdom
|
||||||
|
# 도메인 사전검사(로그인돼 있으면) — 예약·중복이면 지금 경고(빌드·배포 다 하고 나서 발견 방지).
|
||||||
|
if [ -n "$pdom" ]; then
|
||||||
|
local _dc; _dc="$(_domain_check "$pdom")"
|
||||||
|
case "$_dc" in
|
||||||
|
X*) echo " ⚠ '$pdom' 지금은 사용 불가 — ${_dc#X$'\t'}. 다른 도메인을 쓰거나 배포 전 'yakcloud domain check' 로 확인하세요." ;;
|
||||||
|
OK) echo " ✓ '$pdom' 사용 가능" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
printf "컨테이너 포트 [8080]: "; read -r port; port="${port:-8080}"
|
printf "컨테이너 포트 [8080]: "; read -r port; port="${port:-8080}"
|
||||||
printf "헬스체크 경로 [/healthz]: "; read -r health; health="${health:-/healthz}"
|
printf "헬스체크 경로 [/healthz]: "; read -r health; health="${health:-/healthz}"
|
||||||
printf "CPU 요청 [25m]: "; read -r cpu; cpu="${cpu:-25m}"
|
printf "CPU 요청 [25m]: "; read -r cpu; cpu="${cpu:-25m}"
|
||||||
@ -310,6 +318,56 @@ if v is not None: print(v)
|
|||||||
PY
|
PY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 도메인 사용 가능 사전검사(부작용 없음) — 등록과 같은 규칙(형식·존·예약·쿼터·중복).
|
||||||
|
# stdout: "OK" | "X<TAB>사유". 미로그인/네트워크 실패면 빈 출력(스킵 — 블록하지 않음).
|
||||||
|
_domain_check() {
|
||||||
|
local fqdn="$1" out
|
||||||
|
[ -n "${YAKCLOUD_URL:-}" ] && [ -n "${YAKCLOUD_TOKEN:-}" ] || return 0
|
||||||
|
out="$(curl -fsS -H "Authorization: Bearer $YAKCLOUD_TOKEN" --max-time 15 "$YAKCLOUD_URL/api/v1/domains/check?fqdn=$fqdn" 2>/dev/null)" || return 0
|
||||||
|
printf '%s' "$out" | python3 -c "import sys,json;d=json.load(sys.stdin);d=d.get('data',d);print('OK' if d.get('available') else 'X\t'+(d.get('reason') or '사용 불가'))" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# 매니페스트 environments.<env>.domains 목록(줄바꿈 구분).
|
||||||
|
_env_domains() {
|
||||||
|
ensure_pyyaml >/dev/null 2>&1 || true
|
||||||
|
python3 - "$1" <<'PY' 2>/dev/null
|
||||||
|
import sys, yaml
|
||||||
|
try: m = yaml.safe_load(open("yakcloud.yaml")) or {}
|
||||||
|
except Exception: sys.exit(0)
|
||||||
|
e = ((m.get("environments") or {}).get(sys.argv[1]) or {})
|
||||||
|
for d in (e.get("domains") or []):
|
||||||
|
if d: print(d)
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
# 환경 도메인 전부 사전검사. 사용 불가가 하나라도 있으면 1(비어있거나 전부 OK/스킵이면 0).
|
||||||
|
_precheck_env_domains() {
|
||||||
|
local bad=0 d r
|
||||||
|
while IFS= read -r d; do
|
||||||
|
[ -n "$d" ] || continue
|
||||||
|
r="$(_domain_check "$d")"
|
||||||
|
case "$r" in
|
||||||
|
X*) echo " ✗ 도메인 '$d' 사용 불가 — ${r#X$'\t'}"; bad=1 ;;
|
||||||
|
OK) echo " ✓ 도메인 '$d' 사용 가능" ;;
|
||||||
|
esac
|
||||||
|
done <<EOF
|
||||||
|
$(_env_domains "$1")
|
||||||
|
EOF
|
||||||
|
return $bad
|
||||||
|
}
|
||||||
|
|
||||||
|
# yakcloud domain check <fqdn> — 단독 사전검사(등록 안 함).
|
||||||
|
cmd_domain_check() {
|
||||||
|
local fqdn="$1"; [ -n "$fqdn" ] || die "사용법: yakcloud domain check <fqdn>"
|
||||||
|
: "${YAKCLOUD_URL:?YAKCLOUD_URL 필요 — 'yakcloud login'}"; : "${YAKCLOUD_TOKEN:?YAKCLOUD_TOKEN 필요 — 'yakcloud login'}"
|
||||||
|
local r; r="$(_domain_check "$fqdn")"
|
||||||
|
case "$r" in
|
||||||
|
OK) echo "✓ '$fqdn' 사용 가능 — 등록/노출할 수 있습니다." ;;
|
||||||
|
X*) printf "✗ '%s' 사용 불가 — %s\n" "$fqdn" "${r#X$'\t'}"; return 1 ;;
|
||||||
|
*) die "확인 실패 — 네트워크/로그인 상태 확인('yakcloud login')" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
# 로컬 kind 클러스터(yak-<name>) 존재 여부.
|
# 로컬 kind 클러스터(yak-<name>) 존재 여부.
|
||||||
_dev_cluster_exists() {
|
_dev_cluster_exists() {
|
||||||
local n="$1" rt kenv=""; rt="$(_dev_runtime)"; [ "$rt" = podman ] && kenv="KIND_EXPERIMENTAL_PROVIDER=podman"
|
local n="$1" rt kenv=""; rt="$(_dev_runtime)"; [ "$rt" = podman ] && kenv="KIND_EXPERIMENTAL_PROVIDER=podman"
|
||||||
@ -385,6 +443,8 @@ cmd_project_check() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
: "${YAKCLOUD_URL:?YAKCLOUD_URL 필요}"; : "${YAKCLOUD_TOKEN:?YAKCLOUD_TOKEN 필요}"
|
: "${YAKCLOUD_URL:?YAKCLOUD_URL 필요}"; : "${YAKCLOUD_TOKEN:?YAKCLOUD_TOKEN 필요}"
|
||||||
|
echo "도메인 사전검사 ($env):"
|
||||||
|
_precheck_env_domains "$env" || echo " ⚠ 위 도메인은 지금 상태로 승격 시 실패합니다 — 배포 전에 해결하세요."
|
||||||
YAKCLOUD_ENV="$env" python3 "$(_engine deploy)" yakcloud.yaml --dry-run
|
YAKCLOUD_ENV="$env" python3 "$(_engine deploy)" yakcloud.yaml --dry-run
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,6 +526,10 @@ cmd_project_promote() {
|
|||||||
[ -n "$tag" ] || tag="v0.1.0"
|
[ -n "$tag" ] || tag="v0.1.0"
|
||||||
fi
|
fi
|
||||||
case "$tag" in v*) : ;; *) tag="v$tag" ;; esac
|
case "$tag" in v*) : ;; *) tag="v$tag" ;; esac
|
||||||
|
# 도메인 사전검사 — 예약·중복 등으로 못 쓰는 도메인이면 build/push 前에 빠르게 실패(kanban 사태 방지).
|
||||||
|
if ! _precheck_env_domains "$env"; then
|
||||||
|
die "도메인 사전검사 실패 — 위 도메인을 해결(예약 해제·다른 이름·소유자 확인)한 뒤 다시 승격하세요. 이미지 빌드/푸시 안 함."
|
||||||
|
fi
|
||||||
# 운영 승격 게이트 — prod 는 개발계 검증 확정(그 버전)이 선행돼야 한다(val 은 자유).
|
# 운영 승격 게이트 — prod 는 개발계 검증 확정(그 버전)이 선행돼야 한다(val 은 자유).
|
||||||
[ "$env" = prod ] && _require_dev_confirm "$tag"
|
[ "$env" = prod ] && _require_dev_confirm "$tag"
|
||||||
info "'$env' 승격: $tag → 관리형 '$env' 클러스터(이미지 build+push 후 리컨실; 이미 있으면 재빌드 없이 그 이미지)"
|
info "'$env' 승격: $tag → 관리형 '$env' 클러스터(이미지 build+push 후 리컨실; 이미 있으면 재빌드 없이 그 이미지)"
|
||||||
@ -910,6 +974,7 @@ yakcloud $VERSION — YakCloud 프로젝트 CLI (개발·검증·운영 모두
|
|||||||
config 저장된 설정 표시(비밀 마스킹)
|
config 저장된 설정 표시(비밀 마스킹)
|
||||||
logout 저장 자격 삭제
|
logout 저장 자격 삭제
|
||||||
── 배포환경 설정(앱별) ──
|
── 배포환경 설정(앱별) ──
|
||||||
|
domain check <fqdn> 도메인 사용 가능 사전검사(등록 안 함) — 예약·중복·형식 확인. 도메인 정하기 前 권장
|
||||||
domain <fqdn> [wl] 도메인 등록 + 워크로드 할당(관리형=즉시/배포중이면 라이브)
|
domain <fqdn> [wl] 도메인 등록 + 워크로드 할당(관리형=즉시/배포중이면 라이브)
|
||||||
scale <wl> <n> replicas 변경
|
scale <wl> <n> replicas 변경
|
||||||
set <wl> --image/--port/--health/--cpu/--mem/--path/--rewrite
|
set <wl> --image/--port/--health/--cpu/--mem/--path/--rewrite
|
||||||
@ -942,7 +1007,9 @@ case "${1:-help}" in
|
|||||||
config) cmd_config ;;
|
config) cmd_config ;;
|
||||||
logout) cmd_logout ;;
|
logout) cmd_logout ;;
|
||||||
datasource|ds) shift; ctl source "$@" ;;
|
datasource|ds) shift; ctl source "$@" ;;
|
||||||
domain|scale|set|env|source|bind|unbind) ctl "$@" ;;
|
domain)
|
||||||
|
if [ "${2:-}" = check ]; then shift 2; cmd_domain_check "${1:-}"; else ctl "$@"; fi ;;
|
||||||
|
scale|set|env|source|bind|unbind) ctl "$@" ;;
|
||||||
upgrade|self-update) cmd_upgrade ;;
|
upgrade|self-update) cmd_upgrade ;;
|
||||||
version|-v|--version) echo "yakcloud $VERSION" ;;
|
version|-v|--version) echo "yakcloud $VERSION" ;;
|
||||||
help|-h|--help|"") usage ;;
|
help|-h|--help|"") usage ;;
|
||||||
|
|||||||
Reference in New Issue
Block a user