Skip to content

Commit d41c8a2

Browse files
committed
refactor(kubernetes): clarify stop phase names
Signed-off-by: Drew Newberry <anewberry@nvidia.com>
1 parent 8cd2ea4 commit d41c8a2

3 files changed

Lines changed: 57 additions & 49 deletions

File tree

‎architecture/compute-runtimes.md‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,14 @@ A driver stop operation does not complete while its backend still reports an
186186
in-progress stop. This prevents an immediate start from racing the previous
187187
run's delayed exit event and regressing the new run to `Error`.
188188

189-
The Kubernetes driver records stop as a durable two-phase transition. It first
190-
releases the sandbox's runtime-control relationship while the workload boundary
191-
remains reachable, then suspends the Agent Sandbox workload and cleans
192-
generation bootstrap material. The current dedicated-supervisor implementation
193-
releases control by deleting the supervisor Pod. Periodic reconciliation
194-
resumes either phase after a gateway restart. Pod deletion waits include the
195-
configured termination grace period plus Kubernetes API observation headroom.
189+
The Kubernetes driver records stop as a durable two-phase transition. The
190+
`releasing` phase releases the sandbox's runtime-control relationship while the
191+
workload boundary remains reachable. The `suspending` phase then suspends the
192+
Agent Sandbox workload and cleans generation bootstrap material. The current
193+
dedicated-supervisor implementation releases control by deleting the supervisor
194+
Pod. Periodic reconciliation resumes either phase after a gateway restart. Pod
195+
deletion waits include the configured termination grace period plus Kubernetes
196+
API observation headroom.
196197

197198
Persisted `Stopping` and `Starting` rows are retried at startup. Stable
198199
`Stopped` rows remain stopped. Docker and Podman retain the stopped container

‎crates/openshell-driver-kubernetes/src/driver.rs‎

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ enum SandboxRuntimeBootstrapPhase {
110110
Preparing,
111111
Released,
112112
Releasing,
113-
RollingBack,
113+
Suspending,
114114
}
115115

116116
impl SandboxRuntimeBootstrapPhase {
@@ -119,7 +119,7 @@ impl SandboxRuntimeBootstrapPhase {
119119
Self::Preparing => "preparing",
120120
Self::Released => "released",
121121
Self::Releasing => "releasing",
122-
Self::RollingBack => "rolling-back",
122+
Self::Suspending => "suspending",
123123
}
124124
}
125125

