zioinfo-mail/setup/install_auto.sh
DESKTOP-TKLFCPR\ython bae659adba feat(setup): Claude Code Desktop 자동 설치 + 30일 라이선스 + 서비스 자동 실행
[Claude Code Desktop 자동 설치 환경]
- setup/CLAUDE.md: 트리거 키워드 + 설치 패키지 설명
- setup/.claude/skills/guardia-install/SKILL.md: 6단계 설치 오케스트레이터
  Phase 0: 의도 파악 → Phase 1: OS 감지 → Phase 2: 사전 확인
  Phase 3: 설치 실행 → Phase 4: 라이선스 발급 → Phase 5: 검증 → Phase 6: 완료보고

[통합 자동 설치 스크립트]
- setup/install_auto.sh: Linux 통합 (OS 자동 감지 ubuntu/centos/rhel)
  - --license trial30|trial7|<key> 파라미터
  - 설치 완료 후 GUARDiA 자동 실행 + 브라우저 자동 열기
  - --test 검증 모드
- setup/install_auto.ps1: Windows 통합 (ASCII 전용, PS 5.1 호환)
  - 설치 후 NSSM 서비스 자동 시작 + 브라우저 자동 열기
  - -Test 파라미터로 검증 전용 실행

[라이선스 엔진 개선]
- core/license.py: generate_trial_key(days=None) 파라미터 추가
- TRIAL_DURATION_DAYS = TRIAL_DURATION_DAYS 환경변수로 조정 가능
- routers/license.py: TrialRequest.days 필드 + 30일 체험판 지원
  POST /api/license/trial {"days": 30} 로 30일 발급

사용자 경험:
  1. setup/ 폴더를 새 PC에 복사
  2. Claude Code Desktop 열고 해당 폴더 open
  3. "GUARDiA 시스템 1달 사용자로 설치해 줘" 입력
  4. 자동으로 OS 감지 → 설치 → 30일 라이선스 → 브라우저 열림

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 09:06:14 +09:00

330 lines
13 KiB
Bash

