Delete a sandbox container and its workspace volume.
(
&self,
sandbox_id: &str,
sandbox_name: &str,
)
| 624 | |
| 625 | /// Delete a sandbox container and its workspace volume. |
| 626 | pub async fn delete_sandbox( |
| 627 | &self, |
| 628 | sandbox_id: &str, |
| 629 | sandbox_name: &str, |
| 630 | ) -> Result<bool, ComputeDriverError> { |
| 631 | if sandbox_id.is_empty() { |
| 632 | return Err(ComputeDriverError::Precondition( |
| 633 | "sandbox id is required".into(), |
| 634 | )); |
| 635 | } |
| 636 | let name = validated_container_name(sandbox_name)?; |
| 637 | info!( |
| 638 | sandbox_id = %sandbox_id, |
| 639 | sandbox_name = %sandbox_name, |
| 640 | container = %name, |
| 641 | "Deleting sandbox container" |
| 642 | ); |
| 643 | |
| 644 | // Use the request's stable sandbox ID as the source of truth for |
| 645 | // cleanup. Inspect is only used as a best-effort cross-check so |
| 646 | // cleanup still works if the container is already gone or mislabeled. |
| 647 | match self.client.inspect_container(&name).await { |
| 648 | Ok(inspect) => match inspect.config.labels.get(LABEL_SANDBOX_ID) { |
| 649 | Some(label_id) if label_id != sandbox_id => { |
| 650 | warn!( |
| 651 | sandbox_id = %sandbox_id, |
| 652 | sandbox_name = %sandbox_name, |
| 653 | container = %name, |
| 654 | label_sandbox_id = %label_id, |
| 655 | "Container label sandbox ID did not match delete request; cleaning up using request sandbox_id" |
| 656 | ); |
| 657 | } |
| 658 | None => { |
| 659 | warn!( |
| 660 | sandbox_id = %sandbox_id, |
| 661 | sandbox_name = %sandbox_name, |
| 662 | container = %name, |
| 663 | "Container missing '{}' label; cleaning up using request sandbox_id", |
| 664 | LABEL_SANDBOX_ID, |
| 665 | ); |
| 666 | } |
| 667 | Some(_) => {} |
| 668 | }, |
| 669 | Err(PodmanApiError::NotFound(_)) => {} |
| 670 | Err(e) => return Err(ComputeDriverError::from(e)), |
| 671 | } |
| 672 | |
| 673 | // Stop (best-effort). |
| 674 | let _ = self |
| 675 | .client |
| 676 | .stop_container(&name, self.config.stop_timeout_secs) |
| 677 | .await; |
| 678 | |
| 679 | // Remove container. If NotFound, the container was removed between |
| 680 | // inspect and here (TOCTOU race); proceed with volume cleanup |
| 681 | // since the workspace volume is idempotent to remove. |
| 682 | let container_existed = match self.client.remove_container(&name).await { |
| 683 | Ok(()) => true, |
no test coverage detected