@@ -128,7 +128,7 @@ impl SandboxRuntimeBootstrapPhase {
128128
"preparing" => Some(Self::Preparing),
129129
"released" => Some(Self::Released),
130130
"releasing" => Some(Self::Releasing),
131-
"rolling-back" => Some(Self::RollingBack),
131+
"suspending" => Some(Self::Suspending),
132132
_ => None,
133133
}
134134
}
@@ -2711,14 +2711,14 @@ impl KubernetesComputeDriver {
27112711
async fn stop_sandbox_inner(&self, sandbox_id: &str) -> Result<(), KubernetesDriverError> {
27122712
let (agent_sandbox_api, kube_name, pod_name, namespace, stop_timeout, phase) =
27132713
self.prepare_sandbox_stop(sandbox_id).await?;
2714-
if phase != Some(SandboxRuntimeBootstrapPhase::RollingBack) {
2714+
if phase != Some(SandboxRuntimeBootstrapPhase::Suspending) {
27152715
self.delete_sandbox_runtime_supervisor_pod(sandbox_id, &namespace)
27162716
.await?;
27172717
patch_dynamic_object_with_resource_version_retry(
27182718
&agent_sandbox_api.api,
27192719
&kube_name,
27202720
|version| {
2721-
sandbox_runtime_rollback_patch(&agent_sandbox_api.resource.version, version)
2721+
sandbox_runtime_suspension_patch(&agent_sandbox_api.resource.version, version)
27222722
},
27232723
)
27242724
.await?;
@@ -2765,7 +2765,7 @@ impl KubernetesComputeDriver {
27652765
patch_dynamic_object_with_resource_version_retry(
27662766
&agent_sandbox_api.api,
27672767
&kube_name,
2768-
sandbox_runtime_rollback_completion_patch,
2768+
sandbox_runtime_suspension_completion_patch,
27692769
)
27702770
.await?;
27712771
return Ok(());
@@ -2833,7 +2833,7 @@ impl KubernetesComputeDriver {
28332833
let mut object = objects.pop().ok_or(KubernetesDriverError::NotFound)?;
28342834
if sandbox_runtime_bootstrap_in_progress(&object) {
28352835
let phase = sandbox_runtime_bootstrap_phase(&object);
2836-
if phase != Some(SandboxRuntimeBootstrapPhase::RollingBack)
2836+
if phase != Some(SandboxRuntimeBootstrapPhase::Suspending)
28372837
&& sandbox_runtime_bootstrap_operation(&object) != Some("restart")
28382838
{
28392839
return Err(KubernetesDriverError::Precondition(
@@ -3115,7 +3115,7 @@ impl KubernetesComputeDriver {
31153115
if !matches!(
31163116
phase,
31173117
Some(
3118-
SandboxRuntimeBootstrapPhase::Releasing | SandboxRuntimeBootstrapPhase::RollingBack
3118+
SandboxRuntimeBootstrapPhase::Releasing | SandboxRuntimeBootstrapPhase::Suspending
31193119
)
31203120
) {
31213121
patch_dynamic_object_with_resource_version_retry(
@@ -3467,9 +3467,9 @@ impl KubernetesComputeDriver {
34673467
continue;
34683468
}
34693469
if sandbox_runtime_bootstrap_phase(&object)
3470-
== Some(SandboxRuntimeBootstrapPhase::RollingBack)
3470+
== Some(SandboxRuntimeBootstrapPhase::Suspending)
34713471
{
3472-
self.reconcile_sandbox_runtime_rollback(
3472+
self.reconcile_sandbox_runtime_suspending(
34733473
&lookup_api,
34743474
&object,
34753475
&sandbox_id,
@@ -3600,7 +3600,7 @@ impl KubernetesComputeDriver {
36003600
}
36013601
}
36023602

3603-
async fn reconcile_sandbox_runtime_rollback(
3603+
async fn reconcile_sandbox_runtime_suspending(
36043604
&self,
36053605
lookup_api: &AgentSandboxApi,
36063606
object: &DynamicObject,
@@ -3620,23 +3620,23 @@ impl KubernetesComputeDriver {
36203620
Ok(true) => {}
36213621
Ok(false) => return,
36223622
Err(error) => {
3623-
debug!(sandbox_id, %error, "could not verify sandbox-runtime rollback; reconciliation will retry");
3623+
debug!(sandbox_id, %error, "could not verify sandbox-runtime suspension; reconciliation will retry");
36243624
return;
36253625
}
36263626
}
36273627
if let Err(error) = self
36283628
.delete_sandbox_runtime_supervisor(sandbox_id, namespace)
36293629
.await
36303630
{
3631-
warn!(sandbox_id, %error, "could not finish sandbox-runtime rollback cleanup");
3631+
warn!(sandbox_id, %error, "could not finish sandbox-runtime suspension cleanup");
36323632
return;
36333633
}
36343634
let Some(resource_version) = object.metadata.resource_version.as_deref() else {
36353635
return;
36363636
};
36373637
let api =
36383638
Self::agent_sandbox_api(self.client.clone(), &lookup_api.resource.version, namespace);
3639-
let patch = sandbox_runtime_rollback_completion_patch(resource_version);
3639+
let patch = sandbox_runtime_suspension_completion_patch(resource_version);
36403640
match tokio::time::timeout(
36413641
KUBE_API_TIMEOUT,
36423642
api.api
@@ -3646,10 +3646,13 @@ impl KubernetesComputeDriver {
36463646
{
36473647
Ok(Ok(_)) => {}
36483648
Ok(Err(error)) => {
3649-
debug!(sandbox_id, %error, "sandbox-runtime rollback completion raced; reconciliation will retry");
3649+
debug!(sandbox_id, %error, "sandbox-runtime suspension completion raced; reconciliation will retry");
36503650
}
36513651
Err(_) => {
3652-
warn!(sandbox_id, "timed out completing sandbox-runtime rollback");
3652+
warn!(
3653+
sandbox_id,
3654+
"timed out completing sandbox-runtime suspension"
3655+
);
36533656
}
36543657
}
36553658
}
@@ -3674,7 +3677,8 @@ impl KubernetesComputeDriver {
36743677
};
36753678
let api =
36763679
Self::agent_sandbox_api(self.client.clone(), &lookup_api.resource.version, namespace);
3677-
let patch = sandbox_runtime_rollback_patch(&lookup_api.resource.version, resource_version);
3680+
let patch =
3681+
sandbox_runtime_suspension_patch(&lookup_api.resource.version, resource_version);
36783682
match tokio::time::timeout(
36793683
KUBE_API_TIMEOUT,
36803684
api.api
@@ -3764,7 +3768,7 @@ impl KubernetesComputeDriver {
37643768
.unwrap_or(&self.config.namespace);
37653769
let api =
37663770
Self::agent_sandbox_api(self.client.clone(), &lookup_api.resource.version, namespace);
3767-
let patch = sandbox_runtime_rollback_patch(
3771+
let patch = sandbox_runtime_suspension_patch(
37683772
&lookup_api.resource.version,
37693773
object
37703774
.metadata
@@ -6603,7 +6607,7 @@ fn sandbox_operating_state_patch(
66036607
"spec": {"operatingMode": "Running"}
66046608
})
66056609
} else {
6606-
sandbox_runtime_rollback_patch(api_version, resource_version)
6610+
sandbox_runtime_suspension_patch(api_version, resource_version)
66076611
}
66086612
} else {
66096613
if running {
@@ -6612,7 +6616,7 @@ fn sandbox_operating_state_patch(
66126616
"spec": {"replicas": 1}
66136617
})
66146618
} else {
6615-
sandbox_runtime_rollback_patch(api_version, resource_version)
6619+
sandbox_runtime_suspension_patch(api_version, resource_version)
66166620
}
66176621
}
66186622
}
@@ -6632,7 +6636,10 @@ fn sandbox_runtime_stop_begin_patch(resource_version: &str) -> serde_json::Value
66326636
})
66336637
}
66346638

6635-
fn sandbox_runtime_rollback_patch(api_version: &str, resource_version: &str) -> serde_json::Value {
6639+
fn sandbox_runtime_suspension_patch(
6640+
api_version: &str,
6641+
resource_version: &str,
6642+
) -> serde_json::Value {
66366643
let desired_state = if api_version == SANDBOX_VERSION_V1BETA1 {
66376644
serde_json::json!({"operatingMode": "Suspended"})
66386645
} else {
@@ -6645,15 +6652,15 @@ fn sandbox_runtime_rollback_patch(api_version: &str, resource_version: &str) ->
66456652
ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAPPING: "true",
66466653
ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_STARTED_AT: openshell_core::time::now_ms().to_string(),
66476654
ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_OPERATION: "stop",
6648-
ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_PHASE: SandboxRuntimeBootstrapPhase::RollingBack.as_str(),
6655+
ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_PHASE: SandboxRuntimeBootstrapPhase::Suspending.as_str(),
66496656
ANNOTATION_SANDBOX_RUNTIME_READINESS: "unavailable",
66506657
},
66516658
},
66526659
"spec": desired_state,
66536660
})
66546661
}
66556662

6656-
fn sandbox_runtime_rollback_completion_patch(resource_version: &str) -> serde_json::Value {
6663+
fn sandbox_runtime_suspension_completion_patch(resource_version: &str) -> serde_json::Value {
66576664
serde_json::json!({
66586665
"metadata": {
66596666
"resourceVersion": resource_version,
@@ -7584,11 +7591,11 @@ mod tests {
75847591
);
75857592
assert!(stop_begin.get("spec").is_none());
75867593

7587-
let beta_stop = sandbox_runtime_rollback_patch(SANDBOX_VERSION_V1BETA1, "43");
7594+
let beta_stop = sandbox_runtime_suspension_patch(SANDBOX_VERSION_V1BETA1, "43");
75887595
assert_eq!(beta_stop["spec"]["operatingMode"], "Suspended");
75897596
assert!(beta_stop["spec"].get("replicas").is_none());
75907597

7591-
let alpha_stop = sandbox_runtime_rollback_patch(SANDBOX_VERSION_V1ALPHA1, "44");
7598+
let alpha_stop = sandbox_runtime_suspension_patch(SANDBOX_VERSION_V1ALPHA1, "44");
75927599
assert_eq!(alpha_stop["spec"]["replicas"], 0);
75937600
assert!(alpha_stop["spec"].get("operatingMode").is_none());
75947601

@@ -7600,7 +7607,7 @@ mod tests {
76007607
}
76017608

76027609
#[tokio::test]
7603-
async fn stop_resumed_from_rolling_back_removes_the_complete_runtime() {
7610+
async fn stop_resumed_from_suspending_removes_the_complete_runtime() {
76047611
let sandbox = serde_json::json!({
76057612
"apiVersion": "agents.x-k8s.io/v1beta1",
76067613
"kind": "Sandbox",
@@ -7611,7 +7618,7 @@ mod tests {
76117618
"annotations": {
76127619
SANDBOX_POD_NAME_ANNOTATION: "workload-pod",
76137620
ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_PHASE:
7614-
SandboxRuntimeBootstrapPhase::RollingBack.as_str()
7621+
SandboxRuntimeBootstrapPhase::Suspending.as_str()
76157622
}
76167623
},
76177624
"status": {"conditions": [{"type": "Suspended", "status": "True"}]}
@@ -7724,7 +7731,7 @@ mod tests {
77247731
tokio::time::timeout(Duration::from_secs(1), driver.stop_sandbox("sandbox-1"))
77257732
.await
77267733
.expect("stop timed out")
7727-
.expect("resume stop from RollingBack");
7734+
.expect("resume stop from Suspending");
77287735
assert!(steps.lock().unwrap().is_empty());
77297736
}
77307737

@@ -10382,24 +10389,24 @@ mod tests {
1038210389
}
1038310390

1038410391
#[test]
10385-
fn sandbox_runtime_rollback_is_durable_until_cleanup_completes() {
10386-
let rollback = sandbox_runtime_rollback_patch(SANDBOX_VERSION_V1BETA1, "42");
10387-
assert_eq!(rollback["metadata"]["resourceVersion"], "42");
10392+
fn sandbox_runtime_suspension_is_durable_until_cleanup_completes() {
10393+
let suspension = sandbox_runtime_suspension_patch(SANDBOX_VERSION_V1BETA1, "42");
10394+
assert_eq!(suspension["metadata"]["resourceVersion"], "42");
1038810395
assert_eq!(
10389-
rollback["metadata"]["annotations"][ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAPPING],
10396+
suspension["metadata"]["annotations"][ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAPPING],
1039010397
"true"
1039110398
);
1039210399
assert_eq!(
10393-
rollback["metadata"]["annotations"][ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_OPERATION],
10400+
suspension["metadata"]["annotations"][ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_OPERATION],
1039410401
"stop"
1039510402
);
1039610403
assert_eq!(
10397-
rollback["metadata"]["annotations"][ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_PHASE],
10398-
SandboxRuntimeBootstrapPhase::RollingBack.as_str()
10404+
suspension["metadata"]["annotations"][ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_PHASE],
10405+
SandboxRuntimeBootstrapPhase::Suspending.as_str()
1039910406
);
10400-
assert_eq!(rollback["spec"]["operatingMode"], "Suspended");
10407+
assert_eq!(suspension["spec"]["operatingMode"], "Suspended");
1040110408

10402-
let complete = sandbox_runtime_rollback_completion_patch("43");
10409+
let complete = sandbox_runtime_suspension_completion_patch("43");
1040310410
assert_eq!(complete["metadata"]["resourceVersion"], "43");
1040410411
for annotation in [
1040510412
ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAPPING,
@@ -10502,7 +10509,7 @@ mod tests {
1050210509

1050310510
sandbox.metadata.annotations.as_mut().unwrap().insert(
1050410511
ANNOTATION_SANDBOX_RUNTIME_BOOTSTRAP_PHASE.to_string(),
10505-
SandboxRuntimeBootstrapPhase::RollingBack
10512+
SandboxRuntimeBootstrapPhase::Suspending
1050610513
.as_str()
1050710514
.to_string(),
1050810515
);

‎skills/debug-openshell-cluster/SKILL.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -663,14 +663,14 @@ kubectl auth can-i delete pods \
663663
```
664664

665665
Do not suspend or delete the workload Pod manually. The driver advances to
666-
`rolling-back` only after runtime control has been released, and then suspends
667-
the workload.
666+
`suspending` only after runtime control has been released, and then suspends the
667+
workload.
668668

669-
If a Sandbox remains in the `rolling-back` bootstrap phase, verify that the
669+
If a Sandbox remains in the `suspending` bootstrap phase, verify that the
670670
gateway ServiceAccount can create, list, and delete Secrets in the sandbox
671671
namespace. Recovery lists generation Secrets by sandbox and component labels
672672
even when none remain, then deletes stale entries with UID preconditions before
673-
clearing the rollback annotations:
673+
clearing the suspension annotations:
674674

675675
```bash
676676
for verb in create list delete; do

0 commit comments

Comments
 (0)