Skip to main content

canic_backup/plan/
types.rs

1use crate::manifest::IdentityMode;
2use serde::{Deserialize, Serialize};
3
4///
5/// BackupPlan
6///
7
8#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
9pub struct BackupPlan {
10    pub plan_id: String,
11    pub run_id: String,
12    pub fleet: String,
13    pub network: String,
14    pub root_canister_id: String,
15    pub selected_subtree_root: Option<String>,
16    pub selected_scope_kind: BackupScopeKind,
17    pub include_descendants: bool,
18    pub root_included: bool,
19    pub requires_root_controller: bool,
20    pub snapshot_read_authority: SnapshotReadAuthority,
21    pub quiescence_policy: QuiescencePolicy,
22    pub topology_hash_before_quiesce: String,
23    pub targets: Vec<BackupTarget>,
24    pub phases: Vec<BackupOperation>,
25}
26
27///
28/// BackupScopeKind
29///
30
31#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
32#[serde(rename_all = "kebab-case")]
33pub enum BackupScopeKind {
34    Member,
35    Subtree,
36    NonRootFleet,
37    MaintenanceRoot,
38}
39
40///
41/// BackupTarget
42///
43
44#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
45pub struct BackupTarget {
46    pub canister_id: String,
47    pub role: Option<String>,
48    pub parent_canister_id: Option<String>,
49    pub depth: u32,
50    pub control_authority: ControlAuthority,
51    pub snapshot_read_authority: SnapshotReadAuthority,
52    pub identity_mode: IdentityMode,
53    pub expected_module_hash: Option<String>,
54}
55
56///
57/// AuthorityEvidence
58///
59
60#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
61#[serde(rename_all = "kebab-case")]
62pub enum AuthorityEvidence {
63    Proven,
64    Declared,
65    Unknown,
66}
67
68///
69/// ControlAuthority
70///
71
72#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
73pub struct ControlAuthority {
74    pub source: ControlAuthoritySource,
75    pub evidence: AuthorityEvidence,
76}
77
78impl ControlAuthority {
79    #[must_use]
80    pub const fn unknown() -> Self {
81        Self {
82            source: ControlAuthoritySource::Unknown,
83            evidence: AuthorityEvidence::Unknown,
84        }
85    }
86
87    #[must_use]
88    pub const fn root_controller(evidence: AuthorityEvidence) -> Self {
89        Self {
90            source: ControlAuthoritySource::RootController,
91            evidence,
92        }
93    }
94
95    #[must_use]
96    pub const fn operator_controller(evidence: AuthorityEvidence) -> Self {
97        Self {
98            source: ControlAuthoritySource::OperatorController,
99            evidence,
100        }
101    }
102
103    #[must_use]
104    pub fn alternate_controller(
105        controller: impl Into<String>,
106        reason: impl Into<String>,
107        evidence: AuthorityEvidence,
108    ) -> Self {
109        Self {
110            source: ControlAuthoritySource::AlternateController {
111                controller: controller.into(),
112                reason: reason.into(),
113            },
114            evidence,
115        }
116    }
117
118    #[must_use]
119    pub fn is_proven(&self) -> bool {
120        self.evidence == AuthorityEvidence::Proven && self.source != ControlAuthoritySource::Unknown
121    }
122
123    #[must_use]
124    pub fn is_proven_root_controller(&self) -> bool {
125        self.evidence == AuthorityEvidence::Proven
126            && self.source == ControlAuthoritySource::RootController
127    }
128}
129
130///
131/// ControlAuthoritySource
132///
133
134#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
135#[serde(rename_all = "kebab-case", tag = "kind")]
136pub enum ControlAuthoritySource {
137    Unknown,
138    RootController,
139    OperatorController,
140    AlternateController { controller: String, reason: String },
141}
142
143///
144/// SnapshotReadAuthority
145///
146
147#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
148pub struct SnapshotReadAuthority {
149    pub source: SnapshotReadAuthoritySource,
150    pub evidence: AuthorityEvidence,
151}
152
153impl SnapshotReadAuthority {
154    #[must_use]
155    pub const fn unknown() -> Self {
156        Self {
157            source: SnapshotReadAuthoritySource::Unknown,
158            evidence: AuthorityEvidence::Unknown,
159        }
160    }
161
162    #[must_use]
163    pub const fn operator_controller(evidence: AuthorityEvidence) -> Self {
164        Self {
165            source: SnapshotReadAuthoritySource::OperatorController,
166            evidence,
167        }
168    }
169
170    #[must_use]
171    pub const fn snapshot_visibility(evidence: AuthorityEvidence) -> Self {
172        Self {
173            source: SnapshotReadAuthoritySource::SnapshotVisibility,
174            evidence,
175        }
176    }
177
178    #[must_use]
179    pub const fn root_configured_read(evidence: AuthorityEvidence) -> Self {
180        Self {
181            source: SnapshotReadAuthoritySource::RootConfiguredRead,
182            evidence,
183        }
184    }
185
186    #[must_use]
187    pub const fn root_mediated_transfer(evidence: AuthorityEvidence) -> Self {
188        Self {
189            source: SnapshotReadAuthoritySource::RootMediatedTransfer,
190            evidence,
191        }
192    }
193
194    #[must_use]
195    pub fn is_proven(&self) -> bool {
196        self.evidence == AuthorityEvidence::Proven
197            && self.source != SnapshotReadAuthoritySource::Unknown
198    }
199}
200
201///
202/// SnapshotReadAuthoritySource
203///
204
205#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
206#[serde(rename_all = "kebab-case")]
207pub enum SnapshotReadAuthoritySource {
208    Unknown,
209    OperatorController,
210    SnapshotVisibility,
211    RootConfiguredRead,
212    RootMediatedTransfer,
213}
214
215///
216/// QuiescencePolicy
217///
218
219#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
220#[serde(rename_all = "kebab-case")]
221pub enum QuiescencePolicy {
222    CrashConsistent,
223    RootCoordinated,
224    AppQuiesced,
225}
226
227///
228/// BackupOperation
229///
230
231#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
232pub struct BackupOperation {
233    pub operation_id: String,
234    pub order: u32,
235    pub kind: BackupOperationKind,
236    pub target_canister_id: Option<String>,
237}
238
239///
240/// BackupOperationKind
241///
242
243#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
244#[serde(rename_all = "kebab-case")]
245pub enum BackupOperationKind {
246    ValidateTopology,
247    ValidateControlAuthority,
248    ValidateSnapshotReadAuthority,
249    ValidateQuiescencePolicy,
250    Stop,
251    CreateSnapshot,
252    Start,
253    DownloadSnapshot,
254    VerifyArtifact,
255    FinalizeManifest,
256}
257
258///
259/// BackupReceipt
260///
261
262#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
263pub struct BackupReceipt {
264    pub plan_id: String,
265    pub operation_id: String,
266    pub status: BackupReceiptStatus,
267    pub target_canister_id: Option<String>,
268    pub snapshot_id: Option<String>,
269    pub message: Option<String>,
270}
271
272///
273/// BackupReceiptStatus
274///
275
276#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
277#[serde(rename_all = "kebab-case")]
278pub enum BackupReceiptStatus {
279    Completed,
280    Failed,
281    Skipped,
282}
283
284///
285/// BackupExecutionPreflightReceipts
286///
287
288#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
289pub struct BackupExecutionPreflightReceipts {
290    pub plan_id: String,
291    pub preflight_id: String,
292    pub validated_at: String,
293    pub expires_at: String,
294    pub topology: TopologyPreflightReceipt,
295    pub control_authority: Vec<ControlAuthorityReceipt>,
296    pub snapshot_read_authority: Vec<SnapshotReadAuthorityReceipt>,
297    pub quiescence: QuiescencePreflightReceipt,
298}
299
300///
301/// ControlAuthorityReceipt
302///
303
304#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
305pub struct ControlAuthorityReceipt {
306    pub plan_id: String,
307    pub preflight_id: String,
308    pub target_canister_id: String,
309    pub authority: ControlAuthority,
310    pub proof_source: AuthorityProofSource,
311    pub validated_at: String,
312    pub expires_at: String,
313    pub message: Option<String>,
314}
315
316///
317/// SnapshotReadAuthorityReceipt
318///
319
320#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
321pub struct SnapshotReadAuthorityReceipt {
322    pub plan_id: String,
323    pub preflight_id: String,
324    pub target_canister_id: String,
325    pub authority: SnapshotReadAuthority,
326    pub proof_source: AuthorityProofSource,
327    pub validated_at: String,
328    pub expires_at: String,
329    pub message: Option<String>,
330}
331
332///
333/// AuthorityProofSource
334///
335
336#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
337#[serde(rename_all = "kebab-case")]
338pub enum AuthorityProofSource {
339    RootCoordination,
340    ManagementStatus,
341    SnapshotReadCheck,
342    Declaration,
343    Unknown,
344}
345
346///
347/// ControlAuthorityPreflightRequest
348///
349
350#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
351pub struct ControlAuthorityPreflightRequest {
352    pub plan_id: String,
353    pub run_id: String,
354    pub fleet: String,
355    pub network: String,
356    pub root_canister_id: String,
357    pub requires_root_controller: bool,
358    pub targets: Vec<ControlAuthorityPreflightTarget>,
359}
360
361///
362/// ControlAuthorityPreflightTarget
363///
364
365#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
366pub struct ControlAuthorityPreflightTarget {
367    pub canister_id: String,
368    pub role: Option<String>,
369    pub parent_canister_id: Option<String>,
370    pub declared_authority: ControlAuthority,
371}
372
373impl From<&BackupTarget> for ControlAuthorityPreflightTarget {
374    fn from(target: &BackupTarget) -> Self {
375        Self {
376            canister_id: target.canister_id.clone(),
377            role: target.role.clone(),
378            parent_canister_id: target.parent_canister_id.clone(),
379            declared_authority: target.control_authority.clone(),
380        }
381    }
382}
383
384///
385/// SnapshotReadAuthorityPreflightRequest
386///
387
388#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
389pub struct SnapshotReadAuthorityPreflightRequest {
390    pub plan_id: String,
391    pub run_id: String,
392    pub fleet: String,
393    pub network: String,
394    pub root_canister_id: String,
395    pub targets: Vec<SnapshotReadAuthorityPreflightTarget>,
396}
397
398///
399/// SnapshotReadAuthorityPreflightTarget
400///
401
402#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
403pub struct SnapshotReadAuthorityPreflightTarget {
404    pub canister_id: String,
405    pub role: Option<String>,
406    pub parent_canister_id: Option<String>,
407    pub declared_authority: SnapshotReadAuthority,
408}
409
410impl From<&BackupTarget> for SnapshotReadAuthorityPreflightTarget {
411    fn from(target: &BackupTarget) -> Self {
412        Self {
413            canister_id: target.canister_id.clone(),
414            role: target.role.clone(),
415            parent_canister_id: target.parent_canister_id.clone(),
416            declared_authority: target.snapshot_read_authority.clone(),
417        }
418    }
419}
420
421///
422/// TopologyPreflightRequest
423///
424
425#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
426pub struct TopologyPreflightRequest {
427    pub plan_id: String,
428    pub run_id: String,
429    pub fleet: String,
430    pub network: String,
431    pub root_canister_id: String,
432    pub selected_subtree_root: Option<String>,
433    pub selected_scope_kind: BackupScopeKind,
434    pub topology_hash_before_quiesce: String,
435    pub targets: Vec<TopologyPreflightTarget>,
436}
437
438///
439/// TopologyPreflightTarget
440///
441
442#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
443pub struct TopologyPreflightTarget {
444    pub canister_id: String,
445    pub parent_canister_id: Option<String>,
446    pub depth: u32,
447}
448
449impl From<&BackupTarget> for TopologyPreflightTarget {
450    fn from(target: &BackupTarget) -> Self {
451        Self {
452            canister_id: target.canister_id.clone(),
453            parent_canister_id: target.parent_canister_id.clone(),
454            depth: target.depth,
455        }
456    }
457}
458
459///
460/// TopologyPreflightReceipt
461///
462
463#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
464pub struct TopologyPreflightReceipt {
465    pub plan_id: String,
466    pub preflight_id: String,
467    pub topology_hash_before_quiesce: String,
468    pub topology_hash_at_preflight: String,
469    pub targets: Vec<TopologyPreflightTarget>,
470    pub validated_at: String,
471    pub expires_at: String,
472    pub message: Option<String>,
473}
474
475///
476/// QuiescencePreflightRequest
477///
478
479#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
480pub struct QuiescencePreflightRequest {
481    pub plan_id: String,
482    pub run_id: String,
483    pub fleet: String,
484    pub network: String,
485    pub root_canister_id: String,
486    pub selected_subtree_root: Option<String>,
487    pub quiescence_policy: QuiescencePolicy,
488    pub targets: Vec<QuiescencePreflightTarget>,
489}
490
491///
492/// QuiescencePreflightTarget
493///
494
495#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
496pub struct QuiescencePreflightTarget {
497    pub canister_id: String,
498    pub role: Option<String>,
499    pub parent_canister_id: Option<String>,
500}
501
502impl From<&BackupTarget> for QuiescencePreflightTarget {
503    fn from(target: &BackupTarget) -> Self {
504        Self {
505            canister_id: target.canister_id.clone(),
506            role: target.role.clone(),
507            parent_canister_id: target.parent_canister_id.clone(),
508        }
509    }
510}
511
512///
513/// QuiescencePreflightReceipt
514///
515
516#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
517pub struct QuiescencePreflightReceipt {
518    pub plan_id: String,
519    pub preflight_id: String,
520    pub quiescence_policy: QuiescencePolicy,
521    pub accepted: bool,
522    pub targets: Vec<QuiescencePreflightTarget>,
523    pub validated_at: String,
524    pub expires_at: String,
525    pub message: Option<String>,
526}