44 lines
2.7 KiB
Python
44 lines
2.7 KiB
Python
"""Boot the actual server image with the actual rendered configuration, then probe/save/restart it."""
|
|
import json,os,secrets,subprocess,sys,tempfile,time
|
|
from pathlib import Path
|
|
import yaml
|
|
|
|
docs=list(yaml.safe_load_all(Path(sys.argv[1]).read_text()))
|
|
d=next(d for d in docs if d['kind']=='Deployment')
|
|
c=next(c for c in d['spec']['template']['spec']['containers'] if c['name']=='factorio')
|
|
cms={d['metadata']['name']:d['data'] for d in docs if d['kind']=='ConfigMap'}
|
|
run=lambda *a,**kw: subprocess.run(a,check=True,**kw)
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
root=Path(directory)
|
|
for name in ['scripts','settings','credentials','data']:(root/name).mkdir()
|
|
for folder,name in [('scripts','factorio-scripts'),('settings','factorio-settings')]:
|
|
for key,value in cms[name].items():
|
|
file=root/folder/key; file.write_text(value); file.chmod(0o755 if key.endswith('.sh') else 0o644)
|
|
(root/'credentials/rcon-password').write_text(secrets.token_urlsafe(32))
|
|
args=['docker','run','--detach','--name','factorio-smoke-'+secrets.token_hex(5)]
|
|
for env in c['env']:args+=['--env',env['name']+'='+env['value']]
|
|
for mount in c['volumeMounts']:
|
|
folder={'data':'data','scripts':'scripts','settings':'settings','credentials':'credentials'}[mount['name']]
|
|
args+=['--volume',f'{root/folder}:{mount["mountPath"]}'+(':ro' if mount.get('readOnly') else '')]
|
|
args+=['--entrypoint',c['command'][0],c['image'],*c['command'][1:]]
|
|
container=subprocess.check_output(args,text=True).strip()
|
|
def ready():
|
|
command=c['readinessProbe']['exec']['command']
|
|
for _ in range(90):
|
|
if subprocess.run(['docker','exec',container,*command],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=15).returncode==0:return
|
|
time.sleep(2)
|
|
raise RuntimeError('Server did not pass the production readiness probe')
|
|
try:
|
|
ready()
|
|
run('docker','exec',container,'rcon','/server-save')
|
|
run('docker','stop','--time','180',container,stdout=subprocess.DEVNULL)
|
|
assert list((root/'data/saves').glob('*.zip')), 'No persistent save'
|
|
run('docker','start',container,stdout=subprocess.DEVNULL)
|
|
ready()
|
|
assert list((root/'data/upgrade-backups').glob('*/*.zip')), 'No pre-upgrade backup'
|
|
print('Actual image passed RCON readiness, persistent save, restart, and upgrade-backup checks')
|
|
finally:
|
|
run('docker','rm','--force',container,stdout=subprocess.DEVNULL)
|
|
# The upstream image owns its world files; cleanup through the same image.
|
|
run('docker','run','--rm','--volume',f'{root}/data:/cleanup','--entrypoint','sh',c['image'],'-c','rm -rf /cleanup/*',stdout=subprocess.DEVNULL)
|