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