Skip to main content

canic_core/dto/
runtime.rs

1use crate::dto::prelude::*;
2
3pub use crate::domain::runtime::{
4    FailureSeverity, HealthStatus, ReadinessStatus, RuntimeCheckStatus, RuntimeDiagnosticSeverity,
5    RuntimeFieldVisibility, RuntimeStateDomainStatus, RuntimeStatus, TimerStatus,
6};
7
8pub const RUNTIME_INTROSPECTION_SCHEMA_VERSION: u32 = 1;
9
10//
11// CanicHealthStatus
12//
13
14#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
15pub struct CanicHealthStatus {
16    pub schema_version: u32,
17    pub status: HealthStatus,
18    pub observed_at_ns: Option<u64>,
19    pub checks: Vec<RuntimeCheck>,
20}
21
22//
23// CanicReadinessStatus
24//
25
26#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
27pub struct CanicReadinessStatus {
28    pub schema_version: u32,
29    pub role: Option<String>,
30    pub status: ReadinessStatus,
31    pub observed_at_ns: u64,
32    pub checks: Vec<RuntimeCheck>,
33    pub blockers: Vec<RuntimeDiagnostic>,
34    pub warnings: Vec<RuntimeDiagnostic>,
35}
36
37//
38// CanicRuntimeStatus
39//
40
41#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
42pub struct CanicRuntimeStatus {
43    pub schema_version: u32,
44    pub observed_at_ns: u64,
45    pub canister_id: Principal,
46    pub role: Option<String>,
47    pub root: Option<Principal>,
48    pub network: Option<String>,
49    pub build: RuntimeBuildInfo,
50    pub features: Vec<RuntimeFeatureStatus>,
51    pub topology: Option<RuntimeTopologyStatus>,
52    pub timers: Vec<CanicTimerStatus>,
53    pub state: Option<RuntimeStateSummary>,
54    pub auth: Option<RuntimeAuthStatusSummary>,
55    pub blob_storage: Option<RuntimeBlobStorageStatusSummary>,
56    pub recent_failures: Vec<RecentFailure>,
57    pub visibility: Vec<RuntimeVisibilityEntry>,
58    pub readiness: CanicReadinessStatus,
59    pub status: RuntimeStatus,
60}
61
62//
63// RuntimeBuildInfo
64//
65
66#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
67pub struct RuntimeBuildInfo {
68    pub package_name: String,
69    pub package_version: String,
70    pub canic_version: String,
71    pub canister_version: u64,
72}
73
74//
75// RuntimeCheck
76//
77
78#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
79pub struct RuntimeCheck {
80    pub category: String,
81    pub code: String,
82    pub status: RuntimeCheckStatus,
83    pub subject: String,
84    pub detail: String,
85    pub next: Option<String>,
86    pub source: String,
87}
88
89//
90// RuntimeDiagnostic
91//
92
93#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
94pub struct RuntimeDiagnostic {
95    pub category: String,
96    pub code: String,
97    pub severity: RuntimeDiagnosticSeverity,
98    pub subject: String,
99    pub detail: String,
100    pub next: Option<String>,
101    pub source: String,
102}
103
104//
105// RuntimeFeatureStatus
106//
107
108#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
109pub struct RuntimeFeatureStatus {
110    pub name: String,
111    pub enabled: bool,
112    pub visibility: RuntimeFieldVisibility,
113    pub source: String,
114}
115
116//
117// RuntimeTopologyStatus
118//
119
120#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
121pub struct RuntimeTopologyStatus {
122    pub root: Option<Principal>,
123    pub parent: Option<Principal>,
124    pub subnet: Option<Principal>,
125    pub source: String,
126}
127
128//
129// CanicTimerStatus
130//
131
132#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
133pub struct CanicTimerStatus {
134    pub name: String,
135    pub subsystem: String,
136    pub status: TimerStatus,
137    pub enabled: bool,
138    pub registered: bool,
139    pub last_success_at_ns: Option<u64>,
140    pub last_failure_at_ns: Option<u64>,
141    pub next_due_at_ns: Option<u64>,
142    pub consecutive_failures: u64,
143    pub last_error_code: Option<String>,
144    pub last_error_summary: Option<String>,
145}
146
147//
148// RuntimeStateSummary
149//
150
151#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
152pub struct RuntimeStateSummary {
153    pub manifest_schema_version: u32,
154    pub domains: Vec<RuntimeStateDomainSummary>,
155    pub total_stable_memory_pages: Option<u64>,
156}
157
158//
159// RuntimeStateDomainSummary
160//
161
162#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
163pub struct RuntimeStateDomainSummary {
164    pub domain: String,
165    pub version: u32,
166    pub storage: String,
167    pub memory_id: Option<u8>,
168    pub status: RuntimeStateDomainStatus,
169}
170
171//
172// RuntimeAuthStatusSummary
173//
174
175#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
176pub struct RuntimeAuthStatusSummary {
177    pub auth_features: Vec<RuntimeFeatureStatus>,
178}
179
180//
181// RuntimeBlobStorageStatusSummary
182//
183
184#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
185pub struct RuntimeBlobStorageStatusSummary {
186    pub blob_storage_features: Vec<RuntimeFeatureStatus>,
187}
188
189//
190// RecentFailure
191//
192
193#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
194pub struct RecentFailure {
195    pub occurred_at_ns: u64,
196    pub subsystem: String,
197    pub code: String,
198    pub severity: FailureSeverity,
199    pub summary: String,
200    pub correlation_id: Option<String>,
201    pub redacted: bool,
202}
203
204//
205// RuntimeVisibilityEntry
206//
207
208#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
209pub struct RuntimeVisibilityEntry {
210    pub field: String,
211    pub visibility: RuntimeFieldVisibility,
212}
213
214#[cfg(test)]
215mod tests {
216    use super::*;
217    use candid::{Decode, Encode};
218    use serde::Serialize;
219    use serde::de::DeserializeOwned;
220    use std::fmt::Debug;
221
222    #[test]
223    fn runtime_enums_roundtrip_candid_with_canonical_variant_labels() {
224        assert_enum_candid_contract(HealthStatus::Unknown);
225        assert_enum_candid_contract(ReadinessStatus::NotEvaluated);
226        assert_enum_candid_contract(RuntimeStatus::Failing);
227        assert_enum_candid_contract(TimerStatus::NotRegistered);
228        assert_enum_candid_contract(FailureSeverity::Critical);
229        assert_enum_candid_contract(RuntimeCheckStatus::NotEvaluated);
230        assert_enum_candid_contract(RuntimeDiagnosticSeverity::Unsupported);
231        assert_enum_candid_contract(RuntimeFieldVisibility::OperatorOnly);
232        assert_enum_candid_contract(RuntimeStateDomainStatus::NotEvaluated);
233    }
234
235    #[test]
236    fn runtime_enums_serialize_canonical_snake_case_labels() {
237        assert_enum_serde_contract(HealthStatus::Healthy, HealthStatus::Healthy.label());
238        assert_enum_serde_contract(HealthStatus::Degraded, HealthStatus::Degraded.label());
239        assert_enum_serde_contract(HealthStatus::Unhealthy, HealthStatus::Unhealthy.label());
240        assert_enum_serde_contract(HealthStatus::Unknown, HealthStatus::Unknown.label());
241
242        assert_enum_serde_contract(ReadinessStatus::Ready, ReadinessStatus::Ready.label());
243        assert_enum_serde_contract(ReadinessStatus::Degraded, ReadinessStatus::Degraded.label());
244        assert_enum_serde_contract(ReadinessStatus::NotReady, ReadinessStatus::NotReady.label());
245        assert_enum_serde_contract(
246            ReadinessStatus::NotEvaluated,
247            ReadinessStatus::NotEvaluated.label(),
248        );
249
250        assert_enum_serde_contract(RuntimeStatus::Ok, RuntimeStatus::Ok.label());
251        assert_enum_serde_contract(RuntimeStatus::Degraded, RuntimeStatus::Degraded.label());
252        assert_enum_serde_contract(RuntimeStatus::Failing, RuntimeStatus::Failing.label());
253        assert_enum_serde_contract(RuntimeStatus::Unknown, RuntimeStatus::Unknown.label());
254
255        assert_enum_serde_contract(TimerStatus::Healthy, TimerStatus::Healthy.label());
256        assert_enum_serde_contract(TimerStatus::Delayed, TimerStatus::Delayed.label());
257        assert_enum_serde_contract(TimerStatus::Failing, TimerStatus::Failing.label());
258        assert_enum_serde_contract(TimerStatus::Disabled, TimerStatus::Disabled.label());
259        assert_enum_serde_contract(
260            TimerStatus::NotRegistered,
261            TimerStatus::NotRegistered.label(),
262        );
263        assert_enum_serde_contract(TimerStatus::Unknown, TimerStatus::Unknown.label());
264
265        assert_enum_serde_contract(FailureSeverity::Info, FailureSeverity::Info.label());
266        assert_enum_serde_contract(FailureSeverity::Warning, FailureSeverity::Warning.label());
267        assert_enum_serde_contract(FailureSeverity::Error, FailureSeverity::Error.label());
268        assert_enum_serde_contract(FailureSeverity::Critical, FailureSeverity::Critical.label());
269
270        assert_enum_serde_contract(RuntimeCheckStatus::Pass, RuntimeCheckStatus::Pass.label());
271        assert_enum_serde_contract(RuntimeCheckStatus::Warn, RuntimeCheckStatus::Warn.label());
272        assert_enum_serde_contract(RuntimeCheckStatus::Fail, RuntimeCheckStatus::Fail.label());
273        assert_enum_serde_contract(
274            RuntimeCheckStatus::NotEvaluated,
275            RuntimeCheckStatus::NotEvaluated.label(),
276        );
277
278        assert_enum_serde_contract(
279            RuntimeDiagnosticSeverity::Info,
280            RuntimeDiagnosticSeverity::Info.label(),
281        );
282        assert_enum_serde_contract(
283            RuntimeDiagnosticSeverity::Warning,
284            RuntimeDiagnosticSeverity::Warning.label(),
285        );
286        assert_enum_serde_contract(
287            RuntimeDiagnosticSeverity::Blocked,
288            RuntimeDiagnosticSeverity::Blocked.label(),
289        );
290        assert_enum_serde_contract(
291            RuntimeDiagnosticSeverity::Unsupported,
292            RuntimeDiagnosticSeverity::Unsupported.label(),
293        );
294
295        assert_enum_serde_contract(
296            RuntimeFieldVisibility::PublicSafe,
297            RuntimeFieldVisibility::PublicSafe.label(),
298        );
299        assert_enum_serde_contract(
300            RuntimeFieldVisibility::OperatorOnly,
301            RuntimeFieldVisibility::OperatorOnly.label(),
302        );
303        assert_enum_serde_contract(
304            RuntimeFieldVisibility::ControllerOnly,
305            RuntimeFieldVisibility::ControllerOnly.label(),
306        );
307        assert_enum_serde_contract(
308            RuntimeFieldVisibility::FeatureGated,
309            RuntimeFieldVisibility::FeatureGated.label(),
310        );
311        assert_enum_serde_contract(
312            RuntimeFieldVisibility::Disabled,
313            RuntimeFieldVisibility::Disabled.label(),
314        );
315
316        assert_enum_serde_contract(
317            RuntimeStateDomainStatus::Ok,
318            RuntimeStateDomainStatus::Ok.label(),
319        );
320        assert_enum_serde_contract(
321            RuntimeStateDomainStatus::Warning,
322            RuntimeStateDomainStatus::Warning.label(),
323        );
324        assert_enum_serde_contract(
325            RuntimeStateDomainStatus::Failing,
326            RuntimeStateDomainStatus::Failing.label(),
327        );
328        assert_enum_serde_contract(
329            RuntimeStateDomainStatus::NotEvaluated,
330            RuntimeStateDomainStatus::NotEvaluated.label(),
331        );
332    }
333
334    fn assert_enum_candid_contract<T>(value: T)
335    where
336        T: CandidType + Clone + Debug + DeserializeOwned + Eq,
337    {
338        let bytes = Encode!(&value).expect("encode runtime enum");
339        let decoded = Decode!(&bytes, T).expect("decode runtime enum");
340
341        assert_eq!(decoded, value);
342    }
343
344    fn assert_enum_serde_contract<T>(value: T, label: &str)
345    where
346        T: Clone + Debug + DeserializeOwned + Eq + Serialize,
347    {
348        let encoded = serde_cbor::to_vec(&value).expect("encode runtime enum label");
349        let serialized_label: String =
350            serde_cbor::from_slice(&encoded).expect("decode runtime enum label");
351        assert_eq!(serialized_label, label);
352
353        let label_bytes = serde_cbor::to_vec(&label).expect("encode canonical runtime enum label");
354        let decoded: T =
355            serde_cbor::from_slice(&label_bytes).expect("decode canonical runtime enum label");
356        assert_eq!(decoded, value);
357    }
358}