diff --git a/src/aleph/sdk/client/abstract.py b/src/aleph/sdk/client/abstract.py index 9fce5469..23c30e81 100644 --- a/src/aleph/sdk/client/abstract.py +++ b/src/aleph/sdk/client/abstract.py @@ -27,7 +27,11 @@ PostMessage, parse_message, ) -from aleph_message.models.execution.environment import HypervisorType +from aleph_message.models.execution.environment import ( + HostRequirements, + HypervisorType, + TrustedExecutionEnvironment, +) from aleph_message.models.execution.program import Encoding from aleph_message.status import MessageStatus @@ -395,10 +399,12 @@ async def create_instance( internet: bool = True, aleph_api: bool = True, hypervisor: Optional[HypervisorType] = None, + trusted_execution: Optional[TrustedExecutionEnvironment] = None, volumes: Optional[List[Mapping]] = None, volume_persistence: str = "host", ssh_keys: Optional[List[str]] = None, metadata: Optional[Mapping[str, Any]] = None, + requirements: Optional[HostRequirements] = None, ) -> Tuple[AlephMessage, MessageStatus]: """ Post a (create) INSTANCE message. @@ -417,11 +423,14 @@ async def create_instance( :param allow_amend: Whether the deployed VM image may be changed (Default: False) :param internet: Whether the VM should have internet connectivity. (Default: True) :param aleph_api: Whether the VM needs access to Aleph messages API (Default: True) + :param hypervisor: Whether the VM should use as Hypervisor, like QEmu or Firecracker (Default: Qemu) + :param trusted_execution: Whether the VM configuration (firmware and policy) to use for Confidential computing (Default: None) :param encoding: Encoding to use (Default: Encoding.zip) :param volumes: Volumes to mount :param volume_persistence: Where volumes are persisted, can be "host" or "store", meaning distributed across Aleph.im (Default: "host") :param ssh_keys: SSH keys to authorize access to the VM :param metadata: Metadata to attach to the message + :param requirements: CRN Requirements needed for the VM execution """ raise NotImplementedError( "Did you mean to import `AuthenticatedAlephHttpClient`?" diff --git a/src/aleph/sdk/client/authenticated_http.py b/src/aleph/sdk/client/authenticated_http.py index 6d44b526..cb2f3e01 100644 --- a/src/aleph/sdk/client/authenticated_http.py +++ b/src/aleph/sdk/client/authenticated_http.py @@ -29,9 +29,11 @@ from aleph_message.models.execution.base import Encoding, Payment, PaymentType from aleph_message.models.execution.environment import ( FunctionEnvironment, + HostRequirements, HypervisorType, InstanceEnvironment, MachineResources, + TrustedExecutionEnvironment, ) from aleph_message.models.execution.instance import RootfsVolume from aleph_message.models.execution.program import CodeContent, FunctionRuntime @@ -522,10 +524,12 @@ async def create_instance( internet: bool = True, aleph_api: bool = True, hypervisor: Optional[HypervisorType] = None, + trusted_execution: Optional[TrustedExecutionEnvironment] = None, volumes: Optional[List[Mapping]] = None, volume_persistence: str = "host", ssh_keys: Optional[List[str]] = None, metadata: Optional[Mapping[str, Any]] = None, + requirements: Optional[HostRequirements] = None, ) -> Tuple[InstanceMessage, MessageStatus]: address = address or settings.ADDRESS_TO_USE or self.account.get_address() @@ -546,6 +550,7 @@ async def create_instance( internet=internet, aleph_api=aleph_api, hypervisor=selected_hypervisor, + trusted_execution=trusted_execution, ), variables=environment_variables, resources=MachineResources( @@ -563,6 +568,7 @@ async def create_instance( use_latest=True, ), volumes=[parse_volume(volume) for volume in volumes], + requirements=requirements, time=time.time(), authorized_keys=ssh_keys, metadata=metadata, diff --git a/tests/unit/test_asynchronous.py b/tests/unit/test_asynchronous.py index 0f909408..b044e170 100644 --- a/tests/unit/test_asynchronous.py +++ b/tests/unit/test_asynchronous.py @@ -14,7 +14,13 @@ ProgramMessage, StoreMessage, ) -from aleph_message.models.execution.environment import HypervisorType, MachineResources +from aleph_message.models.execution.environment import ( + HostRequirements, + HypervisorType, + MachineResources, + NodeRequirements, + TrustedExecutionEnvironment, +) from aleph_message.status import MessageStatus from aleph.sdk.exceptions import InsufficientFundsError @@ -163,6 +169,35 @@ async def test_create_instance_no_hypervisor(mock_session_with_post_success): assert isinstance(instance_message, InstanceMessage) +@pytest.mark.asyncio +async def test_create_confidential_instance(mock_session_with_post_success): + async with mock_session_with_post_success as session: + confidential_instance_message, message_status = await session.create_instance( + rootfs="cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe", + rootfs_size=1, + channel="TEST", + metadata={"tags": ["test"]}, + payment=Payment( + chain=Chain.AVAX, + receiver="0x4145f182EF2F06b45E50468519C1B92C60FBd4A0", + type=PaymentType.superfluid, + ), + hypervisor=HypervisorType.qemu, + trusted_execution=TrustedExecutionEnvironment( + firmware="cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe", + policy=0b1, + ), + requirements=HostRequirements( + node=NodeRequirements( + node_hash="cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe", + ) + ), + ) + + assert mock_session_with_post_success.http_session.post.assert_called_once + assert isinstance(confidential_instance_message, InstanceMessage) + + @pytest.mark.asyncio async def test_forget(mock_session_with_post_success): async with mock_session_with_post_success as session: