55 lines
2.4 KiB
Python
55 lines
2.4 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':{'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()
|