fix(deploy): 兼容旧配置迁移并支持固定版本验收
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Real Git/config adoption regression; container mutation is not used here."""
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
source = Path(__file__).resolve().parent.parent
|
||||
started = time.monotonic()
|
||||
|
||||
|
||||
def run(args, root, env=None):
|
||||
return subprocess.run(args, cwd=root, env=env, capture_output=True, text=True, timeout=30)
|
||||
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix='easyai-legacy-update-') as directory:
|
||||
base = Path(directory)
|
||||
root = base / 'easyai'
|
||||
root.mkdir()
|
||||
(root / 'docker-compose.yml').write_text('services:\n easyai-server:\n image: server:old\n environment:\n - EXISTING=keep\n watchtower:\n image: watcher:old\n')
|
||||
(root / '.gitignore').write_text('.env\ndata/\n')
|
||||
(root / '.env').write_text('VERSION=old\nCONFIG_JWT_SECRET=keep-this-private-key\n')
|
||||
for args in [['git','init','-q'], ['git','config','user.name','Update test'], ['git','config','user.email','test@example.invalid'], ['git','add','.'], ['git','commit','-qm','test: 旧部署基准']]:
|
||||
assert run(args, root).returncode == 0
|
||||
remote = base / 'remote.git'
|
||||
seed = base / 'seed'
|
||||
assert run(['git','clone','-q','--bare',str(root),str(remote)], base).returncode == 0
|
||||
assert run(['git','remote','add','origin',str(remote)], root).returncode == 0
|
||||
assert run(['git','fetch','-q'],root).returncode == 0
|
||||
branch = run(['git','branch','--show-current'], root).stdout.strip()
|
||||
assert run(['git','branch','--set-upstream-to','origin/'+branch],root).returncode == 0
|
||||
assert run(['git','clone','-q',str(remote),str(seed)],base).returncode == 0
|
||||
(seed / 'docker-compose.yml').write_text('''services:
|
||||
easyai-server:
|
||||
image: server:new
|
||||
environment:
|
||||
- EXISTING=keep
|
||||
- MODEL_CONVERSION_WORKER_TOKEN=${MODEL_CONVERSION_WORKER_TOKEN}
|
||||
watchtower:
|
||||
image: watcher:new
|
||||
easyai-updater:
|
||||
image: updater:new
|
||||
environment:
|
||||
- UPDATE_MANIFEST_FILE=/etc/manifest.json
|
||||
volumes:
|
||||
- ./data/update-state:/state
|
||||
- ./system-update/release-manifest.json:/etc/manifest.json:ro
|
||||
networks:
|
||||
easyai:
|
||||
ipv4_address: 172.21.0.31
|
||||
model-conversion-worker:
|
||||
image: worker:new
|
||||
networks:
|
||||
easyai: {}
|
||||
''')
|
||||
(seed / 'scripts').mkdir()
|
||||
(seed / 'scripts/init-security-env.sh').write_text('# modern security initializer\n')
|
||||
(seed / 'demo.example.conf').write_text('# upstream example\n')
|
||||
for args in [['git','config','user.name','Update test'],['git','config','user.email','test@example.invalid'],['git','add','.'],['git','commit','-qm','test: 新增转换服务与独立更新地址'],['git','push','-q']]:
|
||||
assert run(args,seed).returncode == 0
|
||||
with (root / 'docker-compose.yml').open('a') as stream:
|
||||
stream.write(''' easyai-updater:
|
||||
image: updater:new
|
||||
environment:
|
||||
- UPDATE_MANIFEST_FILE=/state/custom.json
|
||||
volumes:
|
||||
- ./data/update-state:/state
|
||||
networks:
|
||||
- easyai
|
||||
''')
|
||||
(root / 'scripts').mkdir()
|
||||
(root / 'scripts/init-security-env.sh').write_text('# local legacy initializer\n')
|
||||
(root / 'demo.example.conf').write_text('# custom nginx source; active copy elsewhere\n')
|
||||
original = (root / 'docker-compose.yml').read_bytes()
|
||||
bins = base / 'bin'
|
||||
bins.mkdir()
|
||||
docker = bins / 'docker'
|
||||
docker.write_text('#!/bin/sh\nexit 0\n')
|
||||
docker.chmod(0o755)
|
||||
env = {**os.environ, 'PATH': str(bins)+os.pathsep+os.environ['PATH']}
|
||||
legacy = run(['git','pull','--ff-only'],root)
|
||||
assert legacy.returncode != 0 and 'would be overwritten' in legacy.stderr
|
||||
assert original == (root / 'docker-compose.yml').read_bytes()
|
||||
(root / 'business.js').write_text('local business code\n')
|
||||
assert run(['git','add','business.js'],root).returncode == 0
|
||||
rejected = run(['python3',str(source/'scripts/prepare-update-repository.py'),str(root)],root,env)
|
||||
assert rejected.returncode != 0
|
||||
assert original == (root / 'docker-compose.yml').read_bytes()
|
||||
assert run(['git','reset','-q','HEAD','--','business.js'],root).returncode == 0
|
||||
accepted = run(['python3',str(source/'scripts/prepare-update-repository.py'),str(root)],root,env)
|
||||
assert accepted.returncode == 0, accepted.stdout+accepted.stderr
|
||||
assert run(['git','pull','--ff-only'],root).returncode == 0
|
||||
assert run(['git','diff','--name-only'],root).stdout == ''
|
||||
override=json.loads((root/'data/deployment-config/legacy-compose.json').read_text())
|
||||
assert override == {'services': {'easyai-updater': {'environment': {'UPDATE_MANIFEST_FILE': '/state/custom.json'}}}}, override
|
||||
assert 'COMPOSE_FILE=docker-compose.yml:data/deployment-config/legacy-compose.json' in (root/'.env').read_text()
|
||||
assert 'CONFIG_JWT_SECRET=keep-this-private-key' in (root/'.env').read_text()
|
||||
backups=list((root/'data/deployment-backups').glob('legacy-update-*'))
|
||||
assert len(backups)==1
|
||||
assert (backups[0]/'docker-compose.yml').read_bytes()==original
|
||||
assert (backups[0]/'demo.example.conf').read_text().startswith('# custom nginx')
|
||||
assert (backups[0]/'.env').stat().st_mode & 0o077 == 0
|
||||
assert (backups[0]).stat().st_mode & 0o077 == 0
|
||||
resolved=run(['docker','compose','--env-file','.env','config','--format','json'],root)
|
||||
assert resolved.returncode==0,resolved.stderr
|
||||
config=json.loads(resolved.stdout)
|
||||
assert config['services']['easyai-updater']['networks']['easyai']['ipv4_address']=='172.21.0.31'
|
||||
assert config['services']['easyai-updater']['environment']['UPDATE_MANIFEST_FILE']=='/state/custom.json'
|
||||
assert 'model-conversion-worker' in config['services']
|
||||
repeat=run(['python3',str(source/'scripts/prepare-update-repository.py'),str(root)],root,env)
|
||||
assert repeat.returncode==0
|
||||
assert len(list((root/'data/deployment-backups').glob('legacy-update-*')))==1
|
||||
print('legacy Git conflict: reproduced; code guard, private backups, local override, new Worker and updater address passed')
|
||||
print(json.dumps({'passed':True,'durationSeconds':round(time.monotonic()-started,3)}))
|
||||
Reference in New Issue
Block a user