#!/usr/bin/env python3 """Gitea 웹훅 + Jenkins CI/CD 완전 자동화 설정""" import paramiko, time, sys, json HOST = '101.79.17.164'; USER = 'root'; PASS = '1q2w3e!Q' GITEA_USER = 'zio'; GITEA_PASS = 'Zio@Admin2026!' client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(HOST, username=USER, password=PASS, timeout=15) sftp = client.open_sftp() def run(label, cmd, timeout=30): print(f'\n[{label}]') chan = client.get_transport().open_session() chan.set_combine_stderr(True) chan.exec_command(cmd) start = time.time() while not chan.exit_status_ready(): if chan.recv_ready(): sys.stdout.buffer.write(chan.recv(4096)); sys.stdout.flush() if time.time() - start > timeout: break time.sleep(0.2) while chan.recv_ready(): sys.stdout.buffer.write(chan.recv(4096)) sys.stdout.flush() rc = chan.recv_exit_status() print(f'exit={rc}'); return rc # 1. Jenkins 초기 설정 스킵 & 보안 완화 (로컬 전용) run('Jenkins 초기설정 스킵', 'echo 2 > /var/lib/jenkins/jenkins.install.UpgradeWizard.state && ' 'chown jenkins:jenkins /var/lib/jenkins/jenkins.install.UpgradeWizard.state') # Jenkins가 CSRF 없이 트리거 허용하도록 설정 (내부망 전용) jenkins_config_groovy = """ import jenkins.model.* import hudson.security.* def instance = Jenkins.getInstance() // CSRF 설정 완화 (내부망 전용) instance.setCrumbIssuer(null) instance.save() println "CSRF disabled for internal CI/CD" """ with sftp.open('/var/lib/jenkins/init.groovy.d/disable_csrf.groovy', 'w') as f: f.write(jenkins_config_groovy) run('권한 설정', 'chown -R jenkins:jenkins /var/lib/jenkins/init.groovy.d && systemctl restart jenkins && sleep 8 && systemctl is-active jenkins') # 2. Jenkins 빌드 트리거 (CSRF 비활성화 후) chan = client.get_transport().open_session() chan.exec_command('cat /var/lib/jenkins/secrets/initialAdminPassword') jenkins_pw = chan.makefile().read().decode().strip() chan.recv_exit_status() trigger_script = f"""#!/usr/bin/env python3 import urllib.request, base64, time PW = '{jenkins_pw}' cred = base64.b64encode(f'admin:{{PW}}'.encode()).decode() headers = {{'Authorization': f'Basic {{cred}}'}} for attempt in range(5): try: req = urllib.request.Request( 'http://localhost:8080/job/zioinfo-web/build', data=b'', headers=headers) resp = urllib.request.urlopen(req, timeout=10) print(f'빌드 트리거 성공 HTTP {{resp.status}}') break except Exception as e: print(f'시도 {{attempt+1}}: {{e}}') time.sleep(3) """ with sftp.open('/tmp/trigger.py', 'w') as f: f.write(trigger_script) run('Jenkins 빌드 트리거', 'python3 /tmp/trigger.py') # 3. Gitea 웹훅 확인 / 재설정 (Jenkins 빌드 URL로) run('Gitea 웹훅 목록 확인', 'curl -s http://localhost:3000/api/v1/repos/zio/zioinfo-web/hooks ' '-u "zio:Zio@Admin2026!" | python3 -c "import json,sys; ' 'hooks=json.load(sys.stdin); ' '[print(h[chr(105)+chr(100)], h[chr(99)+chr(111)+chr(110)+chr(102)+chr(105)+chr(103)][chr(117)+chr(114)+chr(108)]) for h in hooks]"') # 웹훅을 Jenkins 빌드 직접 트리거 URL로 교체 run('Gitea 웹훅 업데이트', f'curl -s -X DELETE http://localhost:3000/api/v1/repos/zio/zioinfo-web/hooks/1 ' f'-u "{GITEA_USER}:{GITEA_PASS}" && ' f'curl -s -X DELETE http://localhost:3000/api/v1/repos/zio/zioinfo-web/hooks/2 ' f'-u "{GITEA_USER}:{GITEA_PASS}" && ' f'curl -s -X POST http://localhost:3000/api/v1/repos/zio/zioinfo-web/hooks ' f'-H "Content-Type: application/json" ' f'-u "{GITEA_USER}:{GITEA_PASS}" ' f'-d \'{{"type":"gitea","active":true,' f'"config":{{"url":"http://admin:{jenkins_pw}@localhost:8080/job/zioinfo-web/build",' f'"content_type":"json"}},' f'"events":["push"]}}\' | ' f'python3 -c "import json,sys; d=json.load(sys.stdin); print(chr(87)+chr(101)+chr(98)+chr(104)+chr(111)+chr(111)+chr(107)+chr(32)+chr(73)+chr(68)+chr(58), d.get(chr(105)+chr(100)))"') sftp.close() client.close() print('\nCI/CD 설정 완료!') print(f'Jenkins: http://{HOST}:8080 (초기PW: {jenkins_pw})') print(f'Gitea: http://{HOST}:3000 (zio / Zio@Admin2026!)') print(f'홈페이지: http://{HOST}') print(f'관리자: http://{HOST}/admin')