|  | 
| 11 | 11 | from pytest_mock import MockerFixture | 
| 12 | 12 | 
 | 
| 13 | 13 | from aleph.vm.conf import settings | 
|  | 14 | +from aleph.vm.models import VmExecution | 
| 14 | 15 | from aleph.vm.orchestrator.supervisor import setup_webapp | 
| 15 | 16 | from aleph.vm.pool import VmPool | 
| 16 | 17 | from aleph.vm.sevclient import SevClient | 
| 17 | 18 | 
 | 
| 18 | 19 | 
 | 
|  | 20 | +@pytest.fixture() | 
|  | 21 | +def mock_instance_content(): | 
|  | 22 | +    fake = { | 
|  | 23 | +        "address": "0x101d8D16372dBf5f1614adaE95Ee5CCE61998Fc9", | 
|  | 24 | +        "time": 1713874241.800818, | 
|  | 25 | +        "allow_amend": False, | 
|  | 26 | +        "metadata": None, | 
|  | 27 | +        "authorized_keys": None, | 
|  | 28 | +        "variables": None, | 
|  | 29 | +        "environment": {"reproducible": False, "internet": True, "aleph_api": True, "shared_cache": False}, | 
|  | 30 | +        "resources": {"vcpus": 1, "memory": 256, "seconds": 30, "published_ports": None}, | 
|  | 31 | +        "payment": {"type": "superfluid", "chain": "BASE"}, | 
|  | 32 | +        "requirements": None, | 
|  | 33 | +        "replaces": None, | 
|  | 34 | +        "rootfs": { | 
|  | 35 | +            "parent": {"ref": "63f07193e6ee9d207b7d1fcf8286f9aee34e6f12f101d2ec77c1229f92964696"}, | 
|  | 36 | +            "ref": "63f07193e6ee9d207b7d1fcf8286f9aee34e6f12f101d2ec77c1229f92964696", | 
|  | 37 | +            "use_latest": True, | 
|  | 38 | +            "comment": "", | 
|  | 39 | +            "persistence": "host", | 
|  | 40 | +            "size_mib": 1000, | 
|  | 41 | +        }, | 
|  | 42 | +    } | 
|  | 43 | + | 
|  | 44 | +    return fake | 
|  | 45 | + | 
|  | 46 | + | 
| 19 | 47 | @pytest.mark.asyncio | 
| 20 | 48 | async def test_allocation_fails_on_invalid_item_hash(aiohttp_client): | 
| 21 | 49 |     """Test that the allocation endpoint fails when an invalid item_hash is provided.""" | 
| @@ -137,6 +165,124 @@ def get_persistent_executions(self): | 
| 137 | 165 |     assert await response.json() == {"success": True, "successful": [], "failing": [], "errors": {}} | 
| 138 | 166 | 
 | 
| 139 | 167 | 
 | 
