tart/integration-tests/test_stacked_oci.py

88 lines
3.6 KiB
Python

import os
import platform
import uuid
from typing import Optional
import pytest
from paramiko.client import AutoAddPolicy, SSHClient
def _macos_major_version() -> int:
version = platform.mac_ver()[0]
return int(version.split(".", maxsplit=1)[0]) if version else 0
def _shutdown_vm(tart, vm_name: str, guest_command: Optional[str] = None) -> None:
tart_run_process = tart.run_async(["run", "--no-graphics", vm_name])
try:
stdout, _ = tart.run(["ip", vm_name, "--wait", "180"])
client = SSHClient()
client.set_missing_host_key_policy(AutoAddPolicy)
client.connect(stdout.strip(), username="admin", password="admin")
if guest_command:
_, command_stdout, command_stderr = client.exec_command(guest_command)
assert command_stdout.channel.recv_exit_status() == 0, command_stderr.read().decode()
client.exec_command("sudo shutdown -h now")
client.close()
tart_run_process.wait(timeout=180)
assert tart_run_process.returncode == 0
finally:
if tart_run_process.poll() is None:
tart_run_process.terminate()
tart_run_process.wait(timeout=30)
@pytest.mark.skipif(
_macos_major_version() < 27,
reason="stacked disk images require DiskImageKit on macOS 27 or newer",
)
def test_stacked_oci_round_trip_and_boot(tart, docker_registry):
suffix = str(uuid.uuid4())
source_image = os.environ.get(
"TART_STACKED_INTEGRATION_BASE_IMAGE",
"ghcr.io/cirruslabs/macos-tahoe-base:latest",
)
source_clone_args = ["clone"]
if os.environ.get("TART_STACKED_INTEGRATION_BASE_INSECURE") == "1":
source_clone_args.append("--insecure")
standalone_vm = f"stacked-base-{suffix}"
stacked_vm = f"stacked-child-{suffix}"
restored_vm = f"stacked-restored-{suffix}"
base_remote = docker_registry.remote_name(f"stacked-base-{suffix}")
child_remote = docker_registry.remote_name(f"stacked-child-{suffix}")
try:
# Publish a normal Tart image, then start a stacked lineage from that
# remote image. The base remains a normal flat OCI image.
tart.run(source_clone_args + [source_image, standalone_vm])
tart.run(["push", "--insecure", standalone_vm, base_remote])
tart.run(["clone", "--insecure", "--stacked", base_remote, stacked_vm])
stacked_path = os.path.join(tart.home(), "vms", stacked_vm)
assert os.path.isfile(os.path.join(stacked_path, "overlay.asif"))
assert os.path.isfile(os.path.join(stacked_path, "manifest.json"))
assert not os.path.exists(os.path.join(stacked_path, "disk.img"))
# Boot once so the top ASIF overlay contains real guest writes, then
# exercise stacked push, pull, clone, assembly, and a second boot.
_shutdown_vm(tart, stacked_vm, "touch /Users/admin/stacked-round-trip-marker")
tart.run(["push", "--insecure", stacked_vm, child_remote])
tart.run(["delete", stacked_vm])
tart.run(["pull", "--insecure", child_remote])
tart.run(["clone", child_remote, restored_vm])
restored_path = os.path.join(tart.home(), "vms", restored_vm)
assert os.path.isfile(os.path.join(restored_path, "overlay.asif"))
assert os.path.isfile(os.path.join(restored_path, "manifest.json"))
assert not os.path.exists(os.path.join(restored_path, "disk.img"))
_shutdown_vm(tart, restored_vm, "test -f /Users/admin/stacked-round-trip-marker")
finally:
for vm_name in (restored_vm, stacked_vm, standalone_vm):
try:
tart.run(["delete", vm_name])
except Exception:
pass