73 lines
3.2 KiB
Python
73 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Explicit opt-in real-systemd regression; no production service is stopped."""
|
|
from pathlib import Path
|
|
import importlib.util
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import uuid
|
|
|
|
|
|
def main():
|
|
if os.geteuid() != 0 or not Path('/run/systemd/system').is_dir():
|
|
raise RuntimeError('this explicit integration check requires root and real systemd')
|
|
spec = importlib.util.spec_from_file_location('runtime_guard', Path(__file__).with_name('ota_components.py'))
|
|
component = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(component)
|
|
token = 'matrix-runtime-test-' + uuid.uuid4().hex
|
|
service = token + '.service'
|
|
unit = Path('/run/systemd/system') / service
|
|
directory = Path('/run') / token
|
|
dropin = unit.with_name(service + '.d') / '90-matrix-ota-runtime.conf'
|
|
component.SERVICE = service
|
|
component.RUNTIME_GUARD = dropin
|
|
def run(*args, check=True):
|
|
return subprocess.run(['systemctl', *args], check=check, capture_output=True)
|
|
def write_unit(command='/bin/true'):
|
|
unit.write_text('[Unit]\nDescription=Isolated OTA RuntimeDirectory regression\n'
|
|
'[Service]\nType=oneshot\nRemainAfterExit=yes\n'
|
|
f'ExecStart={command}\nRuntimeDirectory={token}\nRuntimeDirectoryMode=0750\n'
|
|
'RuntimeDirectoryPreserve=restart\n', encoding='utf-8')
|
|
def markers():
|
|
for name in ('ota-request.json', 'ota-status.json', 'ota-worker.log'):
|
|
(directory / name).write_bytes(b'unchanged')
|
|
def assert_markers():
|
|
assert all((directory / n).read_bytes() == b'unchanged'
|
|
for n in ('ota-request.json', 'ota-status.json', 'ota-worker.log'))
|
|
try:
|
|
write_unit()
|
|
run('daemon-reload');run('start', service);markers()
|
|
run('stop', service)
|
|
assert not directory.exists(), 'negative control did not reproduce stop cleanup'
|
|
print('PASS: real systemd Preserve=restart deletes runtime directory on explicit stop', flush=True)
|
|
run('start', service);markers()
|
|
component.protect_runtime()
|
|
run('restart', service);assert_markers()
|
|
run('stop', service);assert_markers()
|
|
write_unit('/bin/false');run('daemon-reload')
|
|
assert run('start', service, check=False).returncode != 0
|
|
assert_markers()
|
|
component.release_runtime_guard()
|
|
assert not dropin.exists()
|
|
assert run('show', service, '--property=RuntimeDirectoryPreserve', '--value').stdout.strip() == b'restart'
|
|
print('PASS: real stop/restart/start-failure preserve OTA request/status/log; temporary protection cleaned', flush=True)
|
|
print(json.dumps({'runtime_lifecycle_passed': True}))
|
|
finally:
|
|
run('stop', service, check=False)
|
|
unit.unlink(missing_ok=True)
|
|
if dropin.exists():
|
|
dropin.unlink()
|
|
try:
|
|
dropin.parent.rmdir()
|
|
except OSError:
|
|
pass
|
|
run('daemon-reload');run('reset-failed', service, check=False)
|
|
assert directory.parent == Path('/run') and directory.name.startswith('matrix-runtime-test-')
|
|
if directory.exists():
|
|
shutil.rmtree(directory)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|