Skip to content

Commit 46d844f

Browse files
committed
Add missing update functions to rust and python sdks.
1 parent 28084bc commit 46d844f

5 files changed

Lines changed: 72 additions & 2 deletions

File tree

crates/cloud-sdk/src/sandboxes/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use models::{
1414
DaemonInfo, HealthResponse, ListDirectoryResponse, ListProcessesResponse,
1515
ListSandboxPoolsResponse, ListSandboxesResponse, ListSnapshotsResponse, OutputEvent,
1616
OutputResponse, ProcessInfo, SandboxInfo, SandboxPoolInfo, SandboxPoolRequest,
17-
SendSignalResponse, SnapshotInfo,
17+
SendSignalResponse, SnapshotInfo, UpdateSandboxRequest,
1818
};
1919

2020
/// A client for managing sandbox lifecycle, pool, and snapshot APIs.
@@ -91,6 +91,19 @@ impl SandboxesClient {
9191
Ok(list.sandboxes)
9292
}
9393

94+
pub async fn update(
95+
&self,
96+
sandbox_id: &str,
97+
request: &UpdateSandboxRequest,
98+
) -> Result<SandboxInfo, SdkError> {
99+
let uri = self.endpoint(&format!("sandboxes/{sandbox_id}"));
100+
let req = self
101+
.client
102+
.build_post_json_request(Method::PATCH, &uri, request)?;
103+
let resp = self.client.execute(req).await?;
104+
Self::parse_json(resp).await
105+
}
106+
94107
pub async fn delete(&self, sandbox_id: &str) -> Result<(), SdkError> {
95108
let uri = self.endpoint(&format!("sandboxes/{sandbox_id}"));
96109
let req = self.client.request(Method::DELETE, &uri).build()?;

crates/cloud-sdk/src/sandboxes/models.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ pub struct CreateSandboxRequest {
4242
pub name: Option<String>,
4343
}
4444

45+
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
46+
pub struct UpdateSandboxRequest {
47+
#[serde(skip_serializing_if = "Option::is_none")]
48+
pub name: Option<String>,
49+
}
50+
4551
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4652
pub struct SandboxPoolRequest {
4753
#[serde(skip_serializing_if = "Option::is_none")]

crates/rust-cloud-sdk-py/src/lib.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ use tensorlake_cloud_sdk::images::ImagesClient;
2222
use tensorlake_cloud_sdk::images::models::{
2323
ApplicationBuildContext, CreateApplicationBuildRequest,
2424
};
25-
use tensorlake_cloud_sdk::sandboxes::models::{CreateSandboxRequest, SandboxPoolRequest};
25+
use tensorlake_cloud_sdk::sandboxes::models::{
26+
CreateSandboxRequest, SandboxPoolRequest, UpdateSandboxRequest,
27+
};
2628
use tensorlake_cloud_sdk::sandboxes::{SandboxProxyClient, SandboxesClient};
2729
use tensorlake_cloud_sdk::{Client, ClientBuilder, error::SdkError};
2830
use tokio::runtime::Runtime;
@@ -611,6 +613,18 @@ impl CloudSandboxClient {
611613
})
612614
}
613615

616+
fn update_sandbox(&self, sandbox_id: String, request_json: String) -> PyResult<String> {
617+
let request: UpdateSandboxRequest = parse_json_payload(&request_json)?;
618+
self.run_with_retry(5, move |client| {
619+
let sandbox_id = sandbox_id.clone();
620+
let request = request.clone();
621+
async move {
622+
let response = client.update(&sandbox_id, &request).await?;
623+
Ok(serde_json::to_string(&response)?)
624+
}
625+
})
626+
}
627+
614628
fn delete_sandbox(&self, sandbox_id: String) -> PyResult<()> {
615629
self.run_with_retry(5, move |client| {
616630
let sandbox_id = sandbox_id.clone();

src/tensorlake/sandbox/client.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
SandboxStatus,
3232
SnapshotInfo,
3333
SnapshotStatus,
34+
UpdateSandboxRequest,
3435
)
3536

3637
try:
@@ -364,6 +365,36 @@ def list(self) -> list[SandboxInfo]:
364365
except Exception as e:
365366
_raise_as_sandbox_error(e)
366367

368+
def update_sandbox(self, sandbox_id: str, name: str) -> SandboxInfo:
369+
"""Update a sandbox's properties.
370+
371+
Currently supports updating the sandbox name. Naming an ephemeral sandbox
372+
makes it non-ephemeral and enables suspend/resume.
373+
374+
Args:
375+
sandbox_id: ID of the sandbox to update
376+
name: New name for the sandbox
377+
378+
Returns:
379+
SandboxInfo with updated sandbox details
380+
381+
Raises:
382+
SandboxNotFoundError: If sandbox doesn't exist
383+
RemoteAPIError: If the API request fails
384+
SandboxConnectionError: If the server is unreachable
385+
"""
386+
request = UpdateSandboxRequest(name=name)
387+
try:
388+
response_json = self._rust_client.update_sandbox(
389+
sandbox_id=sandbox_id,
390+
request_json=request.model_dump_json(exclude_none=True),
391+
)
392+
return SandboxInfo.model_validate_json(response_json)
393+
except Exception as e:
394+
if _rust_status_code(e) == 404:
395+
raise SandboxNotFoundError(sandbox_id) from None
396+
_raise_as_sandbox_error(e)
397+
367398
def delete(self, sandbox_id: str) -> None:
368399
"""Terminate a sandbox.
369400

src/tensorlake/sandbox/models.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ class CreateSandboxRequest(BaseModel):
108108
name: str | None = None
109109

110110

111+
class UpdateSandboxRequest(BaseModel):
112+
"""Request payload for updating a sandbox."""
113+
114+
name: str | None = None
115+
116+
111117
class SandboxPoolRequest(BaseModel):
112118
"""Request payload for creating or updating a sandbox pool."""
113119

0 commit comments

Comments
 (0)