#!/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 : 정식 라이선스 키 # --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 정상 기동 확인!" # 온보딩 초기화 (admin 계정 기준으로 온보딩 상태 리셋) curl -sf -X POST http://localhost:8001/api/onboarding/reset \ -H "Authorization: Bearer $(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)" \ -o /dev/null 2>/dev/null && info "온보딩 가이드 활성화 완료" || true # 브라우저 자동 열기 (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 "$@"