Skip to main content

canic_backup/execution/
types.rs

1use crate::plan::BackupOperationKind;
2use serde::{Deserialize, Serialize};
3use thiserror::Error as ThisError;
4
5///
6/// BackupExecutionJournal
7///
8
9#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
10pub struct BackupExecutionJournal {
11    pub journal_version: u16,
12    pub plan_id: String,
13    pub run_id: String,
14    pub preflight_id: Option<String>,
15    pub preflight_accepted: bool,
16    pub restart_required: bool,
17    pub operations: Vec<BackupExecutionJournalOperation>,
18    pub operation_receipts: Vec<BackupExecutionOperationReceipt>,
19}
20
21///
22/// BackupExecutionJournalOperation
23///
24
25#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
26pub struct BackupExecutionJournalOperation {
27    pub sequence: usize,
28    pub operation_id: String,
29    pub kind: BackupOperationKind,
30    pub target_canister_id: Option<String>,
31    pub state: BackupExecutionOperationState,
32    pub state_updated_at: Option<String>,
33    pub blocking_reasons: Vec<String>,
34}
35
36///
37/// BackupExecutionOperationState
38///
39
40#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
41#[serde(rename_all = "kebab-case")]
42pub enum BackupExecutionOperationState {
43    Ready,
44    Pending,
45    Blocked,
46    Completed,
47    Failed,
48    Skipped,
49}
50
51///
52/// BackupExecutionOperationReceipt
53///
54
55#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
56pub struct BackupExecutionOperationReceipt {
57    pub plan_id: String,
58    pub run_id: String,
59    pub preflight_id: Option<String>,
60    pub sequence: usize,
61    pub operation_id: String,
62    pub kind: BackupOperationKind,
63    pub target_canister_id: Option<String>,
64    pub outcome: BackupExecutionOperationReceiptOutcome,
65    pub updated_at: Option<String>,
66    pub snapshot_id: Option<String>,
67    pub artifact_path: Option<String>,
68    pub checksum: Option<String>,
69    pub failure_reason: Option<String>,
70}
71
72///
73/// BackupExecutionOperationReceiptOutcome
74///
75
76#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
77#[serde(rename_all = "kebab-case")]
78pub enum BackupExecutionOperationReceiptOutcome {
79    Completed,
80    Failed,
81    Skipped,
82}
83
84///
85/// BackupExecutionResumeSummary
86///
87
88#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
89pub struct BackupExecutionResumeSummary {
90    pub plan_id: String,
91    pub run_id: String,
92    pub preflight_id: Option<String>,
93    pub preflight_accepted: bool,
94    pub restart_required: bool,
95    pub total_operations: usize,
96    pub ready_operations: usize,
97    pub pending_operations: usize,
98    pub blocked_operations: usize,
99    pub completed_operations: usize,
100    pub failed_operations: usize,
101    pub skipped_operations: usize,
102    pub next_operation: Option<BackupExecutionJournalOperation>,
103}
104
105///
106/// BackupExecutionJournalError
107///
108
109#[derive(Debug, ThisError)]
110pub enum BackupExecutionJournalError {
111    #[error("invalid backup plan for execution journal: {0}")]
112    InvalidPlan(String),
113
114    #[error("unsupported backup execution journal version {0}")]
115    UnsupportedVersion(u16),
116
117    #[error("backup execution journal field {0} is required")]
118    MissingField(&'static str),
119
120    #[error("backup execution journal has duplicate operation sequence {0}")]
121    DuplicateSequence(usize),
122
123    #[error("backup execution journal is missing operation sequence {0}")]
124    MissingSequence(usize),
125
126    #[error("accepted preflight is missing preflight_id")]
127    AcceptedPreflightMissingId,
128
129    #[error("preflight already accepted as {existing}, cannot accept {attempted}")]
130    PreflightAlreadyAccepted { existing: String, attempted: String },
131
132    #[error("preflight receipt plan id {actual} does not match execution journal plan {expected}")]
133    PreflightPlanMismatch { expected: String, actual: String },
134
135    #[error("mutating operation {sequence} is ready before preflight acceptance")]
136    MutationReadyBeforePreflight { sequence: usize },
137
138    #[error("mutating operation {sequence} cannot run before preflight acceptance")]
139    MutationBeforePreflightAccepted { sequence: usize },
140
141    #[error("operation {0} is missing a blocking or failure reason")]
142    OperationMissingReason(usize),
143
144    #[error("operation {0} cannot have blocking reasons in its current state")]
145    UnblockedOperationHasReasons(usize),
146
147    #[error("operation {0} was not found")]
148    OperationNotFound(usize),
149
150    #[error("operation {sequence} cannot transition from {from:?} to {to:?}")]
151    InvalidOperationTransition {
152        sequence: usize,
153        from: BackupExecutionOperationState,
154        to: BackupExecutionOperationState,
155    },
156
157    #[error("operation {requested} cannot advance before operation {next}")]
158    OutOfOrderOperationTransition { requested: usize, next: usize },
159
160    #[error("no operation can be advanced")]
161    NoTransitionableOperation,
162
163    #[error("operation {0} is not failed")]
164    OperationNotFailed(usize),
165
166    #[error("operation receipt references missing operation {0}")]
167    ReceiptOperationNotFound(usize),
168
169    #[error("operation receipt does not match operation {sequence}")]
170    ReceiptOperationMismatch { sequence: usize },
171
172    #[error("operation receipt does not match journal {sequence}")]
173    ReceiptJournalMismatch { sequence: usize },
174
175    #[error("operation receipt does not match accepted preflight {sequence}")]
176    ReceiptPreflightMismatch { sequence: usize },
177
178    #[error("operation receipt {sequence} has no pending operation")]
179    ReceiptWithoutPendingOperation { sequence: usize },
180}