#!/bin/bash
# =============================================================
# GUARDiA ITSM 통합 자동 설치 스크립트 (Linux)
# =============================================================
# Claude Code Desktop에서 자동 호출됨
# 직접 실행: sudo bash install_auto.sh [OS유형] [옵션]
#
# OS유형: ubuntu | centos | rhel | auto(기본)
# 옵션:
# --license trial30 : 30일 체험판 (기본)
# --license trial7 : 7일 체험판
# --license <key> : 정식 라이선스 키
# --test : 설치 검증만
# --offline : 오프라인 모드 (setup/offline/ 필요)
# --db sqlite : SQLite 사용 (기본)
# --db postgres : PostgreSQL 사용
# --skip-ollama : Ollama 생략
# --skip-gitea : Gitea 생략
# =============================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="/var/log/guardia_auto_install.log"
START_TIME=$(date +%s)
# 인수 파싱
OS_TYPE="${1:-auto}"
LICENSE_TYPE="trial30"
TEST_MODE=false
OFFLINE=false
DB_TYPE="sqlite"
INSTALL_OLLAMA=true
INSTALL_GITEA=true
shift 1 2>/dev/null || true
while [[ $# -gt 0 ]]; do
case "$1" in
--license) LICENSE_TYPE="$2"; shift 2 ;;
--test) TEST_MODE=true; shift ;;
--offline) OFFLINE=true; shift ;;
--db) DB_TYPE="$2"; shift 2 ;;
--skip-ollama) INSTALL_OLLAMA=false; shift ;;
--skip-gitea) INSTALL_GITEA=false; shift ;;
*) shift ;;
esac
done
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
ok() { echo -e "${GREEN}[OK]${NC} $*" | tee -a "$LOG_FILE"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*" | tee -a "$LOG_FILE"; }
fail() { echo -e "${RED}[FAIL]${NC} $*" | tee -a "$LOG_FILE"; exit 1; }
info() { echo -e "${CYAN}[INFO]${NC} $*" | tee -a "$LOG_FILE"; }
step() { echo -e "\n${CYAN}━━━ $* ━━━${NC}" | tee -a "$LOG_FILE"; }
# ── OS 자동 감지 ───────────────────────────────────────────────
detect_os() {
if [[ "$OS_TYPE" != "auto" ]]; then return; fi
if [[ -f /etc/os-release ]]; then
source /etc/os-release
case "${ID:-}" in
ubuntu|debian) OS_TYPE="ubuntu" ;;
centos|stream) OS_TYPE="centos" ;;
rhel|rocky|almalinux) OS_TYPE="rhel" ;;
*)
case "${ID_LIKE:-}" in
*debian*) OS_TYPE="ubuntu" ;;
*rhel*|*fedora*) OS_TYPE="rhel" ;;
*) fail "지원하지 않는 OS: $ID" ;;
esac ;;
esac
OS_VERSION="${VERSION_ID%%.*}"
info "OS 감지: $PRETTY_NAME$OS_TYPE $OS_VERSION"
elif [[ "$(uname)" == "Darwin" ]]; then
OS_TYPE="mac"
info "OS 감지: macOS"
else
fail "OS를 감지할 수 없습니다."
fi
}
# ── root 확인 ──────────────────────────────────────────────────
check_root() {
if [[ $EUID -ne 0 ]]; then
echo ""
echo "관리자 권한이 필요합니다."
echo "다음 명령으로 재실행하세요:"
echo " sudo bash $0 $*"
exit 1
fi
}
# ── 설치 검증 모드 ─────────────────────────────────────────────
run_tests() {
echo "=== GUARDiA ITSM 설치 검증 ===" | tee -a "$LOG_FILE"
PASS=0; FAIL=0
chk() {
local desc="$1"; shift
if "$@" &>/dev/null 2>&1; then
ok "$desc"; ((PASS++))
else
echo -e "${RED}[FAIL]${NC} $desc"; ((FAIL++))
fi
}
chk "Python 3.11+" python3.11 --version
chk "Java 17 (OpenJDK)" java -version
chk "Tomcat 9 서비스" systemctl is-active tomcat9
chk "GUARDiA 서비스" systemctl is-active guardia-itsm
chk "GUARDiA HTTP" bash -c 'curl -sf http://localhost:8001/ -o /dev/null'
chk "GUARDiA 로그인 API" bash -c 'curl -sf -X POST http://localhost:8001/api/auth/login \
-H "Content-Type: application/json" -d "{\"username\":\"admin\",\"password\":\"1111\"}" -o /dev/null'
[[ "$INSTALL_OLLAMA" == "true" ]] && chk "Ollama API" bash -c 'curl -sf http://localhost:11434/api/version -o /dev/null'
[[ "$INSTALL_GITEA" == "true" ]] && chk "Gitea HTTP" bash -c 'curl -sf http://localhost:3000/api/v1/version -o /dev/null'
chk "라이선스 상태" bash -c 'curl -sf http://localhost:8001/api/license/status -o /dev/null'
echo ""
echo "검증 결과: 성공 $PASS / 실패 $FAIL"
[[ $FAIL -eq 0 ]] && ok "모든 검증 통과!" || warn "$FAIL개 확인 필요"
return $FAIL
}
# ── 라이선스 발급 ─────────────────────────────────────────────
issue_license() {
local lic_type="$1"
info "라이선스 발급 중: $lic_type"
# GUARDiA 기동 대기
local attempt=0
until curl -sf http://localhost:8001/ -o /dev/null 2>/dev/null; do
sleep 3; ((attempt++))
[[ $attempt -ge 20 ]] && { warn "GUARDiA 미기동 — 라이선스 수동 발급 필요"; return; }
done
# 로그인하여 토큰 획득
local TOKEN
TOKEN=$(curl -sf -X POST http://localhost:8001/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"1111"}' 2>/dev/null | \
python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))" 2>/dev/null)
if [[ -z "$TOKEN" ]]; then
warn "로그인 실패 — 라이선스 수동 발급 필요"
return
fi
case "$lic_type" in
trial30|trial7)
# 체험판 발급
local days=30; [[ "$lic_type" == "trial7" ]] && days=7
local customer="GUARDiA ${days}일 체험판"
local result
result=$(curl -sf -X POST http://localhost:8001/api/license/trial \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"customer\":\"$customer\"}" 2>/dev/null)
if echo "$result" | python3 -c "import sys,json; d=json.load(sys.stdin); exit(0 if d.get('valid') else 1)" 2>/dev/null; then
local lic_key exp_date
lic_key=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('license_key',''))" 2>/dev/null)
exp_date=$(echo "$result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('expires_at','')[:10])" 2>/dev/null)
ok "체험 라이선스 발급 완료 (만료: $exp_date)"
# .env에 저장
local env_file
env_file=$(find /opt/guardia /home -name ".env" -path "*/itsm/*" 2>/dev/null | head -1)
if [[ -f "$env_file" ]]; then
grep -q "GUARDIA_LICENSE_KEY" "$env_file" && \
sed -i "s|GUARDIA_LICENSE_KEY=.*|GUARDIA_LICENSE_KEY=$lic_key|" "$env_file" || \
echo "GUARDIA_LICENSE_KEY=$lic_key" >> "$env_file"
ok "라이선스 키 .env에 저장 완료"
fi
else
warn "체험 라이선스 발급 실패 — 이미 사용한 체험판일 수 있습니다"
info "수동 발급: http://[서버IP]/license 에서 체험 시작"
fi
;;
*)
# 정식 라이선스 키 등록
local result
result=$(curl -sf -X POST http://localhost:8001/api/license/activate \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"license_key\":\"$lic_type\"}" 2>/dev/null)
if echo "$result" | python3 -c "import sys,json; d=json.load(sys.stdin); exit(0 if d.get('valid') else 1)" 2>/dev/null; then
ok "정식 라이선스 등록 완료"
else
warn "라이선스 키 등록 실패 — 키를 확인하세요"
fi
;;
esac
}
# ── 설치 완료 보고 ─────────────────────────────────────────────
print_summary() {
local server_ip
server_ip=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "localhost")
local elapsed=$(( $(date +%s) - START_TIME ))
local elapsed_min=$(( elapsed / 60 ))
echo ""
echo -e "${GREEN}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ GUARDiA ITSM 설치 완료! ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════╝${NC}"
echo ""
echo " 소요 시간: ${elapsed_min}"
echo ""
echo -e "${CYAN}접속 정보:${NC}"
echo " GUARDiA 대시보드: http://$server_ip"
echo " 초기 계정: admin / 1111"
echo " 라이선스: $LICENSE_TYPE"
echo ""
echo -e "${CYAN}서비스 현황:${NC}"
for svc in guardia-itsm tomcat9 ollama gitea nginx; do
systemctl is-active "$svc" &>/dev/null && \
echo "$svc" || \
echo " ⚠️ $svc (미실행)"
done
echo ""
echo -e "${CYAN}다음 단계:${NC}"
echo " 1. http://$server_ip 접속 → admin/1111 로그인"
echo " 2. 비밀번호 변경"
echo " 3. CMDB에 서버 등록"
echo " 4. 메신저 봇 연결 (선택)"
echo ""
echo " 검증: sudo bash $0 --test"
echo " 로그: $LOG_FILE"
echo ""
}
# ── 메인 실행 ─────────────────────────────────────────────────
main() {
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || LOG_FILE="/tmp/guardia_install.log"
echo "=== GUARDiA ITSM 자동 설치 시작: $(date) ===" > "$LOG_FILE"
# 검증 모드
if [[ "$TEST_MODE" == "true" ]]; then
run_tests; exit $?
fi
# root 확인
check_root "$@"
# OS 감지
detect_os
# 설치 시작
echo ""
echo -e "${CYAN}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ GUARDiA ITSM 자동 설치 ║${NC}"
echo -e "${CYAN}║ OS: $OS_TYPE | 라이선스: $LICENSE_TYPE${NC}"
echo -e "${CYAN}╚══════════════════════════════════════════════════╝${NC}"
echo ""
# OS별 설치 스크립트 실행
local SETUP_SCRIPT="$SCRIPT_DIR/setup_${OS_TYPE}.sh"
if [[ ! -f "$SETUP_SCRIPT" ]]; then
fail "설치 스크립트를 찾을 수 없습니다: $SETUP_SCRIPT"
fi
# 환경변수 전달
export DB_TYPE INSTALL_OLLAMA INSTALL_GITEA
[[ "$OFFLINE" == "true" ]] && export OFFLINE_PKG_DIR="$SCRIPT_DIR/offline/${OS_TYPE}"
[[ "$INSTALL_OLLAMA" == "false" ]] && export OLLAMA_INSTALL=skip
[[ "$INSTALL_GITEA" == "false" ]] && export INSTALL_GITEA=false
step "OS 설치 실행: $SETUP_SCRIPT"
bash "$SETUP_SCRIPT" 2>&1 | tee -a "$LOG_FILE"
step "라이선스 발급"
issue_license "$LICENSE_TYPE"
step "설치 검증"
run_tests || true
step "GUARDiA 자동 실행"
_auto_start
step "설치 완료"
print_summary
}
# ── GUARDiA 서비스 자동 실행 + 브라우저 열기 ──────────────────
_auto_start() {
info "GUARDiA 서비스 시작 확인 중..."
# 이미 실행 중이면 스킵, 아니면 시작
if systemctl is-active guardia-itsm &>/dev/null; then
ok "GUARDiA ITSM 이미 실행 중"
else
systemctl start guardia-itsm 2>/dev/null && ok "GUARDiA ITSM 시작" || warn "GUARDiA 시작 실패"
fi
# 연관 서비스 확인 및 시작
for svc in tomcat9 ollama gitea nginx; do
if systemctl is-enabled "$svc" &>/dev/null; then
systemctl is-active "$svc" &>/dev/null || \
{ systemctl start "$svc" 2>/dev/null && info "$svc 시작됨" || warn "$svc 시작 실패"; }
fi
done
# GUARDiA 응답 대기 (최대 60초)
info "GUARDiA 응답 대기 중..."
local attempt=0
until curl -sf http://localhost:8001/ -o /dev/null 2>/dev/null; do
sleep 3; ((attempt++))
[[ $attempt -ge 20 ]] && { warn "GUARDiA 응답 타임아웃 — 잠시 후 재확인"; return; }
done
ok "GUARDiA ITSM 정상 기동 확인!"
# 브라우저 자동 열기 (GUI 환경)
local server_ip
server_ip=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "localhost")
local url="http://${server_ip}"
if command -v xdg-open &>/dev/null 2>&1; then
xdg-open "$url" 2>/dev/null & disown
ok "브라우저 자동 열기: $url"
elif command -v open &>/dev/null 2>&1; then # macOS
open "$url" 2>/dev/null & disown
ok "브라우저 자동 열기: $url"
else
info "브라우저에서 접속하세요: $url"
fi
}
main "$@"