"""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=== 완료 ===')