-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Feature: Added automatic tests to check if QEmu runs. * Fix: Added code quality fixes. * Fix: Changed runtime generation script name. * Fix: Solve conflicts with main branch.
- Loading branch information
Showing
8 changed files
with
231 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#!/bin/bash | ||
|
||
set -euf | ||
|
||
# Variables | ||
ROOTFS_FILENAME="./rootfs.img" | ||
IMAGE_URL="https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64-disk-kvm.img" | ||
IMAGE_NAME="jammy-server-cloudimg-amd64-disk-kvm.img" | ||
|
||
# Cleanup previous run | ||
rm -f "$ROOTFS_FILENAME" | ||
|
||
# Download Ubuntu image | ||
echo "Downloading Ubuntu 22.04 image" | ||
curl -L "$IMAGE_URL" -o "$IMAGE_NAME" | ||
|
||
# Rename final file | ||
mv "$IMAGE_NAME" "$ROOTFS_FILENAME" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .instance import AlephQemuInstance | ||
|
||
__all__ = "AlephQemuInstance" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
import asyncio | ||
import logging | ||
from asyncio.subprocess import Process | ||
from pathlib import Path | ||
from typing import Optional | ||
|
||
import pytest | ||
from aleph_message.models import ItemHash | ||
|
||
from aleph.vm.conf import settings | ||
from aleph.vm.controllers.__main__ import configuration_from_file, execute_persistent_vm | ||
from aleph.vm.controllers.qemu import AlephQemuInstance | ||
from aleph.vm.hypervisors.qemu.qemuvm import QemuVM | ||
from aleph.vm.models import VmExecution | ||
from aleph.vm.network.hostnetwork import Network, make_ipv6_allocator | ||
from aleph.vm.orchestrator import metrics | ||
from aleph.vm.storage import get_message | ||
from aleph.vm.systemd import SystemDManager | ||
from aleph.vm.vm_type import VmType | ||
|
||
|
||
@pytest.mark.asyncio | ||
class MockSystemDManager(SystemDManager): | ||
execution: Optional[QemuVM] = None | ||
process: Optional[Process] = None | ||
|
||
async def enable_and_start(self, vm_hash: str): | ||
config_path = Path(f"{settings.EXECUTION_ROOT}/{vm_hash}-controller.json") | ||
config = configuration_from_file(config_path) | ||
self.execution, self.process = await execute_persistent_vm(config) | ||
return self.execution, self.process | ||
|
||
def is_service_enabled(self, service: str): | ||
return self.process is not None | ||
|
||
def is_service_active(self, service: str): | ||
return self.process is not None | ||
|
||
async def stop_and_disable(self, vm_hash: str): | ||
if self.process: | ||
self.process.kill() | ||
self.process = None | ||
self.execution = None | ||
return self.execution, self.process | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_create_qemu_instance(): | ||
""" | ||
Create an instance and check that it start / init / stop properly. | ||
""" | ||
|
||
settings.USE_FAKE_INSTANCE_BASE = True | ||
settings.FAKE_INSTANCE_MESSAGE = settings.FAKE_INSTANCE_QEMU_MESSAGE | ||
settings.FAKE_INSTANCE_BASE = settings.FAKE_QEMU_INSTANCE_BASE | ||
settings.ALLOW_VM_NETWORKING = False | ||
settings.USE_JAILER = False | ||
|
||
logging.basicConfig(level=logging.DEBUG) | ||
settings.PRINT_SYSTEM_LOGS = True | ||
|
||
# Ensure that the settings are correct and required files present. | ||
settings.setup() | ||
settings.check() | ||
|
||
# The database is required for the metrics and is currently not optional. | ||
engine = metrics.setup_engine() | ||
await metrics.create_tables(engine) | ||
|
||
vm_hash = ItemHash(settings.FAKE_INSTANCE_ID) | ||
message = await get_message(ref=vm_hash) | ||
|
||
mock_systemd_manager = MockSystemDManager() | ||
|
||
execution = VmExecution( | ||
vm_hash=vm_hash, | ||
message=message.content, | ||
original=message.content, | ||
snapshot_manager=None, | ||
systemd_manager=None, | ||
persistent=True, | ||
) | ||
|
||
await asyncio.wait_for(execution.prepare(), timeout=60) | ||
vm_id = 3 | ||
|
||
vm = execution.create(vm_id=vm_id, tap_interface=None) | ||
|
||
# Test that the VM is created correctly. It is not started yet. | ||
assert isinstance(vm, AlephQemuInstance) | ||
assert vm.vm_id == vm_id | ||
|
||
await execution.start() | ||
qemu_execution, process = await mock_systemd_manager.enable_and_start(execution.vm_hash) | ||
assert isinstance(qemu_execution, QemuVM) | ||
assert qemu_execution.qemu_process is not None | ||
qemu_execution, process = await mock_systemd_manager.stop_and_disable(execution.vm_hash) | ||
await execution.stop() | ||
assert qemu_execution is None | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_create_qemu_instance_online(): | ||
""" | ||
Create an instance and check that it start / init / stop properly. | ||
""" | ||
|
||
settings.USE_FAKE_INSTANCE_BASE = True | ||
settings.FAKE_INSTANCE_MESSAGE = settings.FAKE_INSTANCE_QEMU_MESSAGE | ||
settings.FAKE_INSTANCE_BASE = settings.FAKE_QEMU_INSTANCE_BASE | ||
settings.ALLOW_VM_NETWORKING = True | ||
settings.USE_JAILER = False | ||
|
||
logging.basicConfig(level=logging.DEBUG) | ||
settings.PRINT_SYSTEM_LOGS = True | ||
|
||
# Ensure that the settings are correct and required files present. | ||
settings.setup() | ||
settings.check() | ||
|
||
# The database is required for the metrics and is currently not optional. | ||
engine = metrics.setup_engine() | ||
await metrics.create_tables(engine) | ||
|
||
vm_hash = ItemHash(settings.FAKE_INSTANCE_ID) | ||
message = await get_message(ref=vm_hash) | ||
|
||
mock_systemd_manager = MockSystemDManager() | ||
|
||
network = ( | ||
Network( | ||
vm_ipv4_address_pool_range=settings.IPV4_ADDRESS_POOL, | ||
vm_network_size=settings.IPV4_NETWORK_PREFIX_LENGTH, | ||
external_interface=settings.NETWORK_INTERFACE, | ||
ipv6_allocator=make_ipv6_allocator( | ||
allocation_policy=settings.IPV6_ALLOCATION_POLICY, | ||
address_pool=settings.IPV6_ADDRESS_POOL, | ||
subnet_prefix=settings.IPV6_SUBNET_PREFIX, | ||
), | ||
use_ndp_proxy=False, | ||
ipv6_forwarding_enabled=False, | ||
) | ||
if settings.ALLOW_VM_NETWORKING | ||
else None | ||
) | ||
|
||
execution = VmExecution( | ||
vm_hash=vm_hash, | ||
message=message.content, | ||
original=message.content, | ||
snapshot_manager=None, | ||
systemd_manager=None, | ||
persistent=True, | ||
) | ||
|
||
await asyncio.wait_for(execution.prepare(), timeout=60) | ||
vm_id = 3 | ||
|
||
vm_type = VmType.from_message_content(message.content) | ||
tap_interface = await network.prepare_tap(vm_id, vm_hash, vm_type) | ||
await network.create_tap(vm_id, tap_interface) | ||
|
||
vm = execution.create(vm_id=vm_id, tap_interface=tap_interface) | ||
|
||
# Test that the VM is created correctly. It is not started yet. | ||
assert isinstance(vm, AlephQemuInstance) | ||
assert vm.vm_id == vm_id | ||
|
||
await execution.start() | ||
qemu_execution, process = await mock_systemd_manager.enable_and_start(execution.vm_hash) | ||
assert isinstance(qemu_execution, QemuVM) | ||
assert qemu_execution.qemu_process is not None | ||
await execution.wait_for_init() | ||
qemu_execution, process = await mock_systemd_manager.stop_and_disable(execution.vm_hash) | ||
await execution.stop() | ||
assert qemu_execution is None |