Skip to main content

canic_core/dto/
runtime.rs

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