[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>
330 lines
13 KiB
Bash
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 "$@"
|