zioinfo-mail/scripts/setup/fix_jenkins_branch_condition.py
DESKTOP-TKLFCPR\ython ea51238c1d feat(cicd): complete Jenkins pipeline - plugins, triggers, E2E verified
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 20:28:45 +09:00

155 lines
6.3 KiB
Python

"""Jenkins Jenkinsfile branch 조건 수정 + Gitea→Jenkins webhook 검증"""
import paramiko, sys, json, base64, time
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)
J = 'http://127.0.0.1:9080'
A = 'admin:Admin@2026!'
def run(label, cmd, timeout=30):
print(f'\n[{label}]')
_, o, _ = c.exec_command(cmd, timeout=timeout)
out = o.read().decode('utf-8','replace').strip()
if out: print(out[:600])
return out
# crumb
_, o, _ = c.exec_command(f'curl -sf -u "{A}" {J}/crumbIssuer/api/json 2>/dev/null', timeout=10)
try:
cd = json.loads(o.read().decode('utf-8','replace').strip())
CRUMB = f'-H "{cd["crumbRequestField"]}: {cd["crumb"]}"'
except:
CRUMB = ''
# Gitea→Jenkins webhook 동작 확인: guardia-itsm에 직접 push 트리거
run('Gitea→Jenkins 직접 webhook 트리거 테스트',
"""curl -sf -X POST 'http://127.0.0.1:9003/api/v1/repos/zio/guardia-itsm/hooks/17/tests' \
--header 'Authorization: Basic '"$(echo -n 'zio:Zio@Admin2026!' | base64)" \
2>/dev/null && echo "webhook 테스트 전송됨" || echo "FAIL"
""")
time.sleep(3)
run('Jenkins 빌드 큐 확인',
f'curl -sf -u "{A}" {J}/queue/api/json 2>/dev/null | '
'python3 -c "import sys,json; d=json.load(sys.stdin); '
'[print(i[\'task\'][\'name\'],i.get(\'why\',\'?\')) for i in d.get(\'items\',[])]" 2>/dev/null || echo "큐 비어있음"')
# Gitea webhook URL을 Gitea 플러그인 전용 URL로 업데이트
# (일반 webhook URL → /gitea-webhook/post)
print('\n[Jenkins webhook URL 확인]')
run('현재 webhook URL 목록',
"""curl -sf 'http://127.0.0.1:9003/api/v1/repos/zio/guardia-itsm/hooks' \
--header 'Authorization: Basic '"$(echo -n 'zio:Zio@Admin2026!' | base64)" \
2>/dev/null | python3 -c "
import sys,json
for h in json.load(sys.stdin):
print(h['id'], h['config'].get('url',''), 'active:', h['active'])
" 2>/dev/null""")
# Jenkins job SCM 설정에서 GIT_BRANCH 확인
run('guardia-itsm GIT_BRANCH 확인',
f'curl -sf -u "{A}" {J}/job/guardia-itsm/lastBuild/consoleText 2>/dev/null | '
"grep -i 'branch\\|GIT_BRANCH\\|BRANCH_NAME' | head -5")
# Jenkins 환경변수 주입: GIT_BRANCH를 통해 Deploy stage 활성화
# config.xml에서 when { branch 'main' } → when { expression { scm 관련 } } 로 변경하는 대신
# Jenkins job에 파라미터로 BRANCH=main 주입
print('\n[Jenkinsfile branch 조건 수정 - Gitea API로 업데이트]')
import base64 as b64
JENKINSFILE_ITSM = """pipeline {
agent any
environment {
APP = '/opt/guardia/app'
VENV = '/opt/guardia/venv'
NOTIFY = "http://127.0.0.1:9001/api/messenger/webhook"
}
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
timeout(time: 15, unit: 'MINUTES')
timestamps()
}
stages {
stage('Checkout') { steps { checkout scm } }
stage('Install') {
steps { sh "${VENV}/bin/pip install -r requirements.txt -q" }
}
stage('Test') {
when { expression { fileExists('tests/') } }
steps {
sh "${VENV}/bin/pytest tests/ -q --tb=short --junitxml=test-results.xml || true"
junit allowEmptyResults: true, testResults: 'test-results.xml'
}
}
stage('Deploy') {
when {
expression {
return env.GIT_BRANCH == 'main' || env.GIT_BRANCH == 'origin/main' || env.BRANCH_NAME == 'main'
}
}
steps {
sh """
rsync -a --exclude=__pycache__ --exclude=.git \\
--exclude=rpa_rules.json --exclude='*.pyc' \\
. ${APP}/
systemctl restart guardia
sleep 4
systemctl is-active guardia || exit 1
"""
}
}
}
post {
success { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\\"event\\":\\"build_result\\",\\"room\\":\\"ops\\",\\"success\\":true,\\"result_summary\\":\\"✅ guardia-itsm 배포 완료 #${BUILD_NUMBER}\\"}' 2>/dev/null || true" }
failure { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\\"event\\":\\"build_result\\",\\"room\\":\\"ops\\",\\"success\\":false,\\"result_summary\\":\\"❌ guardia-itsm 빌드 실패 #${BUILD_NUMBER}\\"}' 2>/dev/null || true" }
}
}"""
# NOTIFY URL을 9001로 수정한 버전으로 5개 모두 업데이트
REPOS_FIX = {
'guardia-itsm': JENKINSFILE_ITSM,
}
sftp = c.open_sftp()
for repo, content in REPOS_FIX.items():
encoded = b64.b64encode(content.encode('utf-8')).decode()
# SHA 확인
_, o, _ = c.exec_command(
f'curl -sf "http://127.0.0.1:9003/api/v1/repos/zio/{repo}/contents/Jenkinsfile" '
'--header "Authorization: Basic '"$(echo -n 'zio:Zio@Admin2026!' | base64)"'" 2>/dev/null | '
'python3 -c "import sys,json; print(json.load(sys.stdin)[\'sha\'])" 2>/dev/null', timeout=10)
sha = o.read().decode('utf-8','replace').strip()
payload = json.dumps({
"message": "ci: fix branch condition + ITSM notify URL",
"content": encoded,
"sha": sha,
"branch": "main"
})
with sftp.open(f'/tmp/jf_{repo}_fix.json', 'w') as f:
f.write(payload)
run(f'Jenkinsfile 업데이트 {repo}',
f'curl -sf -X PUT "http://127.0.0.1:9003/api/v1/repos/zio/{repo}/contents/Jenkinsfile" '
'--header "Authorization: Basic '"$(echo -n 'zio:Zio@Admin2026!' | base64)"'" '
'--header "Content-Type: application/json" '
f'--data @/tmp/jf_{repo}_fix.json 2>/dev/null | '
'python3 -c "import sys,json; d=json.load(sys.stdin); print(\'OK:\', d.get(\'content\',{}).get(\'name\',\'?\'))" 2>/dev/null || echo FAIL')
sftp.close()
# 빌드 재트리거
time.sleep(2)
run('guardia-itsm 빌드 재트리거',
f'curl -sf -X POST -u "{A}" {CRUMB} {J}/job/guardia-itsm/build 2>/dev/null && echo "트리거됨"')
time.sleep(15)
run('빌드 #3 콘솔 로그 (Deploy 스테이지)',
f'curl -sf -u "{A}" {J}/job/guardia-itsm/lastBuild/consoleText 2>/dev/null | '
"grep -A3 'Deploy\\|GIT_BRANCH\\|BRANCH\\|skipped\\|SUCCESS\\|FAILURE' | head -20")
c.close()
print('\n=== 완료 ===')