feat: 从黄果 NET hgdjnet-server 9bfbafe 导入 HKDJ 官网后端
来源:hgdjnet-server 9bfbafe10d417deea959bd53117bc88a10e60a83 项目身份 HKDJ / JHA-216,独立官网仓库,Jenkins 守卫键 hkdjnet 测试目录 /server/hkdj_net,App/Web API 30331/30332 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Install one HKDJ NET component; never update other Supervisor groups."""
|
||||
import configparser
|
||||
import hashlib
|
||||
import io
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
component, revision = sys.argv[1:]
|
||||
assert component in ('app', 'web') and re.fullmatch('[0-9a-f]{40}', revision)
|
||||
root = Path('/server/hkdj_net')
|
||||
incoming = root / '.incoming' / component
|
||||
binary = incoming / ('hkdj-net-' + component)
|
||||
metadata = subprocess.check_output(['strings', '-a', str(binary)], text=True)
|
||||
assert 'vcs.revision=' + revision in metadata and 'vcs.modified=false' in metadata
|
||||
assert 'hkdj-web-server/' + component in metadata
|
||||
destination = root / component
|
||||
(destination / 'conf').mkdir(parents=True, exist_ok=True)
|
||||
(root / 'logs').mkdir(exist_ok=True)
|
||||
previous = destination / binary.name
|
||||
if previous.exists():
|
||||
old_metadata = subprocess.check_output(['strings', '-a', str(previous)], text=True)
|
||||
old_revision = re.search(r'vcs.revision=([0-9a-f]{40})', old_metadata)
|
||||
assert old_revision and 'vcs.modified=false' in old_metadata
|
||||
assert 'hkdj-web-server/' + component in old_metadata
|
||||
old_checksum = hashlib.sha256(previous.read_bytes()).hexdigest()
|
||||
rollback = destination / '.rollback'
|
||||
rollback.mkdir(exist_ok=True)
|
||||
shutil.copy2(previous, rollback / (binary.name + '.' + old_revision[1] + '.' + old_checksum))
|
||||
os.chmod(binary, 0o755)
|
||||
os.replace(binary, destination / binary.name)
|
||||
os.replace(incoming / (component + '.yaml'), destination / 'conf' / (component + '.yaml'))
|
||||
if component == 'app':
|
||||
for name in ('ip2region_v4.xdb', 'ip2region_v6.xdb'):
|
||||
os.replace(incoming / name, destination / 'conf' / name)
|
||||
config = configparser.RawConfigParser()
|
||||
config.read(incoming / 'supervisor.conf')
|
||||
selected = configparser.RawConfigParser()
|
||||
name = 'hkdj_net_' + component
|
||||
selected['program:' + name] = dict(config['program:' + name])
|
||||
out = io.StringIO()
|
||||
selected.write(out)
|
||||
target = Path('/etc/supervisor/conf.d') / (name + '.conf')
|
||||
changed = not target.exists() or target.read_text() != out.getvalue()
|
||||
temporary = target.with_suffix('.pending')
|
||||
temporary.write_text(out.getvalue())
|
||||
os.replace(temporary, target)
|
||||
subprocess.run(['supervisorctl', 'reread'], check=True)
|
||||
subprocess.run(['supervisorctl', 'update', name], check=True)
|
||||
if not changed:
|
||||
subprocess.run(['supervisorctl', 'restart', name], check=True)
|
||||
for _ in range(40):
|
||||
status = subprocess.check_output(['supervisorctl', 'status', name], text=True)
|
||||
if 'RUNNING' in status:
|
||||
break
|
||||
time.sleep(1)
|
||||
else:
|
||||
raise RuntimeError('selected component did not start')
|
||||
print('installed', component, revision, hashlib.sha256((destination / binary.name).read_bytes()).hexdigest())
|
||||
Reference in New Issue
Block a user