Skip to content

Commit ac35c2c

Browse files
committed
fix(cli): report scheduling failure when sandbox create times out
When the sandbox pod cannot be scheduled, the readiness timeout message only showed Ready=False (ConfigurationPending) although the sandbox status already carried PodScheduled=False with the scheduler's reason. Prefer a failing PodScheduled condition when summarizing why the sandbox is not ready, and fall back to the Ready condition as before. Signed-off-by: Jane Chen <gojane20@gmail.com>
1 parent c3c6746 commit ac35c2c

2 files changed

Lines changed: 106 additions & 3 deletions

File tree

‎crates/openshell-cli/src/commands/common.rs‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,13 +573,29 @@ pub fn print_sandbox_header(
573573
// Sandbox provisioning helpers
574574
// ---------------------------------------------------------------------------
575575

576+
/// Summarize why a sandbox is not ready yet.
577+
///
578+
/// A failing `PodScheduled` condition (for example `Unschedulable` with the
579+
/// scheduler's "0/N nodes are available" message) is preferred because the
580+
/// `Ready` condition may be replaced by a less specific reason such as
581+
/// `ConfigurationPending` while the pod cannot be placed.
576582
pub fn ready_false_condition_message(
577583
status: Option<&openshell_core::proto::SandboxStatus>,
578584
) -> Option<String> {
579-
let condition = status?.conditions.iter().find(|condition| {
580-
condition.r#type == "Ready" && condition.status.eq_ignore_ascii_case("false")
581-
})?;
585+
let conditions = &status?.conditions;
586+
let false_condition_message = |condition_type: &str| {
587+
conditions
588+
.iter()
589+
.filter(|condition| {
590+
condition.r#type == condition_type && condition.status.eq_ignore_ascii_case("false")
591+
})
592+
.find_map(condition_summary)
593+
};
594+
595+
false_condition_message("PodScheduled").or_else(|| false_condition_message("Ready"))
596+
}
582597

598+
fn condition_summary(condition: &openshell_core::proto::SandboxCondition) -> Option<String> {
583599
if condition.message.is_empty() {
584600
if condition.reason.is_empty() {
585601
None

‎crates/openshell-cli/src/run.rs‎

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8258,6 +8258,93 @@ mod tests {
82588258
assert!(ready_false_condition_message(Some(&status)).is_none());
82598259
}
82608260

8261+
#[test]
8262+
fn ready_false_condition_message_prefers_unschedulable_pod_scheduled_condition() {
8263+
let status = SandboxStatus {
8264+
agent_pod: "pending-pod".to_string(),
8265+
conditions: vec![
8266+
SandboxCondition {
8267+
r#type: "Ready".to_string(),
8268+
status: "False".to_string(),
8269+
reason: "ConfigurationPending".to_string(),
8270+
message: "Waiting for effective configuration validation".to_string(),
8271+
transition_time: None,
8272+
},
8273+
SandboxCondition {
8274+
r#type: "PodScheduled".to_string(),
8275+
status: "False".to_string(),
8276+
reason: "Unschedulable".to_string(),
8277+
message: "0/11 nodes are available: 11 Insufficient cpu.".to_string(),
8278+
transition_time: None,
8279+
},
8280+
],
8281+
..Default::default()
8282+
};
8283+
8284+
assert_eq!(
8285+
ready_false_condition_message(Some(&status)).as_deref(),
8286+
Some("Unschedulable: 0/11 nodes are available: 11 Insufficient cpu.")
8287+
);
8288+
}
8289+
8290+
#[test]
8291+
fn ready_false_condition_message_ignores_scheduled_pod_condition() {
8292+
let status = SandboxStatus {
8293+
agent_pod: "scheduled-pod".to_string(),
8294+
conditions: vec![
8295+
SandboxCondition {
8296+
r#type: "PodScheduled".to_string(),
8297+
status: "True".to_string(),
8298+
reason: String::new(),
8299+
message: String::new(),
8300+
transition_time: None,
8301+
},
8302+
SandboxCondition {
8303+
r#type: "Ready".to_string(),
8304+
status: "False".to_string(),
8305+
reason: "ConfigurationPending".to_string(),
8306+
message: "Waiting for effective configuration validation".to_string(),
8307+
transition_time: None,
8308+
},
8309+
],
8310+
..Default::default()
8311+
};
8312+
8313+
assert_eq!(
8314+
ready_false_condition_message(Some(&status)).as_deref(),
8315+
Some("ConfigurationPending: Waiting for effective configuration validation")
8316+
);
8317+
}
8318+
8319+
#[test]
8320+
fn ready_false_condition_message_falls_back_when_pod_scheduled_has_no_detail() {
8321+
let status = SandboxStatus {
8322+
agent_pod: "pending-pod".to_string(),
8323+
conditions: vec![
8324+
SandboxCondition {
8325+
r#type: "PodScheduled".to_string(),
8326+
status: "False".to_string(),
8327+
reason: String::new(),
8328+
message: String::new(),
8329+
transition_time: None,
8330+
},
8331+
SandboxCondition {
8332+
r#type: "Ready".to_string(),
8333+
status: "False".to_string(),
8334+
reason: "ConfigurationPending".to_string(),
8335+
message: String::new(),
8336+
transition_time: None,
8337+
},
8338+
],
8339+
..Default::default()
8340+
};
8341+
8342+
assert_eq!(
8343+
ready_false_condition_message(Some(&status)).as_deref(),
8344+
Some("ConfigurationPending")
8345+
);
8346+
}
8347+
82618348
#[test]
82628349
fn provisioning_timeout_message_includes_condition_and_gpu_hint() {
82638350
let resource_requirements = ResourceRequirements {

0 commit comments

Comments
 (0)