zioinfo-mail/setup/install_auto.sh
DESKTOP-TKLFCPR\ython 97afb8d51d feat(onboarding): 설치 후 자동 실행 가이드 챗봇 구현
[온보딩 API (routers/onboarding.py)]
- 8단계 온보딩 플로우:
  0. 환영 → 1. 비밀번호변경 → 2. 대시보드 → 3. 프로젝트등록
  → 4. 서버등록 → 5. 소스코드등록 → 6. 메신저봇 → 7. 완료
- POST /api/onboarding/message: 현재화면 + 사용자질문 → Ollama 답변
- 화면별 스포트라이트 target 정의 (CSS selector)
- 사용자별 단계 상태 영속 관리

[온보딩 챗봇 UI (static/onboarding.js)]
- 우측 고정 패널 (360px, 모바일 하단 슬라이드)
- 타이핑 애니메이션 효과 + 마크다운 렌더링
- 스포트라이트: 현재 단계 UI 요소를 하이라이트
- 화면 변화 감지 (MutationObserver + click 이벤트)
- 최소화/닫기/재시작 제어
- 사용자 질문 입력 → Ollama 실시간 답변
- 온보딩 완료 후 우측하단 ? 도움말 버튼
- 액션버튼: next/navigate/external/complete/skip

[설치 자동화 연동]
- install_auto.sh: 설치 완료 후 onboarding reset API 호출
- 브라우저 열릴 때 챗봇 자동 표시

사용자 경험:
  설치 완료 → 브라우저 자동 오픈 → 챗봇 우측 등장
  → "환영합니다!" → 비밀번호변경 화면 이동 안내
  → CMDB 서버등록 스포트라이트 → Gitea 소스등록
  → 완료 후 ? 버튼으로 재시작 가능

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

337 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 정상 기동 확인!"
# 온보딩 초기화 (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 "$@"