"""Jenkins 최종 설정: Gitea 직접 트리거 + config 업데이트"""
import paramiko, sys, json, 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)
sftp = c.open_sftp()
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
_, 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())
CH = f'{cd["crumbRequestField"]}: {cd["crumb"]}'
except:
CH = 'Jenkins-Crumb: x'
REPOS = ['guardia-itsm', 'zioinfo-web', 'guardia-manager', 'guardia-messenger', 'guardia-docs']
# 1. config.xml 업데이트: triggers 추가 (올바른 URL: /job/{name}/config.xml)
print('[Jenkins job config.xml Gitea trigger 추가]')
for repo in REPOS:
_, o, _ = c.exec_command(f'curl -sf -u "{A}" {J}/job/{repo}/config.xml 2>/dev/null', timeout=10)
config = o.read().decode('utf-8','replace')
if not config or 'xml' not in config[:50]:
print(f' {repo}: config 가져오기 실패')
continue
modified = False
if '' in config:
config = config.replace('',
''
''
''
''
'')
modified = True
if modified:
with sftp.open(f'/tmp/{repo}_config.xml', 'w') as f:
f.write(config)
# 올바른 엔드포인트: POST /job/{name}/config.xml
_, o, e = c.exec_command(
f'curl -sf -X POST -u "{A}" '
f'-H "{CH}" '
f'-H "Content-Type: text/xml" '
f'--data-binary @/tmp/{repo}_config.xml '
f'"{J}/job/{repo}/config.xml" 2>/dev/null; echo $?', timeout=15)
result = o.read().decode('utf-8','replace').strip()
print(f' {repo}: {"OK" if result == "0" else f"exit={result}"}')
else:
print(f' {repo}: 이미 trigger 있음')
# 2. Gitea webhook → Jenkins: URL을 /job/{name}/build?token=... 방식으로 변경
# (Gitea plugin webhook이 안 되므로 build token 방식 사용)
print('\n[Gitea webhook URL을 build token 방식으로 업데이트]')
# Jenkins job에 빌드 token 설정 (Groovy)
TOKEN = 'gitea-auto-build-2026'
groovy_token = '\n'.join([
'import jenkins.model.*',
'import org.jenkinsci.plugins.workflow.job.properties.*',
f'def token = "{TOKEN}"',
'def repos = ["guardia-itsm","zioinfo-web","guardia-manager","guardia-messenger","guardia-docs"]',
'repos.each { name ->',
' def job = Jenkins.instance.getItem(name)',
' if (!job) { println "NOT FOUND: ${name}"; return }',
' def prop = new org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty([])',
' // Set auth token for remote trigger',
' job.setAuthToken(token)',
' job.save()',
' println "Set token for: ${name}"',
'}',
])
with sftp.open('/tmp/set_token.groovy', 'w') as f:
f.write(groovy_token)
run('build token 설정',
f'curl -sf -X POST "{J}/scriptText" -u "{A}" '
f'-H "{CH}" --data-urlencode "script@/tmp/set_token.groovy" 2>/dev/null')
# 3. Gitea webhook URL 업데이트: /job/{name}/build?token=...
HOOK_IDS = {'zioinfo-web':16,'guardia-itsm':17,'guardia-manager':18,'guardia-messenger':19,'guardia-docs':20}
for repo, hid in HOOK_IDS.items():
payload = json.dumps({
"config": {
"url": f"http://127.0.0.1:9080/job/{repo}/build?token={TOKEN}",
"content_type": "json"
},
"active": True, "events": ["push"]
})
with sftp.open(f'/tmp/hook_{repo}.json', 'w') as f:
f.write(payload)
run(f'webhook URL 업데이트 {repo}',
f"curl -sf -X PATCH 'http://127.0.0.1:9003/api/v1/repos/zio/{repo}/hooks/{hid}' "
"--header 'Authorization: Basic $(echo -n zio:Zio@Admin2026! | base64)' "
"--header 'Content-Type: application/json' "
f"--data @/tmp/hook_{repo}.json 2>/dev/null | "
"python3 -c \"import sys,json; h=json.load(sys.stdin); print('URL:', h['config'].get('url'))\" 2>/dev/null")
# 4. E2E 최종 검증: Gitea webhook → Jenkins 직접 트리거
time.sleep(2)
run('Gitea webhook 직접 테스트 (guardia-itsm)',
"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(8)
run('Jenkins 빌드 결과',
f'curl -sf -u "{A}" {J}/job/guardia-itsm/api/json 2>/dev/null | '
"python3 -c \"import sys,json; d=json.load(sys.stdin); "
"print('lastBuild #'+str(d['lastBuild']['number']), 'nextBuild:', d['nextBuildNumber'])\" 2>/dev/null")
run('최종 전체 job 상태',
f'curl -sf -u "{A}" {J}/api/json 2>/dev/null | '
"python3 -c \"import sys,json; [print(j['name'].ljust(22), j['color']) for j in json.load(sys.stdin)['jobs']]\" 2>/dev/null")
sftp.close()
c.close()
print('\n=== 완료 ===')