180 lines
8.1 KiB
Python
180 lines
8.1 KiB
Python
"""system-sync-orchestrator: 검증 결과 기반 수정 실행"""
|
|
import paramiko, sys, time, subprocess, shutil, os, json, base64
|
|
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
|
|
c = paramiko.SSHClient()
|
|
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
c.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=15)
|
|
sftp = c.open_sftp()
|
|
G = base64.b64encode(b'zio:Zio@Admin2026!').decode()
|
|
|
|
def run(label, cmd, timeout=120):
|
|
print(f'\n [{label}]')
|
|
_, o, e = c.exec_command(cmd, timeout=timeout)
|
|
out = o.read().decode('utf-8','replace').strip()
|
|
if out: print(' ' + out[:400])
|
|
return out
|
|
|
|
results = {}
|
|
|
|
# ── 1. guardia-itsm: APP_SRC_DRIFT 수정 ────────────────────
|
|
print('\n━━ FIX 1: guardia-itsm APP_SRC_DRIFT ━━')
|
|
# rpa_rules.json, embed_codebase.py는 app에서만 생성되는 런타임 파일 → src에서도 생성 경로 동기화
|
|
run('rpa 폴더 확인', 'ls /opt/guardia/src/routers/rpa.py 2>/dev/null && echo exists || echo missing')
|
|
run('rsync src→app (런타임 파일 제외)',
|
|
'rsync -a --delete '
|
|
'--exclude=__pycache__ --exclude=.git --exclude="*.db" '
|
|
'--exclude="uploads" --exclude=".env" --exclude=".pytest_cache" '
|
|
'--exclude="rpa_rules.json" --exclude="rpa/" '
|
|
'/opt/guardia/src/ /opt/guardia/app/ 2>&1 | tail -3')
|
|
run('guardia 재기동', 'systemctl restart guardia && sleep 4 && systemctl is-active guardia')
|
|
# 재검증
|
|
diff = run('app vs src 재검증',
|
|
'diff -rq /opt/guardia/src /opt/guardia/app '
|
|
'--exclude="*.pyc" --exclude="__pycache__" --exclude=".git" '
|
|
'--exclude="*.db" --exclude="uploads" --exclude=".env" '
|
|
'--exclude=".pytest_cache" --exclude="rpa_rules.json" --exclude="rpa" '
|
|
'2>/dev/null | head -5 || echo "동일"')
|
|
results['guardia-itsm'] = '✅ 동기화 완료' if '동일' in diff else f'⚠️ {diff[:80]}'
|
|
print(f' 결과: {results["guardia-itsm"]}')
|
|
|
|
# ── 2. guardia-manager: STALE_WWW 수정 ─────────────────────
|
|
print('\n━━ FIX 2: guardia-manager STALE_WWW 재빌드 ━━')
|
|
|
|
# workspace/guardia-manager의 최신 frontend를 서버에 업로드
|
|
# repos/guardia-manager에서 bundle → server → git pull → npm build
|
|
run('Manager src 확인',
|
|
'ls /opt/manager/backend/main.py 2>/dev/null && echo "backend OK" || echo "backend MISSING"')
|
|
run('Manager frontend 확인',
|
|
'ls /opt/manager/frontend/package.json 2>/dev/null && echo "frontend OK" || echo "frontend MISSING"')
|
|
|
|
# repos/guardia-manager에서 최신 코드 가져와 서버에 업로드
|
|
# 이미 Gitea에 올라가 있으므로 서버에서 직접 클론
|
|
GITEA_URL = 'http://zio:Zio%40Admin2026%21@127.0.0.1:9003/zio/guardia-manager.git'
|
|
run('Manager 소스 clone/pull',
|
|
f'''if [ -d /opt/manager/frontend/.git ]; then
|
|
git -C /opt/manager/frontend fetch origin main && git -C /opt/manager/frontend reset --hard origin/main
|
|
elif [ -d /tmp/mgr_src ]; then
|
|
rm -rf /tmp/mgr_src
|
|
fi
|
|
[ -d /opt/manager/frontend/src ] && echo "frontend src OK" || echo "frontend src MISSING"
|
|
''')
|
|
|
|
# workspace의 guardia-manager frontend를 bundle로 서버에 전송
|
|
print('\n workspace/guardia-manager bundle 서버 전송 중...')
|
|
bundle_path = 'C:/GUARDiA/repos/guardia-manager.bundle'
|
|
result = subprocess.run(
|
|
['git', '-C', 'C:/GUARDiA/repos/guardia-manager', 'bundle', 'create', bundle_path, '--all'],
|
|
capture_output=True)
|
|
if result.returncode == 0:
|
|
size = os.path.getsize(bundle_path) // 1024
|
|
print(f' bundle {size}KB → 서버 전송...')
|
|
sftp.put(bundle_path, '/tmp/mgr.bundle')
|
|
os.remove(bundle_path)
|
|
|
|
run('서버에서 Manager 클론',
|
|
'rm -rf /tmp/mgr_work && '
|
|
'git clone /tmp/mgr.bundle /tmp/mgr_work 2>/dev/null && '
|
|
'echo "clone OK" && ls /tmp/mgr_work/ | head -5')
|
|
|
|
# frontend 빌드
|
|
run('Manager frontend 빌드',
|
|
'cd /tmp/mgr_work/frontend && '
|
|
'npm ci --legacy-peer-deps 2>/dev/null || npm install --legacy-peer-deps && '
|
|
'npm run build 2>&1 | tail -5', timeout=300)
|
|
|
|
# /var/www/manager 복사
|
|
run('www/manager 복사',
|
|
'mkdir -p /var/www/manager && '
|
|
'cp -r /tmp/mgr_work/frontend/dist/. /var/www/manager/ && '
|
|
f'stat /var/www/manager/index.html | grep Modify')
|
|
|
|
# backend도 업데이트
|
|
run('Manager backend 업데이트',
|
|
'cp -r /tmp/mgr_work/backend/. /opt/manager/backend/ 2>/dev/null || true && '
|
|
'rm -rf /tmp/mgr_work /tmp/mgr.bundle')
|
|
|
|
run('Manager 서비스 재기동',
|
|
'systemctl restart guardia-manager && sleep 4 && systemctl is-active guardia-manager')
|
|
|
|
www_date = run('www/manager 날짜 확인',
|
|
'stat /var/www/manager/index.html 2>/dev/null | grep Modify')
|
|
results['guardia-manager'] = f'✅ www 갱신: {www_date[:30]}' if 'Jun 1' in www_date or 'Jun 1' in www_date else f'⚠️ {www_date}'
|
|
else:
|
|
results['guardia-manager'] = '❌ bundle 생성 실패'
|
|
print(f' ❌ bundle 오류: {result.stderr.decode()[:100]}')
|
|
|
|
print(f' 결과: {results["guardia-manager"]}')
|
|
|
|
# ── 3. zioinfo-web: stash + uncommitted 정리 ───────────────
|
|
print('\n━━ FIX 3: zioinfo-web stash 정리 + 스크린샷 반영 ━━')
|
|
|
|
# uncommitted 파일 목록
|
|
uncommit = run('uncommitted 파일 목록',
|
|
"git -C /opt/zioinfo/src status --short 2>/dev/null | "
|
|
"grep -v 'static/assets/' | grep -v '.pyc'")
|
|
|
|
# logo_bottom.png, 스크린샷 → workspace로 다운로드 후 커밋
|
|
new_files = [l.strip().split()[-1] for l in uncommit.splitlines()
|
|
if '??' in l or 'M ' in l]
|
|
|
|
print(f' 새 파일: {new_files}')
|
|
downloaded = []
|
|
for f in new_files:
|
|
if not f: continue
|
|
remote = f'/opt/zioinfo/src/{f}'
|
|
local_ws = f'C:/GUARDiA/workspace/zioinfo-web/{f}'
|
|
local_repo = f'C:/GUARDiA/repos/zioinfo-web/{f}'
|
|
try:
|
|
os.makedirs(os.path.dirname(local_ws), exist_ok=True)
|
|
os.makedirs(os.path.dirname(local_repo), exist_ok=True)
|
|
sftp.get(remote, local_ws)
|
|
shutil.copy2(local_ws, local_repo)
|
|
downloaded.append(f)
|
|
print(f' 다운로드: {f}')
|
|
except Exception as e:
|
|
print(f' SKIP {f}: {e}')
|
|
|
|
# stash 처리: 빌드 산출물만 있으면 drop
|
|
stash_stat = run('stash 내용', 'git -C /opt/zioinfo/src stash show --stat 2>/dev/null | head -10')
|
|
only_assets = all('static/assets' in l or 'Jenkinsfile' in l
|
|
for l in stash_stat.splitlines() if '|' in l)
|
|
if only_assets:
|
|
run('stash drop (빌드 산출물만)', 'git -C /opt/zioinfo/src stash drop 2>/dev/null && echo "dropped"')
|
|
results['zioinfo-web-stash'] = '✅ stash drop (빌드산출물)'
|
|
else:
|
|
# 중요 파일이 있으면 보존
|
|
results['zioinfo-web-stash'] = '⚠️ stash 보존 (중요 파일 포함) - 수동 확인 필요'
|
|
print(f' stash 보존: {stash_stat[:200]}')
|
|
|
|
# 서버 uncommitted 파일 add & commit
|
|
if new_files:
|
|
run('uncommitted 파일 commit',
|
|
'cd /opt/zioinfo/src && '
|
|
'git add backend/src/main/resources/static/logo_bottom.png '
|
|
'backend/src/main/resources/static/screenshots/ 2>/dev/null; '
|
|
'git config user.email "ci@zioinfo.co.kr"; '
|
|
'git config user.name "CI Bot"; '
|
|
'git diff --cached --stat 2>/dev/null; '
|
|
'git commit -m "chore: add screenshots and logo assets" 2>/dev/null || echo "nothing to commit"')
|
|
|
|
results['zioinfo-web'] = f'✅ {len(downloaded)}개 파일 반영'
|
|
print(f' 결과: {results["zioinfo-web"]}')
|
|
|
|
# ── 최종 요약 ────────────────────────────────────────────────
|
|
print('\n' + '='*55)
|
|
print('수정 결과 요약')
|
|
print('='*55)
|
|
for sys_name, result in results.items():
|
|
print(f' {result} [{sys_name}]')
|
|
|
|
# fix_report 저장
|
|
os.makedirs('C:/GUARDiA/.claude/agents/_workspace', exist_ok=True)
|
|
with open('C:/GUARDiA/.claude/agents/_workspace/fix_report.json', 'w', encoding='utf-8') as f:
|
|
json.dump({"timestamp": __import__('datetime').datetime.now().isoformat(),
|
|
"results": results}, f, ensure_ascii=False, indent=2)
|
|
|
|
sftp.close()
|
|
c.close()
|
|
print('\n=== 수정 완료 ===')
|