Files
apex.ermnvldmr.com/ci/scripts/init-node/tests/test_provision_image.py
T

113 lines
6.0 KiB
Python

import io
import os
from pathlib import Path
import shlex
import subprocess
import sys
import tarfile
import tempfile
import unittest
from unittest.mock import patch
from provisioning import access, image
from provisioning.image import cloud_enroll, sanitize_files
from provisioning.bundle import build_bundle
from provisioning.state import atomic_write, safe_path
from provisioning.state import ProvisionError
class ImageTests(unittest.TestCase):
def test_uploaded_package_installs_runnable_wrappers_and_watchdog(self):
commons = Path(__file__).resolve().parents[4]
data, digest, _ = build_bundle(commons)
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary).resolve()
upload = root / 'tmp'
upload.mkdir()
with tarfile.open(fileobj=io.BytesIO(data)) as archive:
archive.extractall(upload, filter='data')
def mapped(path):
return safe_path(root / str(path).lstrip('/'))
def write(path, content, mode=0o600):
return atomic_write(mapped(path), content, mode)
with patch.object(image, '__file__', str(upload / 'provisioning/image.py')), \
patch.object(image, 'safe_path', side_effect=mapped), \
patch.object(image, 'atomic_write', side_effect=write):
metadata = image.install()
installed = root / 'usr/local/lib/apex-provisioner' / digest
self.assertEqual(metadata['path'], str(installed))
self.assertTrue((installed / 'provisioning/seed.sh').is_file())
environment = dict(os.environ)
environment.pop('PYTHONPATH', None)
for executable in ('apex-provision-image', 'apex-bootstrap'):
wrapper = root / 'usr/local/bin' / executable
self.assertEqual(wrapper.stat().st_mode & 0o777, 0o755)
script = wrapper.read_text().replace('/usr/bin/python3', shlex.quote(sys.executable) + ' -S')
result = subprocess.run(['/bin/sh', '-c', script, executable, '--help'],
cwd=root, env=environment, capture_output=True,
text=True, timeout=30)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn('usage:', result.stdout)
commands = []
def runner(args, **kwargs):
commands.append(args)
return subprocess.CompletedProcess(args, 0, '', '')
canonical = '/usr/local/lib/apex-provisioner/' + digest
with patch.object(access, '__file__', canonical + '/provisioning/access.py'):
access.Host(root, runner=runner).arm()
service = (root / 'etc/systemd/system/apex-access-rollback.service').read_text()
fields = dict(line.split('=', 1) for line in service.splitlines() if '=' in line)
self.assertEqual(fields['WorkingDirectory'], canonical)
argv = shlex.split(fields['ExecStart'])
self.assertEqual(argv[-1], 'tick')
result = subprocess.run([sys.executable, '-S', *argv[1:-1], '--help'],
cwd=installed, env=environment, capture_output=True,
text=True, timeout=30)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn(['systemctl', 'enable', '--now', 'apex-access-rollback.timer'], commands)
sanitize_files(root)
self.assertFalse((upload / 'provisioning').exists())
self.assertTrue((installed / 'provisioning/image.py').is_file())
def test_watchdog_rejects_uninstalled_package_before_writing_units(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary).resolve()
with self.assertRaisesRegex(access.AccessError, 'installed root-owned bundle'):
access.Host(root).arm()
self.assertEqual(list(root.iterdir()), [])
def test_incompatible_image_stops_before_any_enrollment(self):
for metadata in ('{}', '{"enrollment_interface":999}'):
with self.subTest(metadata=metadata), patch.object(Path, 'read_text', return_value=metadata), \
patch('provisioning.target.enroll') as enroll:
with self.assertRaisesRegex(ProvisionError, 'image enrollment interface'):
cloud_enroll()
enroll.assert_not_called()
def test_sanitization_removes_cloned_identity_and_enrollment_but_preserves_runner(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary).resolve()
for relative in ('etc/ssh/ssh_host_ed25519_key', 'etc/ssh/ssh_host_ed25519_key.pub',
'root/.ssh/authorized_keys', 'home/debian/.ssh/authorized_keys',
'etc/machine-id', 'var/lib/dbus/machine-id',
'var/lib/apex-init/enrollment.json', 'var/lib/cloud/instance/user-data.txt',
'usr/local/lib/apex-provisioner/digest/provisioning/target.py',
'tmp/provisioning/image.py'):
path = root / relative
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text('build-specific')
sanitize_files(root)
self.assertEqual(list((root / 'etc/ssh').glob('ssh_host_*')), [])
self.assertEqual((root / 'etc/machine-id').read_text(), '')
self.assertFalse((root / 'root/.ssh/authorized_keys').exists())
self.assertFalse((root / 'var/lib/apex-init').exists())
self.assertFalse((root / 'var/lib/cloud').exists())
self.assertFalse((root / 'tmp/provisioning').exists())
self.assertTrue((root / 'usr/local/lib/apex-provisioner/digest/provisioning/target.py').is_file())
self.assertTrue((root / 'etc/systemd/system/ssh.service.d/10-generate-host-keys.conf').is_file())