Skip to main content

canic_backup/plan/
error.rs

1use crate::discovery::DiscoveryError;
2use thiserror::Error as ThisError;
3
4///
5/// BackupPlanError
6///
7
8#[derive(Debug, ThisError)]
9pub enum BackupPlanError {
10    #[error("field {0} must not be empty")]
11    EmptyField(&'static str),
12
13    #[error("field {field} must be a valid principal: {value}")]
14    InvalidPrincipal { field: &'static str, value: String },
15
16    #[error("field {field} must be a 64-character hex topology hash: {value}")]
17    InvalidTopologyHash { field: &'static str, value: String },
18
19    #[error("field {field} must be a unix timestamp marker: {value}")]
20    InvalidTimestamp { field: &'static str, value: String },
21
22    #[error("backup plan has no targets")]
23    EmptyTargets,
24
25    #[error("backup plan has no phases")]
26    EmptyPhases,
27
28    #[error("duplicate backup target {0}")]
29    DuplicateTarget(String),
30
31    #[error("duplicate backup operation id {0}")]
32    DuplicateOperationId(String),
33
34    #[error("operation {operation_id} has order {order}, expected {expected}")]
35    OperationOrderMismatch {
36        operation_id: String,
37        order: u32,
38        expected: u32,
39    },
40
41    #[error("normal backup scope must not include root")]
42    RootIncludedWithoutMaintenance,
43
44    #[error("maintenance root scope must include root")]
45    MaintenanceRootExcludesRoot,
46
47    #[error("selected scope root {0} is not present in plan targets")]
48    SelectedRootNotInTargets(String),
49
50    #[error("non-root-fleet scope must not declare a selected subtree root")]
51    NonRootFleetHasSelectedRoot,
52
53    #[error("target {0} has no proven control authority")]
54    UnprovenControlAuthority(String),
55
56    #[error("target {0} has no proven snapshot read authority")]
57    UnprovenTargetSnapshotReadAuthority(String),
58
59    #[error("target {0} must be controllable by root for this plan")]
60    MissingRootController(String),
61
62    #[error("target {0} has no control authority receipt")]
63    MissingControlAuthorityReceipt(String),
64
65    #[error("target {0} has no snapshot read authority receipt")]
66    MissingSnapshotReadAuthorityReceipt(String),
67
68    #[error("authority receipt targets unknown canister {0}")]
69    UnknownAuthorityReceiptTarget(String),
70
71    #[error("duplicate authority receipt for target {0}")]
72    DuplicateAuthorityReceipt(String),
73
74    #[error("authority receipt plan id {actual} does not match plan {expected}")]
75    AuthorityReceiptPlanMismatch { expected: String, actual: String },
76
77    #[error("authority receipt preflight id {actual} does not match preflight {expected}")]
78    AuthorityReceiptPreflightMismatch { expected: String, actual: String },
79
80    #[error("preflight receipt plan id {actual} does not match plan {expected}")]
81    PreflightReceiptPlanMismatch { expected: String, actual: String },
82
83    #[error("preflight receipt id {actual} does not match preflight {expected}")]
84    PreflightReceiptIdMismatch { expected: String, actual: String },
85
86    #[error(
87        "preflight receipt {preflight_id} is not valid yet at {as_of}; validated at {validated_at}"
88    )]
89    PreflightReceiptNotYetValid {
90        preflight_id: String,
91        validated_at: String,
92        as_of: String,
93    },
94
95    #[error("preflight receipt {preflight_id} expired at {expires_at}; checked at {as_of}")]
96    PreflightReceiptExpired {
97        preflight_id: String,
98        expires_at: String,
99        as_of: String,
100    },
101
102    #[error("preflight receipt {preflight_id} has invalid validity window")]
103    PreflightReceiptInvalidWindow { preflight_id: String },
104
105    #[error("topology preflight hash drifted from {expected} to {actual}")]
106    TopologyPreflightHashMismatch { expected: String, actual: String },
107
108    #[error("topology preflight targets do not match selected plan targets")]
109    TopologyPreflightTargetsMismatch,
110
111    #[error("quiescence preflight policy does not match plan")]
112    QuiescencePolicyMismatch,
113
114    #[error("quiescence preflight was not accepted")]
115    QuiescencePreflightRejected,
116
117    #[error("quiescence preflight targets do not match selected plan targets")]
118    QuiescencePreflightTargetsMismatch,
119
120    #[error("operation {operation_id} targets unknown canister {target_canister_id}")]
121    UnknownOperationTarget {
122        operation_id: String,
123        target_canister_id: String,
124    },
125
126    #[error("backup selector {0} did not match a live topology node")]
127    UnknownSelector(String),
128
129    #[error("backup selector {selector} matched multiple canisters: {matches:?}")]
130    AmbiguousSelector {
131        selector: String,
132        matches: Vec<String>,
133    },
134
135    #[error("required preflight operation {0} is missing")]
136    MissingPreflight(&'static str),
137
138    #[error("mutating operation {operation_id} appears before required preflights")]
139    MutationBeforePreflight { operation_id: String },
140
141    #[error(transparent)]
142    Discovery(#[from] DiscoveryError),
143}