54 lines
2.7 KiB
Python
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))
|