Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/aleph/sdk/client/vm_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@


class VmOperation(str, Enum):
START = "start"
STOP = "stop"
REBOOT = "reboot"
ERASE = "erase"
Expand Down Expand Up @@ -217,8 +218,19 @@ async def get_logs(self, vm_id: ItemHash) -> AsyncGenerator[str, None]:
logger.warning("WebSocket closed by server")
break

async def start_instance(self, vm_id: ItemHash) -> Tuple[int, str]:
return await self.notify_allocation(vm_id)
async def start_instance(self, vm_id: ItemHash) -> Tuple[Optional[int], str]:
"""Start a VM its owner stopped.

Calls the authenticated /control/machine/{ref}/start route, falling
back to the legacy /control/allocation/notify push on 404 for CRNs
that predate aleph-vm 2.1.
"""
status, result = await self.perform_operation(vm_id, VmOperation.START)

if status == 404:
return await self.notify_allocation(vm_id)

return status, result

async def stop_instance(self, vm_id: ItemHash) -> Tuple[Optional[int], str]:
return await self.perform_operation(vm_id, VmOperation.STOP)
Expand Down
80 changes: 80 additions & 0 deletions tests/unit/test_vm_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,85 @@ async def test_notify_allocation():
await vm_client.session.close()


@pytest.mark.asyncio
async def test_start_instance_uses_machine_start_route():
account = ETHAccount(private_key=b"0x" + b"1" * 30)
vm_id = ItemHash("cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe")

with aioresponses() as m:
vm_client = VmClient(
account=account,
node_url="http://localhost",
session=aiohttp.ClientSession(),
)
m.post(
f"http://localhost/control/machine/{vm_id}/start",
status=200,
payload="Started VM with ref",
)

status, response_text = await vm_client.start_instance(vm_id)
assert status == 200
assert len(m.requests) == 1
assert (
"POST",
URL(f"http://localhost/control/machine/{vm_id}/start"),
) in m.requests
await vm_client.session.close()


@pytest.mark.asyncio
async def test_start_instance_falls_back_to_notify_on_404():
account = ETHAccount(private_key=b"0x" + b"1" * 30)
vm_id = ItemHash("cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe")

with aioresponses() as m:
vm_client = VmClient(
account=account,
node_url="http://localhost",
session=aiohttp.ClientSession(),
)
m.post(
f"http://localhost/control/machine/{vm_id}/start",
status=404,
body="404: Not Found",
)
m.post("http://localhost/control/allocation/notify", status=200)

status, response_text = await vm_client.start_instance(vm_id)
assert status == 200
assert len(m.requests) == 2
assert (
"POST",
URL(f"http://localhost/control/machine/{vm_id}/start"),
) in m.requests
assert ("POST", URL("http://localhost/control/allocation/notify")) in m.requests
await vm_client.session.close()


@pytest.mark.asyncio
async def test_start_instance_does_not_fall_back_on_other_errors():
account = ETHAccount(private_key=b"0x" + b"1" * 30)
vm_id = ItemHash("cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe")

with aioresponses() as m:
vm_client = VmClient(
account=account,
node_url="http://localhost",
session=aiohttp.ClientSession(),
)
m.post(
f"http://localhost/control/machine/{vm_id}/start",
status=403,
body="Unauthorized sender",
)

status, response_text = await vm_client.start_instance(vm_id)
assert status == 403
assert len(m.requests) == 1
await vm_client.session.close()


@pytest.mark.asyncio
async def test_perform_operation():
account = ETHAccount(private_key=b"0x" + b"1" * 30)
Expand Down Expand Up @@ -659,6 +738,7 @@ async def test_restore_from_file_not_found():


def test_vm_operation_enum_values():
assert VmOperation.START == "start"
assert VmOperation.STOP == "stop"
assert VmOperation.REBOOT == "reboot"
assert VmOperation.ERASE == "erase"
Expand Down
Loading