|  | 168 | +@pytest.mark.asyncio | 
|  | 169 | +async def test_v2_executions_list_one_vm(aiohttp_client, mock_app_with_pool, mock_instance_content): | 
|  | 170 | +    web_app = await mock_app_with_pool | 
|  | 171 | +    pool = web_app["vm_pool"] | 
|  | 172 | +    message = InstanceContent.model_validate(mock_instance_content) | 
|  | 173 | + | 
|  | 174 | +    hash = "decadecadecadecadecadecadecadecadecadecadecadecadecadecadecadeca" | 
|  | 175 | + | 
|  | 176 | +    execution = VmExecution( | 
|  | 177 | +        vm_hash=hash, | 
|  | 178 | +        message=message, | 
|  | 179 | +        original=message, | 
|  | 180 | +        persistent=False, | 
|  | 181 | +        snapshot_manager=None, | 
|  | 182 | +        systemd_manager=None, | 
|  | 183 | +    ) | 
|  | 184 | +    pool.executions = {hash: execution} | 
|  | 185 | +    client = await aiohttp_client(web_app) | 
|  | 186 | +    response: web.Response = await client.get( | 
|  | 187 | +        "/v2/about/executions/list", | 
|  | 188 | +    ) | 
|  | 189 | +    assert response.status == 200 | 
|  | 190 | +    assert await response.json() == { | 
|  | 191 | +        "decadecadecadecadecadecadecadecadecadecadecadecadecadecadecadeca": { | 
|  | 192 | +            "networking": {}, | 
|  | 193 | +            "status": { | 
|  | 194 | +                "defined_at": str(execution.times.defined_at), | 
|  | 195 | +                "preparing_at": None, | 
|  | 196 | +                "prepared_at": None, | 
|  | 197 | +                "starting_at": None, | 
|  | 198 | +                "started_at": None, | 
|  | 199 | +                "stopping_at": None, | 
|  | 200 | +                "stopped_at": None, | 
|  | 201 | +            }, | 
|  | 202 | +            "running": None, | 
|  | 203 | +        } | 
|  | 204 | +    } | 
|  | 205 | + | 
|  | 206 | + | 
|  | 207 | +@pytest.mark.asyncio | 
|  | 208 | +async def test_v2_executions_list_vm_network(aiohttp_client, mocker, mock_app_with_pool, mock_instance_content): | 
|  | 209 | +    "Test locally but do not create" | 
|  | 210 | +    web_app = await mock_app_with_pool | 
|  | 211 | +    pool = web_app["vm_pool"] | 
|  | 212 | +    message = InstanceContent.model_validate(mock_instance_content) | 
|  | 213 | + | 
|  | 214 | +    vm_hash = "decadecadecadecadecadecadecadecadecadecadecadecadecadecadecadeca" | 
|  | 215 | + | 
|  | 216 | +    execution = VmExecution( | 
|  | 217 | +        vm_hash=hash, | 
|  | 218 | +        message=message, | 
|  | 219 | +        original=message, | 
|  | 220 | +        persistent=False, | 
|  | 221 | +        snapshot_manager=None, | 
|  | 222 | +        systemd_manager=None, | 
|  | 223 | +    ) | 
|  | 224 | +    vm_id = 3 | 
|  | 225 | +    from aleph.vm.network.hostnetwork import Network, make_ipv6_allocator | 
|  | 226 | + | 
|  | 227 | +    network = Network( | 
|  | 228 | +        vm_ipv4_address_pool_range=settings.IPV4_ADDRESS_POOL, | 
|  | 229 | +        vm_network_size=settings.IPV4_NETWORK_PREFIX_LENGTH, | 
|  | 230 | +        external_interface=settings.NETWORK_INTERFACE, | 
|  | 231 | +        ipv6_allocator=make_ipv6_allocator( | 
|  | 232 | +            allocation_policy=settings.IPV6_ALLOCATION_POLICY, | 
|  | 233 | +            address_pool=settings.IPV6_ADDRESS_POOL, | 
|  | 234 | +            subnet_prefix=settings.IPV6_SUBNET_PREFIX, | 
|  | 235 | +        ), | 
|  | 236 | +        use_ndp_proxy=False, | 
|  | 237 | +        ipv6_forwarding_enabled=False, | 
|  | 238 | +    ) | 
|  | 239 | +    network.setup() | 
|  | 240 | + | 
|  | 241 | +    from aleph.vm.vm_type import VmType | 
|  | 242 | + | 
|  | 243 | +    vm_type = VmType.from_message_content(message) | 
|  | 244 | +    tap_interface = await network.prepare_tap(vm_id, vm_hash, vm_type) | 
|  | 245 | +    # await network.create_tap(vm_id, tap_interface) | 
|  | 246 | +    execution.vm = mocker.Mock() | 
|  | 247 | +    execution.vm.tap_interface = tap_interface | 
|  | 248 | + | 
|  | 249 | +    pool.executions = {vm_hash: execution} | 
|  | 250 | +    client = await aiohttp_client(web_app) | 
|  | 251 | +    response: web.Response = await client.get( | 
|  | 252 | +        "/v2/about/executions/list", | 
|  | 253 | +    ) | 
|  | 254 | +    assert response.status == 200 | 
|  | 255 | +    assert await response.json() == { | 
|  | 256 | +        "decadecadecadecadecadecadecadecadecadecadecadecadecadecadecadeca": { | 
|  | 257 | +            "networking": { | 
|  | 258 | +                "ipv4_network": "172.16.3.0/24", | 
|  | 259 | +                "ipv6_network": "fc00:1:2:3:3:deca:deca:dec0/124", | 
|  | 260 | +                "ipv6_ip": "fc00:1:2:3:3:deca:deca:dec1", | 
|  | 261 | +            }, | 
|  | 262 | +            "status": { | 
|  | 263 | +                "defined_at": str(execution.times.defined_at), | 
|  | 264 | +                "preparing_at": None, | 
|  | 265 | +                "prepared_at": None, | 
|  | 266 | +                "starting_at": None, | 
|  | 267 | +                "started_at": None, | 
|  | 268 | +                "stopping_at": None, | 
|  | 269 | +                "stopped_at": None, | 
|  | 270 | +            }, | 
|  | 271 | +            "running": None, | 
|  | 272 | +        } | 
|  | 273 | +    } | 
|  | 274 | + | 
|  | 275 | + | 
|  | 276 | +@pytest.mark.asyncio | 
|  | 277 | +async def test_v2_executions_list_empty(aiohttp_client, mock_app_with_pool): | 
|  | 278 | +    client = await aiohttp_client(await mock_app_with_pool) | 
|  | 279 | +    response: web.Response = await client.get( | 
|  | 280 | +        "/v2/about/executions/list", | 
|  | 281 | +    ) | 
|  | 282 | +    assert response.status == 200 | 
|  | 283 | +    assert await response.json() == {} | 
|  | 284 | + | 
|  | 285 | + | 
| 140 | 286 | @pytest.mark.asyncio | 
| 141 | 287 | async def test_about_certificates_missing_setting(aiohttp_client): | 
| 142 | 288 |     """Test that the certificates system endpoint returns an error if the setting isn't enabled""" | 
| @@ -268,7 +414,6 @@ def mock_is_kernel_enabled_gpu(pci_host: str) -> bool: | 
| 268 | 414 |     ) | 
| 269 | 415 | 
 | 
| 270 | 416 |     mocker.patch.object(settings, "ENABLE_GPU_SUPPORT", True) | 
| 271 |  | -    loop = asyncio.new_event_loop() | 
| 272 | 417 |     pool = VmPool() | 
| 273 | 418 |     await pool.setup() | 
| 274 | 419 |     app = setup_webapp(pool=pool) | 
|  | 
0 commit comments