Skip to main content

lightshuttle_runtime/lifecycle/
view.rs

1//! Lightweight value types exposed by the control plane.
2//!
3//! Built on demand by [`crate::ManagerHandle`] and surfaced through the
4//! [`crate::LifecycleHandle`] trait. The shape is intentionally stable
5//! across runtime backends so callers (REST API, dashboard, CLI) never
6//! see backend-specific types.
7
8use std::time::SystemTime;
9
10use serde::{Deserialize, Serialize};
11
12use crate::lifecycle::status::NodeStatus;
13use lightshuttle_spec::ImageSource;
14
15/// Dashboard-friendly view of a single managed resource.
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17pub struct ResourceView {
18    /// Manifest-declared resource name.
19    pub name: String,
20    /// Resource kind discriminant (`postgres`, `redis`, `container`, `dockerfile`).
21    pub kind: String,
22    /// Coarse-grained status suitable for UI rendering.
23    pub status: ResourceStatus,
24    /// Whether the resource passed its healthcheck.
25    pub healthy: bool,
26    /// Container image reference, as resolved at start time.
27    pub image: String,
28    /// Wall-clock time at which the runtime accepted the start request.
29    pub started_at: Option<SystemTime>,
30    /// Last terminal failure reason, when applicable.
31    pub last_error: Option<String>,
32}
33
34/// Coarse-grained resource status, derived from [`NodeStatus`] and
35/// flattened for UI consumption.
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
37pub enum ResourceStatus {
38    /// Not started yet.
39    Pending,
40    /// Container is booting up.
41    Starting,
42    /// Container is up, with or without a green healthcheck.
43    Running,
44    /// Resource has entered a terminal failure state.
45    Failed,
46    /// Resource has been stopped on request.
47    Stopped,
48}
49
50impl From<&NodeStatus> for ResourceStatus {
51    fn from(status: &NodeStatus) -> Self {
52        match status {
53            NodeStatus::Pending => Self::Pending,
54            NodeStatus::Starting => Self::Starting,
55            NodeStatus::Running | NodeStatus::Healthy => Self::Running,
56            NodeStatus::Failed { .. } => Self::Failed,
57            NodeStatus::Stopped => Self::Stopped,
58        }
59    }
60}
61
62/// Render an [`ImageSource`] as the user-facing image reference: the
63/// pulled image string for `Pull`, the produced tag for `Build`.
64pub(crate) fn image_label(src: &ImageSource) -> String {
65    match src {
66        ImageSource::Pull(s) => s.clone(),
67        ImageSource::Build { tag, .. } => tag.clone(),
68    }
69}
70
71/// Extract the last error message from a [`NodeStatus`], when terminal.
72pub(crate) fn last_error_from(status: &NodeStatus) -> Option<String> {
73    match status {
74        NodeStatus::Failed { reason } => Some(reason.clone()),
75        _ => None,
76    }
77}