Files
archy/scripts/provision-os-custody.py
T

54 lines
2.7 KiB
Python

#!/usr/bin/python3
"""Install a reviewed node-specific OS custody owner, without starting it.
This only stages root-owned code/config/unit files. The coordinator must then
produce READY from actual pinned custody before a dependent D09 owner may run.
Existing differing appointments/code require reviewed replacement, not overwrite.
"""
import argparse
import hashlib
import os
from pathlib import Path
import subprocess
from d09_store import atomic, read, secure
from os_update_mount_custody import CONFIG, pin_source
import json
def install(appointment,expected):
if os.getresuid()!=(0,0,0):raise PermissionError('root required')
raw=read(appointment)
if hashlib.sha256(raw).hexdigest()!=expected:raise ValueError('OS custody appointment digest differs')
value=json.loads(raw)
if value['node']!=os.uname().nodename:raise ValueError('wrong node custody appointment')
fd=pin_source(value['source'],value['source_identity']);os.close(fd)
package=Path(__file__).resolve().parent.parent
pairs={str(CONFIG):raw,
'/etc/systemd/system/archipelago-os-custody.service':read(package/'image-recipe/configs/archipelago-os-custody.service'),
'/etc/systemd/system/archipelago-d09-lifecycle.service.d/40-os-custody.conf':read(package/'image-recipe/configs/archipelago-d09-os-custody.conf')}
for name in ('os_update_mount_custody.py','os_update_custody.py','os_update_plan.py','d09_store.py','d09_wire.py','d09-wire-schema.json'):
pairs['/usr/libexec/'+name]=read(package/'scripts'/name)
for path,data in pairs.items():
p=Path(path)
if p.exists() or p.is_symlink():
if read(p)!=data:raise ValueError('different existing custody package input: '+path)
else:
parent=p.parent
if not parent.exists():
fd=secure(parent.parent,True)
try:os.mkdir(parent.name,0o755,dir_fd=fd);os.fsync(fd)
finally:os.close(fd)
fd=secure(parent,True);os.close(fd)
for path,data in pairs.items():
p=Path(path)
if not p.exists():atomic(p,data,0o600 if p==CONFIG else 0o644)
subprocess.run(['/usr/bin/systemctl','daemon-reload'],check=True)
subprocess.run(['/usr/bin/systemctl','enable','archipelago-os-custody.service'],check=True)
return {'installed_not_started':True,'appointment_sha256':expected,
'files':{path:hashlib.sha256(raw).hexdigest() for path,raw in pairs.items()}}
if __name__=='__main__':
parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--appointment',type=Path,required=True);parser.add_argument('--sha256',required=True)
args=parser.parse_args();print(json.dumps(install(args.appointment,args.sha256),sort_keys=True))