Files
2026-09-21 12:16:31 +01:00

55 lines
2.5 KiB
Python

"""Ship locally built static output, preserving TLS, ingress and other services."""
from pathlib import Path
import datetime
import json
import os
import subprocess
import urllib.request
import time
import shlex
ROOT = Path(__file__).resolve().parent
HOST = os.environ.get('DEPLOY_HOST', 'fzc')
def run(*args, capture=False):
return subprocess.run(args, check=True, text=True, capture_output=capture).stdout
def ssh(*args, capture=False):
return run('ssh', HOST, shlex.join(args), capture=capture)
def kube(*args, capture=False):
return ssh('kubectl', '-n', 'gnoc-hugo', *args, capture=capture)
def main():
release = datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%SZ') + '-' + run('git','rev-parse','--short','HEAD',capture=True).strip()
target = '/var/gnoc/site-releases/' + release
deployment = json.loads(kube('get','deployment','hugo','-o','json',capture=True))
volumes = deployment['spec']['template']['spec']['volumes']
current = next(v for v in volumes if v['name']=='site')
previous = current['hostPath']['path']
assert previous == '/var/gnoc/hugo-public' or previous.startswith('/var/gnoc/site-releases/'), 'Unexpected production mount'
owner = ssh('id','-un',capture=True).strip()
ssh('sudo','install','-d','-m','0755','-o',owner,'/var/gnoc/site-releases')
ssh('mkdir','-p',target)
run('rsync','-az','--chmod=D755,F644',str(ROOT/'public')+'/',f'{HOST}:{target}/')
def point(path):
patch={'spec':{'strategy':{'type':'RollingUpdate','rollingUpdate':{'maxUnavailable':0,'maxSurge':1}},'template':{'spec':{'volumes':[{'name':'site','hostPath':{'path':path,'type':'Directory'}}]}}}}
kube('patch','deployment','hugo','--type=strategic','-p',json.dumps(patch))
kube('rollout','status','deployment/hugo','--timeout=120s')
try:
point(target)
for _ in range(10):
try:
with urllib.request.urlopen('https://famzheng.me/release.json',timeout=15) as response:
actual=json.load(response)
expected=json.loads((ROOT/'public/release.json').read_text())
if actual == expected: break
except Exception: pass
time.sleep(2)
else: raise RuntimeError('Public release smoke test failed')
except Exception:
print('Restoring previous site:',previous)
point(previous)
raise
print('Published https://famzheng.me/ →', target)
print('Previous release retained:', previous)
if __name__ == '__main__': main()