Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,8 @@ async fn kill_refuses_signals_it_cannot_deliver_before_cleanup_admission() {
};

for state in SandboxState::all() {
let deliverable = matches!(state, SandboxState::Started | SandboxState::Paused);
let deliverable =
crate::service::tests::stop_kill_admission_tests::fatal_kill_admits(state);
for signal in [9, 15] {
let (service, id) = service_with(Some(state));
let case = format!("{state} signal {signal}");
Expand Down
28 changes: 16 additions & 12 deletions crates/libs/sbx/mgr/server/src/service/grpc_lifecycle/kill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ impl SandboxManagerService {
return Err(Status::invalid_argument("signal must be non-zero"));
}

// Must be running or paused to receive a signal
if !matches!(sandbox.state, SandboxState::Started | SandboxState::Paused) {
return Err(Status::failed_precondition(format!(
"cannot kill: sandbox is {}, not started or paused",
sandbox.state
)));
}

// Only fatal signals (SIGKILL=9, SIGTERM=15) trigger state transition and cleanup.
// Non-fatal signals (e.g. SIGHUP, SIGUSR1) are just forwarded to the process.
let is_fatal = signal == 9 || signal == 15;
if !is_fatal {
// A forwarded signal starts no cleanup, so it never supersedes an
// in-flight operation.
if !matches!(sandbox.state, SandboxState::Started | SandboxState::Paused) {
return Err(Status::failed_precondition(format!(
"cannot kill: sandbox is {}, not started or paused",
sandbox.state
)));
}
let mut node_client = connect_node(&self.node_manager)
.await
.map_err(|e| Status::internal(format!("cannot connect to node-manager: {e}")))?;
Expand All @@ -51,10 +51,14 @@ impl SandboxManagerService {
return Ok(Response::new(KillResponse {}));
}

sandbox
.state
.transition(SandboxState::Stopping)
.map_err(Status::from)?;
// A fatal signal stops the sandbox, so it is admitted exactly where a
// stop may supersede the current state.
if !sandbox.state.can_transition_to(SandboxState::Stopping) {
return Err(Status::failed_precondition(format!(
"cannot kill: sandbox is {}, which cannot stop",
sandbox.state
)));
}

let (sandbox_id, uuid8) = Self::cleanup_identity(id, Some(&sandbox.uuid8))?;
let completion = CleanupCompletion::MarkStopped;
Expand Down
3 changes: 3 additions & 0 deletions crates/libs/sbx/mgr/server/src/service/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ mod local_backup_inventory_tests;
#[cfg(test)]
pub(crate) mod node_manager_transport_tests;

#[cfg(test)]
pub(crate) mod stop_kill_admission_tests;

#[cfg(test)]
pub(crate) mod service_tests {
use super::start_support::*;
Expand Down
Loading
Loading