zioinfo-mail/skills/guardia-deploy/SKILL.md
DESKTOP-TKLFCPR\ython e228faabf5 feat(itsm): G-1~G-12 확장 기능 + 하네스/봇/설치스크립트 구현
G-1: 메신저 Webhook Relay + _send_to_room 실제 httpx 호출 구현
G-2: POST /api/tasks/bulk SR 대량작업 엔드포인트 (최대 100건)
G-3: 라이선스 만료 알림 스케줄러 (매일 09:00 KST)
G-4: 체험판 upgrade_banner 필드 + license.py 배너 로직
G-5: core/auto_rca.py + incidents/problem auto-rca 엔드포인트
G-6: core/deploy_impact.py + vibe impact-analysis 엔드포인트
G-7: core/ticket_classifier.py + SR 생성 시 AI 분류 + ai-suggestion API
G-8: VulnPatchRecord 모델 + vuln_scan 패치추적 4개 엔드포인트
G-9: core/jira_sync.py + gateway Jira/Confluence 연동 엔드포인트
G-10: core/push_notify.py + routers/push.py + PushSubscription 모델
G-11: approvals 다중승인 (위임/서명/기한초과/마감연장)
G-12: alembic.ini + migrations/ + cicd/migrate_to_postgres.sh

하네스: guardia-orchestrator 확장기능 Phase 반영
봇명령어: /sr /status /license /bulk 슬래시 명령어 추가
설치스크립트: setup/ (Ubuntu, CentOS, RHEL, Windows) --test 옵션 포함

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:52 +09:00

113 lines
3.6 KiB
Markdown

---
name: guardia-deploy
description: >
GUARDiA 프로젝트에서 SSH/SFTP 기반 에이전트리스 배포 엔진 코드를 작성하거나
수정할 때 사용하는 스킬. 다음 경우에 반드시 먼저 읽어라:
- paramiko 관련 코드 작성/수정
- 롤링 배포 로직 구현
- 헬스체크 / 롤백 로직 작성
- 배포 파이프라인 API 엔드포인트 작성
- 파일 무결성(MD5/SHA-256) 검증 코드
---
# GUARDiA 배포 엔진 스킬
## 핵심 원칙
1. **백업 우선**: 배포 전 반드시 타임스탬프 포함 백업 (`app.jar.bak_YYYYMMDD_HHMMSS`)
2. **무결성 검증**: SFTP 전송 후 MD5 로컬 vs 원격 비교 필수
3. **헬스체크 강제**: 재기동 후 30초 이내 HTTP 200 미확인 시 즉시 롤백
4. **롤링 배포**: WAS #1 완료·검증 후 WAS #2 시작 (동시 배포 금지)
5. **감사 로그**: 성공/실패 모두 `log_execution()` 호출 필수
## 환경 변수
```python
SSH_TIMEOUT = 300 # SSH 명령 실행 타임아웃 (초)
HEALTH_TIMEOUT = 30 # 헬스체크 최대 대기 (초)
HEALTH_INTERVAL = 2 # 헬스체크 폴링 간격 (초)
DISK_THRESHOLD = 90 # 배포 전 디스크 임계치 (%)
MAX_BATCH_SIZE = 50 # 티어2 병렬 배포 단위
```
## 금지 사항
- root 계정으로 SSH 접속 금지 → opsagent + sudoers 사용
- `rm -rf`, `mkfs`, `format`, `drop table` 등 Blacklist 명령 차단
- 자격증명(비밀번호) 로그 출력 금지
- 헬스체크 없이 다음 노드 진행 금지
- 라이선스 미등록/만료 상태에서 CICD 기능 실행 금지 (ENTERPRISE 에디션 전용)
## 코드 패턴
### SSH 실행
```python
result = executor.execute_command("sh /app/scripts/startup.sh")
if result["exit_code"] != 0:
raise DeploymentError(f"startup 실패: {result['stderr']}")
```
### 파일 전송 + 무결성
```python
remote_md5 = executor.upload_file(local_path, remote_path)
local_md5 = hashlib.md5(open(local_path, 'rb').read()).hexdigest()
assert local_md5 == remote_md5, "MD5 불일치"
```
### 헬스체크
```python
deadline = time.time() + HEALTH_TIMEOUT
while time.time() < deadline:
try:
r = requests.get(f"http://{ip}:8080", timeout=3)
if r.status_code == 200:
return True
except:
pass
time.sleep(HEALTH_INTERVAL)
return False # 실패 → 즉시 rollback 트리거
```
## 에러 처리 표준
```python
try:
# 배포 로직
except DeploymentError as e:
self._rollback(executor, node, backup_ts)
log_execution(sr_id, node["ip"], "DEPLOY_FAILED", 1, str(e))
messenger.notify_failure(sr_id, str(e))
return False
finally:
executor.close()
```
## 정적 vs 동적 자원 판별
```python
STATIC_EXTENSIONS = {".html", ".js", ".css", ".png", ".jpg", ".gif", ".svg"}
DYNAMIC_EXTENSIONS = {".class", ".jar", ".war", ".properties"}
def requires_restart(filename: str) -> bool:
ext = Path(filename).suffix.lower()
return ext in DYNAMIC_EXTENSIONS
```
## 라이선스 확인
CICD/배포 기능은 ENTERPRISE 에디션 전용이다. 배포 시작 전 라이선스를 검증한다:
```python
from routers.license import get_license_status
async def verify_license_for_deploy(db):
status = await get_license_status(db)
if not status.get("valid"):
raise DeploymentError(f"라이선스 오류: {status.get('message', '미등록')}")
features = (status.get("limits") or {}).get("features", [])
if "CICD" not in features:
raise DeploymentError(
f"CICD 기능은 ENTERPRISE 에디션에서만 사용 가능합니다 (현재: {status.get('edition')})"
)
```