diff --git a/src/blaxel/core/client/api/agents/list_agents.py b/src/blaxel/core/client/api/agents/list_agents.py index fc2d1e03..d669f494 100644 --- a/src/blaxel/core/client/api/agents/list_agents.py +++ b/src/blaxel/core/client/api/agents/list_agents.py @@ -19,6 +19,7 @@ def _get_kwargs( sort: Union[Unset, ListAgentsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListAgentsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -40,6 +41,8 @@ def _get_kwargs( params["anchor"] = json_anchor + params["status"] = status + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} _kwargs: dict[str, Any] = { @@ -93,6 +96,7 @@ def sync_detailed( sort: Union[Unset, ListAgentsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListAgentsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[AgentList, Error]]: """List all agents @@ -107,6 +111,7 @@ def sync_detailed( sort (Union[Unset, ListAgentsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListAgentsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -122,6 +127,7 @@ def sync_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = client.get_httpx_client().request( @@ -139,6 +145,7 @@ def sync( sort: Union[Unset, ListAgentsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListAgentsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[AgentList, Error] | None: """List all agents @@ -153,6 +160,7 @@ def sync( sort (Union[Unset, ListAgentsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListAgentsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -169,6 +177,7 @@ def sync( sort=sort, q=q, anchor=anchor, + status=status, ).parsed @@ -180,6 +189,7 @@ async def asyncio_detailed( sort: Union[Unset, ListAgentsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListAgentsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[AgentList, Error]]: """List all agents @@ -194,6 +204,7 @@ async def asyncio_detailed( sort (Union[Unset, ListAgentsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListAgentsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -209,6 +220,7 @@ async def asyncio_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -224,6 +236,7 @@ async def asyncio( sort: Union[Unset, ListAgentsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListAgentsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[AgentList, Error] | None: """List all agents @@ -238,6 +251,7 @@ async def asyncio( sort (Union[Unset, ListAgentsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListAgentsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -255,5 +269,6 @@ async def asyncio( sort=sort, q=q, anchor=anchor, + status=status, ) ).parsed diff --git a/src/blaxel/core/client/api/applications/list_applications.py b/src/blaxel/core/client/api/applications/list_applications.py index 6a561887..42aeeb6a 100644 --- a/src/blaxel/core/client/api/applications/list_applications.py +++ b/src/blaxel/core/client/api/applications/list_applications.py @@ -19,6 +19,7 @@ def _get_kwargs( sort: Union[Unset, ListApplicationsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListApplicationsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -40,6 +41,8 @@ def _get_kwargs( params["anchor"] = json_anchor + params["status"] = status + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} _kwargs: dict[str, Any] = { @@ -95,6 +98,7 @@ def sync_detailed( sort: Union[Unset, ListApplicationsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListApplicationsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[ApplicationList, Error]]: """List all applications @@ -109,6 +113,7 @@ def sync_detailed( sort (Union[Unset, ListApplicationsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListApplicationsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -124,6 +129,7 @@ def sync_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = client.get_httpx_client().request( @@ -141,6 +147,7 @@ def sync( sort: Union[Unset, ListApplicationsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListApplicationsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[ApplicationList, Error] | None: """List all applications @@ -155,6 +162,7 @@ def sync( sort (Union[Unset, ListApplicationsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListApplicationsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -171,6 +179,7 @@ def sync( sort=sort, q=q, anchor=anchor, + status=status, ).parsed @@ -182,6 +191,7 @@ async def asyncio_detailed( sort: Union[Unset, ListApplicationsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListApplicationsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[ApplicationList, Error]]: """List all applications @@ -196,6 +206,7 @@ async def asyncio_detailed( sort (Union[Unset, ListApplicationsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListApplicationsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -211,6 +222,7 @@ async def asyncio_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -226,6 +238,7 @@ async def asyncio( sort: Union[Unset, ListApplicationsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListApplicationsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[ApplicationList, Error] | None: """List all applications @@ -240,6 +253,7 @@ async def asyncio( sort (Union[Unset, ListApplicationsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListApplicationsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -257,5 +271,6 @@ async def asyncio( sort=sort, q=q, anchor=anchor, + status=status, ) ).parsed diff --git a/src/blaxel/core/client/api/compute/list_sandboxes.py b/src/blaxel/core/client/api/compute/list_sandboxes.py index 40e9bb1f..0516aa4e 100644 --- a/src/blaxel/core/client/api/compute/list_sandboxes.py +++ b/src/blaxel/core/client/api/compute/list_sandboxes.py @@ -20,6 +20,7 @@ def _get_kwargs( sort: Union[Unset, ListSandboxesSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListSandboxesAnchor] = UNSET, + status: Union[Unset, str] = UNSET, external_id: Union[Unset, str] = UNSET, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -44,6 +45,8 @@ def _get_kwargs( params["anchor"] = json_anchor + params["status"] = status + params["externalId"] = external_id params = {k: v for k, v in params.items() if v is not UNSET and v is not None} @@ -102,6 +105,7 @@ def sync_detailed( sort: Union[Unset, ListSandboxesSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListSandboxesAnchor] = UNSET, + status: Union[Unset, str] = UNSET, external_id: Union[Unset, str] = UNSET, ) -> Response[Union[Error, SandboxList]]: """List sandboxes @@ -119,6 +123,7 @@ def sync_detailed( sort (Union[Unset, ListSandboxesSort]): q (Union[Unset, str]): anchor (Union[Unset, ListSandboxesAnchor]): + status (Union[Unset, str]): external_id (Union[Unset, str]): Raises: @@ -136,6 +141,7 @@ def sync_detailed( sort=sort, q=q, anchor=anchor, + status=status, external_id=external_id, ) @@ -155,6 +161,7 @@ def sync( sort: Union[Unset, ListSandboxesSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListSandboxesAnchor] = UNSET, + status: Union[Unset, str] = UNSET, external_id: Union[Unset, str] = UNSET, ) -> Union[Error, SandboxList] | None: """List sandboxes @@ -172,6 +179,7 @@ def sync( sort (Union[Unset, ListSandboxesSort]): q (Union[Unset, str]): anchor (Union[Unset, ListSandboxesAnchor]): + status (Union[Unset, str]): external_id (Union[Unset, str]): Raises: @@ -190,6 +198,7 @@ def sync( sort=sort, q=q, anchor=anchor, + status=status, external_id=external_id, ).parsed @@ -203,6 +212,7 @@ async def asyncio_detailed( sort: Union[Unset, ListSandboxesSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListSandboxesAnchor] = UNSET, + status: Union[Unset, str] = UNSET, external_id: Union[Unset, str] = UNSET, ) -> Response[Union[Error, SandboxList]]: """List sandboxes @@ -220,6 +230,7 @@ async def asyncio_detailed( sort (Union[Unset, ListSandboxesSort]): q (Union[Unset, str]): anchor (Union[Unset, ListSandboxesAnchor]): + status (Union[Unset, str]): external_id (Union[Unset, str]): Raises: @@ -237,6 +248,7 @@ async def asyncio_detailed( sort=sort, q=q, anchor=anchor, + status=status, external_id=external_id, ) @@ -254,6 +266,7 @@ async def asyncio( sort: Union[Unset, ListSandboxesSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListSandboxesAnchor] = UNSET, + status: Union[Unset, str] = UNSET, external_id: Union[Unset, str] = UNSET, ) -> Union[Error, SandboxList] | None: """List sandboxes @@ -271,6 +284,7 @@ async def asyncio( sort (Union[Unset, ListSandboxesSort]): q (Union[Unset, str]): anchor (Union[Unset, ListSandboxesAnchor]): + status (Union[Unset, str]): external_id (Union[Unset, str]): Raises: @@ -290,6 +304,7 @@ async def asyncio( sort=sort, q=q, anchor=anchor, + status=status, external_id=external_id, ) ).parsed diff --git a/src/blaxel/core/client/api/drives/list_drives.py b/src/blaxel/core/client/api/drives/list_drives.py index 677931ea..62b2c216 100644 --- a/src/blaxel/core/client/api/drives/list_drives.py +++ b/src/blaxel/core/client/api/drives/list_drives.py @@ -19,6 +19,7 @@ def _get_kwargs( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListDrivesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -42,6 +43,8 @@ def _get_kwargs( params["externalId"] = external_id + params["status"] = status + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} _kwargs: dict[str, Any] = { @@ -85,6 +88,7 @@ def sync_detailed( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListDrivesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[Any, DriveList]]: """List drives @@ -100,6 +104,7 @@ def sync_detailed( q (Union[Unset, str]): anchor (Union[Unset, ListDrivesAnchor]): external_id (Union[Unset, str]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -116,6 +121,7 @@ def sync_detailed( q=q, anchor=anchor, external_id=external_id, + status=status, ) response = client.get_httpx_client().request( @@ -134,6 +140,7 @@ def sync( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListDrivesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[Any, DriveList] | None: """List drives @@ -149,6 +156,7 @@ def sync( q (Union[Unset, str]): anchor (Union[Unset, ListDrivesAnchor]): external_id (Union[Unset, str]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -166,6 +174,7 @@ def sync( q=q, anchor=anchor, external_id=external_id, + status=status, ).parsed @@ -178,6 +187,7 @@ async def asyncio_detailed( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListDrivesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[Any, DriveList]]: """List drives @@ -193,6 +203,7 @@ async def asyncio_detailed( q (Union[Unset, str]): anchor (Union[Unset, ListDrivesAnchor]): external_id (Union[Unset, str]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -209,6 +220,7 @@ async def asyncio_detailed( q=q, anchor=anchor, external_id=external_id, + status=status, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -225,6 +237,7 @@ async def asyncio( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListDrivesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[Any, DriveList] | None: """List drives @@ -240,6 +253,7 @@ async def asyncio( q (Union[Unset, str]): anchor (Union[Unset, ListDrivesAnchor]): external_id (Union[Unset, str]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -258,5 +272,6 @@ async def asyncio( q=q, anchor=anchor, external_id=external_id, + status=status, ) ).parsed diff --git a/src/blaxel/core/client/api/functions/list_functions.py b/src/blaxel/core/client/api/functions/list_functions.py index afdc5145..a74b7faf 100644 --- a/src/blaxel/core/client/api/functions/list_functions.py +++ b/src/blaxel/core/client/api/functions/list_functions.py @@ -19,6 +19,7 @@ def _get_kwargs( sort: Union[Unset, ListFunctionsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListFunctionsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -40,6 +41,8 @@ def _get_kwargs( params["anchor"] = json_anchor + params["status"] = status + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} _kwargs: dict[str, Any] = { @@ -95,6 +98,7 @@ def sync_detailed( sort: Union[Unset, ListFunctionsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListFunctionsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[Error, FunctionList]]: """List all MCP servers @@ -109,6 +113,7 @@ def sync_detailed( sort (Union[Unset, ListFunctionsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListFunctionsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -124,6 +129,7 @@ def sync_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = client.get_httpx_client().request( @@ -141,6 +147,7 @@ def sync( sort: Union[Unset, ListFunctionsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListFunctionsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[Error, FunctionList] | None: """List all MCP servers @@ -155,6 +162,7 @@ def sync( sort (Union[Unset, ListFunctionsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListFunctionsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -171,6 +179,7 @@ def sync( sort=sort, q=q, anchor=anchor, + status=status, ).parsed @@ -182,6 +191,7 @@ async def asyncio_detailed( sort: Union[Unset, ListFunctionsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListFunctionsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[Error, FunctionList]]: """List all MCP servers @@ -196,6 +206,7 @@ async def asyncio_detailed( sort (Union[Unset, ListFunctionsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListFunctionsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -211,6 +222,7 @@ async def asyncio_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -226,6 +238,7 @@ async def asyncio( sort: Union[Unset, ListFunctionsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListFunctionsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[Error, FunctionList] | None: """List all MCP servers @@ -240,6 +253,7 @@ async def asyncio( sort (Union[Unset, ListFunctionsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListFunctionsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -257,5 +271,6 @@ async def asyncio( sort=sort, q=q, anchor=anchor, + status=status, ) ).parsed diff --git a/src/blaxel/core/client/api/jobs/list_jobs.py b/src/blaxel/core/client/api/jobs/list_jobs.py index 09a1f502..08b9bdf7 100644 --- a/src/blaxel/core/client/api/jobs/list_jobs.py +++ b/src/blaxel/core/client/api/jobs/list_jobs.py @@ -18,6 +18,7 @@ def _get_kwargs( sort: Union[Unset, ListJobsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListJobsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -39,6 +40,8 @@ def _get_kwargs( params["anchor"] = json_anchor + params["status"] = status + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} _kwargs: dict[str, Any] = { @@ -78,6 +81,7 @@ def sync_detailed( sort: Union[Unset, ListJobsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListJobsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[JobList]: """List batch jobs @@ -92,6 +96,7 @@ def sync_detailed( sort (Union[Unset, ListJobsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListJobsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -107,6 +112,7 @@ def sync_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = client.get_httpx_client().request( @@ -124,6 +130,7 @@ def sync( sort: Union[Unset, ListJobsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListJobsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> JobList | None: """List batch jobs @@ -138,6 +145,7 @@ def sync( sort (Union[Unset, ListJobsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListJobsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -154,6 +162,7 @@ def sync( sort=sort, q=q, anchor=anchor, + status=status, ).parsed @@ -165,6 +174,7 @@ async def asyncio_detailed( sort: Union[Unset, ListJobsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListJobsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[JobList]: """List batch jobs @@ -179,6 +189,7 @@ async def asyncio_detailed( sort (Union[Unset, ListJobsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListJobsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -194,6 +205,7 @@ async def asyncio_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -209,6 +221,7 @@ async def asyncio( sort: Union[Unset, ListJobsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListJobsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> JobList | None: """List batch jobs @@ -223,6 +236,7 @@ async def asyncio( sort (Union[Unset, ListJobsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListJobsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -240,5 +254,6 @@ async def asyncio( sort=sort, q=q, anchor=anchor, + status=status, ) ).parsed diff --git a/src/blaxel/core/client/api/models/list_models.py b/src/blaxel/core/client/api/models/list_models.py index a27c66af..555e9841 100644 --- a/src/blaxel/core/client/api/models/list_models.py +++ b/src/blaxel/core/client/api/models/list_models.py @@ -19,6 +19,7 @@ def _get_kwargs( sort: Union[Unset, ListModelsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListModelsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -40,6 +41,8 @@ def _get_kwargs( params["anchor"] = json_anchor + params["status"] = status + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} _kwargs: dict[str, Any] = { @@ -93,6 +96,7 @@ def sync_detailed( sort: Union[Unset, ListModelsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListModelsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[Error, ModelList]]: """List model endpoints @@ -107,6 +111,7 @@ def sync_detailed( sort (Union[Unset, ListModelsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListModelsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -122,6 +127,7 @@ def sync_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = client.get_httpx_client().request( @@ -139,6 +145,7 @@ def sync( sort: Union[Unset, ListModelsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListModelsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[Error, ModelList] | None: """List model endpoints @@ -153,6 +160,7 @@ def sync( sort (Union[Unset, ListModelsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListModelsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -169,6 +177,7 @@ def sync( sort=sort, q=q, anchor=anchor, + status=status, ).parsed @@ -180,6 +189,7 @@ async def asyncio_detailed( sort: Union[Unset, ListModelsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListModelsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[Error, ModelList]]: """List model endpoints @@ -194,6 +204,7 @@ async def asyncio_detailed( sort (Union[Unset, ListModelsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListModelsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -209,6 +220,7 @@ async def asyncio_detailed( sort=sort, q=q, anchor=anchor, + status=status, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -224,6 +236,7 @@ async def asyncio( sort: Union[Unset, ListModelsSort] = UNSET, q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListModelsAnchor] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[Error, ModelList] | None: """List model endpoints @@ -238,6 +251,7 @@ async def asyncio( sort (Union[Unset, ListModelsSort]): q (Union[Unset, str]): anchor (Union[Unset, ListModelsAnchor]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -255,5 +269,6 @@ async def asyncio( sort=sort, q=q, anchor=anchor, + status=status, ) ).parsed diff --git a/src/blaxel/core/client/api/volumes/list_volumes.py b/src/blaxel/core/client/api/volumes/list_volumes.py index 8f42a08a..e1b7e8c5 100644 --- a/src/blaxel/core/client/api/volumes/list_volumes.py +++ b/src/blaxel/core/client/api/volumes/list_volumes.py @@ -20,6 +20,7 @@ def _get_kwargs( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListVolumesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> dict[str, Any]: params: dict[str, Any] = {} @@ -43,6 +44,8 @@ def _get_kwargs( params["externalId"] = external_id + params["status"] = status + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} _kwargs: dict[str, Any] = { @@ -97,6 +100,7 @@ def sync_detailed( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListVolumesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[Error, VolumeList]]: """List persistent volumes @@ -112,6 +116,7 @@ def sync_detailed( q (Union[Unset, str]): anchor (Union[Unset, ListVolumesAnchor]): external_id (Union[Unset, str]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -128,6 +133,7 @@ def sync_detailed( q=q, anchor=anchor, external_id=external_id, + status=status, ) response = client.get_httpx_client().request( @@ -146,6 +152,7 @@ def sync( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListVolumesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[Error, VolumeList] | None: """List persistent volumes @@ -161,6 +168,7 @@ def sync( q (Union[Unset, str]): anchor (Union[Unset, ListVolumesAnchor]): external_id (Union[Unset, str]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -178,6 +186,7 @@ def sync( q=q, anchor=anchor, external_id=external_id, + status=status, ).parsed @@ -190,6 +199,7 @@ async def asyncio_detailed( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListVolumesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Response[Union[Error, VolumeList]]: """List persistent volumes @@ -205,6 +215,7 @@ async def asyncio_detailed( q (Union[Unset, str]): anchor (Union[Unset, ListVolumesAnchor]): external_id (Union[Unset, str]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -221,6 +232,7 @@ async def asyncio_detailed( q=q, anchor=anchor, external_id=external_id, + status=status, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -237,6 +249,7 @@ async def asyncio( q: Union[Unset, str] = UNSET, anchor: Union[Unset, ListVolumesAnchor] = UNSET, external_id: Union[Unset, str] = UNSET, + status: Union[Unset, str] = UNSET, ) -> Union[Error, VolumeList] | None: """List persistent volumes @@ -252,6 +265,7 @@ async def asyncio( q (Union[Unset, str]): anchor (Union[Unset, ListVolumesAnchor]): external_id (Union[Unset, str]): + status (Union[Unset, str]): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -270,5 +284,6 @@ async def asyncio( q=q, anchor=anchor, external_id=external_id, + status=status, ) ).parsed diff --git a/src/blaxel/core/client/models/__init__.py b/src/blaxel/core/client/models/__init__.py index b59a0ad9..159a1f18 100644 --- a/src/blaxel/core/client/models/__init__.py +++ b/src/blaxel/core/client/models/__init__.py @@ -237,6 +237,7 @@ from .sandbox_fork_request import SandboxForkRequest from .sandbox_fork_response import SandboxForkResponse from .sandbox_fork_response_type import SandboxForkResponseType +from .sandbox_infrastructure_error import SandboxInfrastructureError from .sandbox_lifecycle import SandboxLifecycle from .sandbox_list import SandboxList from .sandbox_network import SandboxNetwork @@ -530,6 +531,7 @@ "SandboxForkRequest", "SandboxForkResponse", "SandboxForkResponseType", + "SandboxInfrastructureError", "SandboxLifecycle", "SandboxList", "SandboxNetwork", diff --git a/src/blaxel/core/client/models/api_key.py b/src/blaxel/core/client/models/api_key.py index b1327286..16f4f86a 100644 --- a/src/blaxel/core/client/models/api_key.py +++ b/src/blaxel/core/client/models/api_key.py @@ -19,7 +19,8 @@ class ApiKey: updated_by (Union[Unset, str]): The user or service account who updated the resource api_key (Union[Unset, str]): Api key expires_in (Union[Unset, str]): Duration until expiration. Supports formats like '30d' (30 days), '24h' (24 - hours), '1w' (1 week). If not set, the API key never expires. Example: 30d. + hours), '1w' (1 week). Must be positive and at most 10 years. If not set, the API key never expires. Example: + 30d. id (Union[Unset, str]): Api key id, to retrieve it from the API Example: ak_abc123def456. name (Union[Unset, str]): Name for the API key Example: CI/CD Pipeline Key. sub (Union[Unset, str]): User subject identifier diff --git a/src/blaxel/core/client/models/drive_spec.py b/src/blaxel/core/client/models/drive_spec.py index 6f412d3c..337deff5 100644 --- a/src/blaxel/core/client/models/drive_spec.py +++ b/src/blaxel/core/client/models/drive_spec.py @@ -17,26 +17,18 @@ class DriveSpec: """Immutable drive configuration set at creation time Attributes: - infrastructure_id (Union[Unset, str]): The internal infrastructure resource identifier for this drive (bucket - name) permissions (Union[Unset, list['DrivePermission']]): Permissions controlling which workloads can access this drive. Empty means all workloads in the workspace can access the drive. Maximum 3 permissions. region (Union[Unset, str]): Deployment region for the drive (e.g., us-pdx-1, eu-lon-1). Must match the region of resources it attaches to. Example: us-pdx-1. - size (Union[Unset, int]): Optional size limit for the drive in GB. If not specified, drive has no size limit. - Example: 100. """ - infrastructure_id: Union[Unset, str] = UNSET permissions: Union[Unset, list["DrivePermission"]] = UNSET region: Union[Unset, str] = UNSET - size: Union[Unset, int] = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: - infrastructure_id = self.infrastructure_id - permissions: Union[Unset, list[dict[str, Any]]] = UNSET if not isinstance(self.permissions, Unset): permissions = [] @@ -49,19 +41,13 @@ def to_dict(self) -> dict[str, Any]: region = self.region - size = self.size - field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) - if infrastructure_id is not UNSET: - field_dict["infrastructureId"] = infrastructure_id if permissions is not UNSET: field_dict["permissions"] = permissions if region is not UNSET: field_dict["region"] = region - if size is not UNSET: - field_dict["size"] = size return field_dict @@ -72,8 +58,6 @@ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: if not src_dict: return None d = src_dict.copy() - infrastructure_id = d.pop("infrastructureId", d.pop("infrastructure_id", UNSET)) - permissions = [] _permissions = d.pop("permissions", UNSET) for permissions_item_data in _permissions or []: @@ -83,13 +67,9 @@ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: region = d.pop("region", UNSET) - size = d.pop("size", UNSET) - drive_spec = cls( - infrastructure_id=infrastructure_id, permissions=permissions, region=region, - size=size, ) drive_spec.additional_properties = d diff --git a/src/blaxel/core/client/models/sandbox.py b/src/blaxel/core/client/models/sandbox.py index e3bb163a..d010046e 100644 --- a/src/blaxel/core/client/models/sandbox.py +++ b/src/blaxel/core/client/models/sandbox.py @@ -10,6 +10,7 @@ if TYPE_CHECKING: from ..models.core_event import CoreEvent from ..models.metadata import Metadata + from ..models.sandbox_infrastructure_error import SandboxInfrastructureError from ..models.sandbox_spec import SandboxSpec @@ -26,6 +27,8 @@ class Sandbox: and ownership information spec (SandboxSpec): Configuration for a sandbox including its image, memory, ports, region, and lifecycle policies + errors (Union[Unset, list['SandboxInfrastructureError']]): Infrastructure failures recorded on the sandbox, + oldest first (read-only, managed by the system) events (Union[Unset, list['CoreEvent']]): Events happening on a resource deployed on Blaxel expires_in (Union[Unset, int]): Time in seconds until the sandbox is automatically deleted based on TTL and lifecycle policies. Only present for sandboxes with lifecycle configured. @@ -37,6 +40,7 @@ class Sandbox: metadata: "Metadata" spec: "SandboxSpec" + errors: Union[Unset, list["SandboxInfrastructureError"]] = UNSET events: Union[Unset, list["CoreEvent"]] = UNSET expires_in: Union[Unset, int] = UNSET last_used_at: Union[Unset, str] = UNSET @@ -57,6 +61,16 @@ def to_dict(self) -> dict[str, Any]: else: spec = self.spec.to_dict() + errors: Union[Unset, list[dict[str, Any]]] = UNSET + if not isinstance(self.errors, Unset): + errors = [] + for errors_item_data in self.errors: + if type(errors_item_data) is dict: + errors_item = errors_item_data + else: + errors_item = errors_item_data.to_dict() + errors.append(errors_item) + events: Union[Unset, list[dict[str, Any]]] = UNSET if not isinstance(self.events, Unset): events = [] @@ -91,6 +105,8 @@ def to_dict(self) -> dict[str, Any]: "spec": spec, } ) + if errors is not UNSET: + field_dict["errors"] = errors if events is not UNSET: field_dict["events"] = events if expires_in is not UNSET: @@ -110,6 +126,7 @@ def to_dict(self) -> dict[str, Any]: def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: from ..models.core_event import CoreEvent from ..models.metadata import Metadata + from ..models.sandbox_infrastructure_error import SandboxInfrastructureError from ..models.sandbox_spec import SandboxSpec if not src_dict: @@ -119,6 +136,13 @@ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: spec = SandboxSpec.from_dict(d.pop("spec")) + errors = [] + _errors = d.pop("errors", UNSET) + for errors_item_data in _errors or []: + errors_item = SandboxInfrastructureError.from_dict(errors_item_data) + + errors.append(errors_item) + events = [] _events = d.pop("events", UNSET) for componentsschemas_core_events_item_data in _events or []: @@ -151,6 +175,7 @@ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: sandbox = cls( metadata=metadata, spec=spec, + errors=errors, events=events, expires_in=expires_in, last_used_at=last_used_at, diff --git a/src/blaxel/core/client/models/sandbox_infrastructure_error.py b/src/blaxel/core/client/models/sandbox_infrastructure_error.py new file mode 100644 index 00000000..e776d57f --- /dev/null +++ b/src/blaxel/core/client/models/sandbox_infrastructure_error.py @@ -0,0 +1,98 @@ +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="SandboxInfrastructureError") + + +@_attrs_define +class SandboxInfrastructureError: + """Infrastructure failure the compute plane reported for a sandbox + + Attributes: + code (Union[Unset, str]): Stable code of the failure pattern Example: VM_NETWORK_FAILURE. + fatal (Union[Unset, bool]): Whether the failure was terminal, putting the sandbox in FAILED, as opposed to being + cleared by a restart + instance (Union[Unset, str]): Instance the failure was reported for + message (Union[Unset, str]): Reason reported with the failure + time (Union[Unset, str]): Time at which the failure was recorded + """ + + code: Union[Unset, str] = UNSET + fatal: Union[Unset, bool] = UNSET + instance: Union[Unset, str] = UNSET + message: Union[Unset, str] = UNSET + time: Union[Unset, str] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + code = self.code + + fatal = self.fatal + + instance = self.instance + + message = self.message + + time = self.time + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if code is not UNSET: + field_dict["code"] = code + if fatal is not UNSET: + field_dict["fatal"] = fatal + if instance is not UNSET: + field_dict["instance"] = instance + if message is not UNSET: + field_dict["message"] = message + if time is not UNSET: + field_dict["time"] = time + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: + if not src_dict: + return None + d = src_dict.copy() + code = d.pop("code", UNSET) + + fatal = d.pop("fatal", UNSET) + + instance = d.pop("instance", UNSET) + + message = d.pop("message", UNSET) + + time = d.pop("time", UNSET) + + sandbox_infrastructure_error = cls( + code=code, + fatal=fatal, + instance=instance, + message=message, + time=time, + ) + + sandbox_infrastructure_error.additional_properties = d + return sandbox_infrastructure_error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/blaxel/core/client/models/sandbox_schedule_execution.py b/src/blaxel/core/client/models/sandbox_schedule_execution.py index d4187d3f..73d77710 100644 --- a/src/blaxel/core/client/models/sandbox_schedule_execution.py +++ b/src/blaxel/core/client/models/sandbox_schedule_execution.py @@ -15,6 +15,9 @@ class SandboxScheduleExecution: Attributes: created_at (Union[Unset, str]): Creation timestamp (read-only). + error (Union[Unset, str]): Reason the execution failed, naming the resource that could not be reached. Empty + when the command was accepted by the sandbox. Example: sandbox my-sandbox is not reachable at https://xxx.us- + pdx-1.bl.run (HTTP 404). executed_at (Union[Unset, str]): RFC 3339 time at which the command was submitted. Example: 2026-07-01T09:00:00Z. id (Union[Unset, str]): Unique id of this execution within the schedule. Example: 00000000000000000042. @@ -28,6 +31,7 @@ class SandboxScheduleExecution: """ created_at: Union[Unset, str] = UNSET + error: Union[Unset, str] = UNSET executed_at: Union[Unset, str] = UNSET id: Union[Unset, str] = UNSET process_name: Union[Unset, str] = UNSET @@ -39,6 +43,8 @@ class SandboxScheduleExecution: def to_dict(self) -> dict[str, Any]: created_at = self.created_at + error = self.error + executed_at = self.executed_at id = self.id @@ -56,6 +62,8 @@ def to_dict(self) -> dict[str, Any]: field_dict.update({}) if created_at is not UNSET: field_dict["createdAt"] = created_at + if error is not UNSET: + field_dict["error"] = error if executed_at is not UNSET: field_dict["executedAt"] = executed_at if id is not UNSET: @@ -78,6 +86,8 @@ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: d = src_dict.copy() created_at = d.pop("createdAt", d.pop("created_at", UNSET)) + error = d.pop("error", UNSET) + executed_at = d.pop("executedAt", d.pop("executed_at", UNSET)) id = d.pop("id", UNSET) @@ -92,6 +102,7 @@ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: sandbox_schedule_execution = cls( created_at=created_at, + error=error, executed_at=executed_at, id=id, process_name=process_name, diff --git a/src/blaxel/core/client/models/volume_spec.py b/src/blaxel/core/client/models/volume_spec.py index 55cec1c3..a85be91d 100644 --- a/src/blaxel/core/client/models/volume_spec.py +++ b/src/blaxel/core/client/models/volume_spec.py @@ -13,7 +13,6 @@ class VolumeSpec: """Immutable volume configuration set at creation time (size and region cannot be changed after creation) Attributes: - infrastructure_id (Union[Unset, str]): The internal infrastructure resource identifier for this volume region (Union[Unset, str]): Deployment region for the volume (e.g., us-pdx-1, eu-lon-1). Must match the region of sandboxes it attaches to. Example: us-pdx-1. size (Union[Unset, int]): Storage capacity in megabytes. Can be increased after creation but not decreased. @@ -22,15 +21,12 @@ class VolumeSpec: or "mytemplate:latest") Example: mytemplate:latest. """ - infrastructure_id: Union[Unset, str] = UNSET region: Union[Unset, str] = UNSET size: Union[Unset, int] = UNSET template: Union[Unset, str] = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: - infrastructure_id = self.infrastructure_id - region = self.region size = self.size @@ -40,8 +36,6 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) - if infrastructure_id is not UNSET: - field_dict["infrastructureId"] = infrastructure_id if region is not UNSET: field_dict["region"] = region if size is not UNSET: @@ -56,8 +50,6 @@ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: if not src_dict: return None d = src_dict.copy() - infrastructure_id = d.pop("infrastructureId", d.pop("infrastructure_id", UNSET)) - region = d.pop("region", UNSET) size = d.pop("size", UNSET) @@ -65,7 +57,6 @@ def from_dict(cls: type[T], src_dict: dict[str, Any]) -> T | None: template = d.pop("template", UNSET) volume_spec = cls( - infrastructure_id=infrastructure_id, region=region, size=size, template=template, diff --git a/src/blaxel/core/drive/drive.py b/src/blaxel/core/drive/drive.py index f38ba5cb..353fb3d8 100644 --- a/src/blaxel/core/drive/drive.py +++ b/src/blaxel/core/drive/drive.py @@ -122,7 +122,7 @@ def __init__( name: str | None = None, display_name: str | None = None, labels: Dict[str, str] | None = None, - size: int | None = None, # Size in GB + size: int | None = None, # Deprecated: drives have no size limit, this is ignored region: str | None = None, # Region permissions: list | None = None, ): @@ -173,7 +173,10 @@ def display_name(self): @property def size(self): - return self.drive.spec.size if self.drive.spec else None + """Deprecated: only legacy drives created with a size still report one.""" + if not self.drive.spec: + return None + return self.drive.spec.additional_properties.get("size") @property def region(self): @@ -201,7 +204,6 @@ async def create( labels=config.labels, ), spec=DriveSpec( - size=config.size or UNSET, region=config.region or settings.region or UNSET, permissions=config.permissions if config.permissions is not None else UNSET, ), @@ -215,7 +217,6 @@ async def create( labels=drive_config.labels, ), spec=DriveSpec( - size=drive_config.size or UNSET, region=drive_config.region or settings.region or UNSET, permissions=drive_config.permissions if drive_config.permissions is not None @@ -368,7 +369,10 @@ def display_name(self): @property def size(self): - return self.drive.spec.size if self.drive.spec else None + """Deprecated: only legacy drives created with a size still report one.""" + if not self.drive.spec: + return None + return self.drive.spec.additional_properties.get("size") @property def region(self): @@ -397,7 +401,6 @@ def create( labels=config.labels, ), spec=DriveSpec( - size=config.size or UNSET, region=config.region or settings.region or UNSET, permissions=config.permissions if config.permissions is not None else UNSET, ), @@ -411,7 +414,6 @@ def create( labels=drive_config.labels, ), spec=DriveSpec( - size=drive_config.size or UNSET, region=drive_config.region or settings.region or UNSET, permissions=drive_config.permissions if drive_config.permissions is not None @@ -564,7 +566,6 @@ async def _update_drive_by_name( labels=updates.labels, ) new_spec = DriveSpec( - size=updates.size, region=updates.region, permissions=updates.permissions, ) @@ -576,7 +577,6 @@ async def _update_drive_by_name( labels=config.labels, ) new_spec = DriveSpec( - size=config.size, region=config.region, permissions=config.permissions, ) @@ -597,9 +597,6 @@ async def _update_drive_by_name( ) merged_spec = DriveSpec( - size=new_spec.size - if new_spec and new_spec.size - else (current_drive.spec.size if current_drive.spec else None), region=new_spec.region if new_spec and new_spec.region else (current_drive.spec.region if current_drive.spec else None), @@ -644,7 +641,6 @@ def _update_drive_by_name_sync( labels=updates.labels, ) new_spec = DriveSpec( - size=updates.size, region=updates.region, permissions=updates.permissions, ) @@ -656,7 +652,6 @@ def _update_drive_by_name_sync( labels=config.labels, ) new_spec = DriveSpec( - size=config.size, region=config.region, permissions=config.permissions, ) @@ -677,9 +672,6 @@ def _update_drive_by_name_sync( ) merged_spec = DriveSpec( - size=new_spec.size - if new_spec and new_spec.size - else (current_drive.spec.size if current_drive.spec else None), region=new_spec.region if new_spec and new_spec.region else (current_drive.spec.region if current_drive.spec else None), diff --git a/src/blaxel/core/sandbox/default/sandbox.py b/src/blaxel/core/sandbox/default/sandbox.py index 9dac8850..4f60746f 100644 --- a/src/blaxel/core/sandbox/default/sandbox.py +++ b/src/blaxel/core/sandbox/default/sandbox.py @@ -23,6 +23,7 @@ Sandbox, SandboxForkRequest, SandboxForkResponse, + SandboxInfrastructureError, SandboxLifecycle, SandboxRuntime, SandboxRuntimeExtraArgs, @@ -36,7 +37,7 @@ from ...client.models.error import Error from ...client.models.sandbox_error import SandboxError from ...client.pagination import AsyncPaginatedList, make_async_paginated_list, normalize_cursor -from ...client.types import UNSET +from ...client.types import UNSET, Unset from ...common.settings import settings from ..types import ( SandboxConfiguration, @@ -215,6 +216,17 @@ def events(self): def spec(self): return self.sandbox.spec + @property + def errors(self) -> list[SandboxInfrastructureError]: + """Infrastructure failures the compute plane recorded for this sandbox, oldest first. + + Entries with ``fatal`` set are the ones that moved the sandbox to FAILED; the + others (e.g. a microVM that exited and restarted) are informational. Only + returned when a single sandbox is read, never in listings. + """ + errors = self.sandbox.errors + return list(errors) if not isinstance(errors, Unset) and errors else [] + @property def last_used_at(self): return self.sandbox.last_used_at diff --git a/src/blaxel/core/sandbox/sync/sandbox.py b/src/blaxel/core/sandbox/sync/sandbox.py index 0abbbb1c..d11219b3 100644 --- a/src/blaxel/core/sandbox/sync/sandbox.py +++ b/src/blaxel/core/sandbox/sync/sandbox.py @@ -21,6 +21,7 @@ Sandbox, SandboxForkRequest, SandboxForkResponse, + SandboxInfrastructureError, SandboxLifecycle, SandboxRuntime, SandboxRuntimeExtraArgs, @@ -34,7 +35,7 @@ from ...client.models.error import Error from ...client.models.sandbox_error import SandboxError from ...client.pagination import PaginatedList, make_paginated_list, normalize_cursor -from ...client.types import UNSET +from ...client.types import UNSET, Unset from ...common.settings import settings from ..default.sandbox import ( NON_REUSABLE_SANDBOX_STATUSES, @@ -131,6 +132,17 @@ def events(self): def spec(self): return self.sandbox.spec + @property + def errors(self) -> list[SandboxInfrastructureError]: + """Infrastructure failures the compute plane recorded for this sandbox, oldest first. + + Entries with ``fatal`` set are the ones that moved the sandbox to FAILED; the + others (e.g. a microVM that exited and restarted) are informational. Only + returned when a single sandbox is read, never in listings. + """ + errors = self.sandbox.errors + return list(errors) if not isinstance(errors, Unset) and errors else [] + @property def last_used_at(self): return self.sandbox.last_used_at diff --git a/tests/core/test_drive.py b/tests/core/test_drive.py index b8452844..96aa41b0 100644 --- a/tests/core/test_drive.py +++ b/tests/core/test_drive.py @@ -153,13 +153,13 @@ class TestDriveUpdateWithPermissions: async def test_update_permissions_via_config(self, mock_get, mock_update): existing = Drive( metadata=Metadata(name="d1"), - spec=DriveSpec(size=10, region="us-pdx-1"), + spec=DriveSpec(region="us-pdx-1"), ) mock_get.return_value = DriveInstance(existing) updated = Drive( metadata=Metadata(name="d1"), - spec=DriveSpec(size=10, region="us-pdx-1", permissions=SAMPLE_PERMISSIONS), + spec=DriveSpec(region="us-pdx-1", permissions=SAMPLE_PERMISSIONS), ) mock_update.return_value = updated @@ -175,13 +175,13 @@ async def test_update_permissions_via_config(self, mock_get, mock_update): async def test_update_permissions_via_dict(self, mock_get, mock_update): existing = Drive( metadata=Metadata(name="d1"), - spec=DriveSpec(size=10, region="us-pdx-1"), + spec=DriveSpec(region="us-pdx-1"), ) mock_get.return_value = DriveInstance(existing) updated = Drive( metadata=Metadata(name="d1"), - spec=DriveSpec(size=10, region="us-pdx-1", permissions=SAMPLE_PERMISSIONS), + spec=DriveSpec(region="us-pdx-1", permissions=SAMPLE_PERMISSIONS), ) mock_update.return_value = updated @@ -196,17 +196,17 @@ async def test_update_permissions_via_dict(self, mock_get, mock_update): async def test_update_preserves_existing_permissions(self, mock_get, mock_update): existing = Drive( metadata=Metadata(name="d1"), - spec=DriveSpec(size=10, region="us-pdx-1", permissions=SAMPLE_PERMISSIONS), + spec=DriveSpec(region="us-pdx-1", permissions=SAMPLE_PERMISSIONS), ) mock_get.return_value = DriveInstance(existing) updated = Drive( metadata=Metadata(name="d1"), - spec=DriveSpec(size=20, region="us-pdx-1", permissions=SAMPLE_PERMISSIONS), + spec=DriveSpec(region="us-pdx-1", permissions=SAMPLE_PERMISSIONS), ) mock_update.return_value = updated - await DriveInstance.update("d1", {"size": 20}) + await DriveInstance.update("d1", {"display_name": "D1"}) body = mock_update.call_args.kwargs["body"] assert body.spec.permissions is SAMPLE_PERMISSIONS @@ -217,13 +217,13 @@ async def test_read_back_permissions_from_created_drive(self, mock_get, mock_upd new_perms = [make_permission(mode="read", path="/shared")] existing = Drive( metadata=Metadata(name="d1"), - spec=DriveSpec(size=10, region="us-pdx-1"), + spec=DriveSpec(region="us-pdx-1"), ) mock_get.return_value = DriveInstance(existing) updated = Drive( metadata=Metadata(name="d1"), - spec=DriveSpec(size=10, region="us-pdx-1", permissions=new_perms), + spec=DriveSpec(region="us-pdx-1", permissions=new_perms), ) mock_update.return_value = updated diff --git a/tests/integration/core/sandbox/test_drive_acl.py b/tests/integration/core/sandbox/test_drive_acl.py index 4a7d29c1..e9a43c68 100644 --- a/tests/integration/core/sandbox/test_drive_acl.py +++ b/tests/integration/core/sandbox/test_drive_acl.py @@ -61,7 +61,6 @@ async def _create_drive_with_permissions(name: str, permissions: list[dict]) -> ), spec=DriveSpec( region=default_region, - size=1, permissions=_make_permissions(permissions), ), ) diff --git a/tests/integration/core/sandbox/test_sandbox_errors.py b/tests/integration/core/sandbox/test_sandbox_errors.py new file mode 100644 index 00000000..e5751949 --- /dev/null +++ b/tests/integration/core/sandbox/test_sandbox_errors.py @@ -0,0 +1,48 @@ +"""Integration tests for the infrastructure error history of a sandbox. + +The compute plane matches configured patterns in the microVM logs and signals +them to the control plane, which appends them to ``sandbox.errors`` +(controlplane#5198). A healthy sandbox has none, so what is asserted here is the +contract of the accessor: always a list, and never carried by a listing (the +projection drops the field, so it reads as empty too). +""" + +import pytest + +from blaxel.core import SandboxInstance +from tests.helpers import default_image, default_labels, default_region, unique_name + + +@pytest.mark.asyncio(loop_scope="class") +class TestSandboxErrors: + """Test reading the infrastructure errors recorded on a sandbox.""" + + async def test_reads_empty_error_history_on_healthy_sandbox(self): + """A sandbox that never hit an infrastructure failure reports no error.""" + name = unique_name("errors") + await SandboxInstance.create( + { + "name": name, + "image": default_image, + "region": default_region, + "labels": default_labels, + } + ) + + try: + sandbox = await SandboxInstance.get(name) + + # The shape of an entry (code, fatal, instance, message, time) is + # not exercisable here: covering it would mean provoking a real + # infrastructure failure on the compute plane. + assert isinstance(sandbox.errors, list) + assert sandbox.errors == [] + finally: + await SandboxInstance.delete(name) + + async def test_listing_does_not_carry_the_error_history(self): + """Listings project the field out, so they must not be read for it.""" + page = await SandboxInstance.list(limit=1) + + assert len(page.data) > 0 + assert page.data[0].errors == [] diff --git a/tests/manual/sandbox_errors.py b/tests/manual/sandbox_errors.py new file mode 100644 index 00000000..25095e6d --- /dev/null +++ b/tests/manual/sandbox_errors.py @@ -0,0 +1,89 @@ +"""Sample: read the infrastructure failures the compute plane recorded on a sandbox. + +The compute plane matches configured patterns in the microVM logs and signals them to +the control plane, which appends them to ``sandbox.errors`` (oldest first, bounded) and +moves the sandbox to FAILED for the fatal ones. Only a single-sandbox read returns the +array: listings never carry it. + +The dev compute plane ships two fake patterns to produce entries on demand, both matched +in the microVM logs of the sandbox:: + + echo blaxel-fake-vmm-error # non-fatal, the sandbox keeps running + echo blaxel-fake-vm-error # fatal, moves the sandbox to FAILED + +so a sandbox that never hit an incident legitimately reports an empty list. + +Credentials are picked up automatically via blaxel.core autoload (local config / env). + +Run: + + uv run python tests/manual/sandbox_errors.py + +Env vars: + NAME sandbox to read (default: create a throwaway one) + IMAGE image for the created sandbox (default blaxel/base-image:latest) + BL_REGION region to create the sandbox in (optional) + CLEANUP delete a created sandbox at the end (default "true") +""" + +import asyncio +import os +import uuid + +from blaxel.core import SandboxInstance + +NAME = os.environ.get("NAME") +IMAGE = os.environ.get("IMAGE", "blaxel/base-image:latest") +REGION = os.environ.get("BL_REGION") +CLEANUP = os.environ.get("CLEANUP", "true") != "false" + + +def log(msg: str) -> None: + print(f"[errors] {msg}") + + +async def main() -> None: + created = False + if NAME: + sandbox = await SandboxInstance.get(NAME) + else: + name = f"errors-{uuid.uuid4().hex[:8]}" + log(f"creating sandbox {name}") + sandbox = await SandboxInstance.create_if_not_exists( + { + "name": name, + "image": IMAGE, + **({"region": REGION} if REGION else {}), + } + ) + created = True + + log(f"sandbox {sandbox.metadata.name} status={sandbox.status}") + + # Always a list: empty when the sandbox never hit an infrastructure failure. + errors = sandbox.errors + log(f"{len(errors)} infrastructure error(s) recorded") + for error in errors: + log( + f" {error.time} {error.code} fatal={bool(error.fatal)} " + f"instance={error.instance or '-'} {error.message or ''}".rstrip() + ) + + fatal = [error for error in errors if error.fatal] + if fatal: + # The last fatal entry is why the sandbox is FAILED, and its code is the same + # one the gateway answers with (WORKLOAD_FAILED responses). + log(f"sandbox failed on {fatal[-1].code}") + + # Listings drop the array, so never look for a failure reason there. + page = await SandboxInstance.list(limit=1) + if page.data: + listed = page.data[0] + log(f"listed {listed.metadata.name} carries errors: {bool(listed.errors)}") + + if created and CLEANUP: + await SandboxInstance.delete(sandbox.metadata.name) + + +if __name__ == "__main__": + asyncio.run(main())