Skip to content

Commit 30a7491

Browse files
author
secus
committed
Add function to get all deployment pods including terminating
1 parent 1f43777 commit 30a7491

2 files changed

Lines changed: 100 additions & 0 deletions

File tree

src/handlers/logs.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,37 @@ pub async fn get_deployment_pods(
8383
// Found pods for deployment
8484
Ok(Json(PodsResponse { pods }))
8585
}
86+
87+
/// Get all pods for deployment including terminating ones (for debugging)
88+
pub async fn get_deployment_pods_debug(
89+
State(state): State<AppState>,
90+
Path(deployment_id): Path<Uuid>,
91+
user: AuthUser,
92+
) -> Result<Json<PodsResponse>, AppError> {
93+
// Verify deployment ownership
94+
if !verify_deployment_ownership(&state, deployment_id, user.user_id).await? {
95+
error!("User {} does not own deployment {}", user.user_id, deployment_id);
96+
return Err(AppError::not_found("Deployment not found"));
97+
}
98+
99+
let k8s_service = KubernetesService::for_deployment(&deployment_id, &user.user_id).await?;
100+
101+
let k8s_pods: Vec<crate::services::kubernetes::PodInfo> = k8s_service.get_deployment_pods_all(&deployment_id).await?;
102+
103+
// Convert from k8s PodInfo to our response PodInfo
104+
let pods: Vec<PodInfo> = k8s_pods.into_iter().map(|pod| PodInfo {
105+
name: pod.name,
106+
status: pod.status,
107+
ready: pod.ready,
108+
restart_count: pod.restart_count,
109+
node_name: pod.node_name,
110+
created_at: pod.created_at,
111+
}).collect();
112+
113+
// Found all pods for deployment (including terminating)
114+
Ok(Json(PodsResponse { pods }))
115+
}
116+
86117
pub async fn get_pod_logs(
87118
State(state): State<AppState>,
88119
Path((deployment_id, pod_name)): Path<(Uuid, String)>,

src/services/kubernetes.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,13 +1350,23 @@ async fn detect_cluster_type(&self) -> Result<String, AppError> {
13501350

13511351
let mut pod_infos = Vec::new();
13521352
for pod in pod_list.items {
1353+
// Skip pods that are marked for deletion (Terminating state)
1354+
if pod.metadata.deletion_timestamp.is_some() {
1355+
continue;
1356+
}
1357+
13531358
if let Some(name) = &pod.metadata.name {
13541359
let status = if let Some(pod_status) = &pod.status {
13551360
pod_status.phase.clone().unwrap_or_else(|| "Unknown".to_string())
13561361
} else {
13571362
"Unknown".to_string()
13581363
};
13591364

1365+
// Only include pods that are not in Terminating state
1366+
if status == "Terminating" {
1367+
continue;
1368+
}
1369+
13601370
let ready = if let Some(pod_status) = &pod.status {
13611371
pod_status.container_statuses
13621372
.as_ref()
@@ -1387,6 +1397,65 @@ async fn detect_cluster_type(&self) -> Result<String, AppError> {
13871397

13881398
Ok(pod_infos)
13891399
}
1400+
1401+
/// Get all pods for deployment including terminating ones (for debugging)
1402+
pub async fn get_deployment_pods_all(&self, deployment_id: &Uuid) -> Result<Vec<PodInfo>, AppError> {
1403+
use k8s_openapi::api::core::v1::Pod;
1404+
use kube::api::{Api, ListParams};
1405+
1406+
let pods: Api<Pod> = Api::namespaced(self.client.clone(), &self.namespace);
1407+
let lp = ListParams::default().labels(&format!("deployment-id={}", deployment_id));
1408+
1409+
let pod_list = pods
1410+
.list(&lp)
1411+
.await
1412+
.map_err(|e| AppError::internal(&format!("Failed to list pods: {}", e)))?;
1413+
1414+
let mut pod_infos = Vec::new();
1415+
for pod in pod_list.items {
1416+
if let Some(name) = &pod.metadata.name {
1417+
let status = if let Some(pod_status) = &pod.status {
1418+
// Check if pod is marked for deletion
1419+
if pod.metadata.deletion_timestamp.is_some() {
1420+
"Terminating".to_string()
1421+
} else {
1422+
pod_status.phase.clone().unwrap_or_else(|| "Unknown".to_string())
1423+
}
1424+
} else {
1425+
"Unknown".to_string()
1426+
};
1427+
1428+
let ready = if let Some(pod_status) = &pod.status {
1429+
pod_status.container_statuses
1430+
.as_ref()
1431+
.map(|statuses| statuses.iter().all(|cs| cs.ready))
1432+
.unwrap_or(false)
1433+
} else {
1434+
false
1435+
};
1436+
1437+
pod_infos.push(PodInfo {
1438+
name: name.clone(),
1439+
status,
1440+
ready,
1441+
restart_count: if let Some(pod_status) = &pod.status {
1442+
pod_status.container_statuses
1443+
.as_ref()
1444+
.map(|statuses| statuses.iter().map(|cs| cs.restart_count).sum())
1445+
.unwrap_or(0)
1446+
} else {
1447+
0
1448+
},
1449+
node_name: pod.spec.as_ref().and_then(|s| s.node_name.clone()),
1450+
created_at: pod.metadata.creation_timestamp
1451+
.map(|ts| ts.0.format("%Y-%m-%d %H:%M:%S UTC").to_string()),
1452+
});
1453+
}
1454+
}
1455+
1456+
Ok(pod_infos)
1457+
}
1458+
13901459
pub async fn get_pod_logs(
13911460
&self,
13921461
pod_name: &str,

0 commit comments

Comments
 (0)