| 3511 | } |
| 3512 | |
| 3513 | pub async fn sandbox_provider_detach( |
| 3514 | server: &str, |
| 3515 | name: &str, |
| 3516 | provider: &str, |
| 3517 | tls: &TlsOptions, |
| 3518 | ) -> Result<()> { |
| 3519 | let mut client = grpc_client(server, tls).await?; |
| 3520 | |
| 3521 | // Fetch current sandbox to get resource_version for CAS |
| 3522 | let sandbox = client |
| 3523 | .get_sandbox(GetSandboxRequest { |
| 3524 | name: name.to_string(), |
| 3525 | }) |
| 3526 | .await |
| 3527 | .into_diagnostic()? |
| 3528 | .into_inner() |
| 3529 | .sandbox |
| 3530 | .ok_or_else(|| miette::miette!("sandbox not found"))?; |
| 3531 | |
| 3532 | let resource_version = sandbox.metadata.as_ref().map_or(0, |m| m.resource_version); |
| 3533 | |
| 3534 | let response = match client |
| 3535 | .detach_sandbox_provider(DetachSandboxProviderRequest { |
| 3536 | sandbox_name: name.to_string(), |
| 3537 | provider_name: provider.to_string(), |
| 3538 | expected_resource_version: resource_version, |
| 3539 | }) |
| 3540 | .await |
| 3541 | { |
| 3542 | Ok(response) => response.into_inner(), |
| 3543 | Err(status) if status.code() == Code::Aborted => { |
| 3544 | return Err(miette::miette!( |
| 3545 | "Failed to detach provider: sandbox was modified by another operation.\n\ |
| 3546 | Please retry the command." |
| 3547 | ) |
| 3548 | .with_source_code(status.message().to_string())); |
| 3549 | } |
| 3550 | Err(e) => return Err(e).into_diagnostic(), |
| 3551 | }; |
| 3552 | |
| 3553 | if response.detached { |
| 3554 | println!( |
| 3555 | "{} Detached provider {} from sandbox {}", |
| 3556 | "✓".green().bold(), |
| 3557 | provider, |
| 3558 | name |
| 3559 | ); |
| 3560 | } else { |
| 3561 | println!("Provider {provider} was not attached to sandbox {name}."); |
| 3562 | } |
| 3563 | Ok(()) |
| 3564 | } |
| 3565 | |
| 3566 | fn print_provider_attachment_table(providers: &[Provider]) { |
| 3567 | print!("{}", format_provider_attachment_table(providers, true)); |