canic_backup/plan/build/
mod.rs1mod phases;
8mod selector;
9mod targets;
10
11pub use selector::resolve_backup_selector;
12
13use crate::plan::{
14 BackupPlan, BackupPlanError, BackupScopeKind, ControlAuthority, ControlAuthoritySource,
15 QuiescencePolicy, SnapshotReadAuthority,
16};
17use crate::{manifest::IdentityMode, registry::RegistryEntry};
18use targets::{backup_target, selected_subtree_root, snapshot_targets, target_depths};
19
20pub(in crate::plan) use phases::build_backup_phases;
21
22pub struct BackupPlanBuildInput<'a> {
30 pub plan_id: String,
31 pub run_id: String,
32 pub fleet: String,
33 pub environment: String,
34 pub root_canister_id: String,
35 pub selected_canister_id: Option<String>,
36 pub selected_scope_kind: BackupScopeKind,
37 pub include_descendants: bool,
38 pub topology_hash_before_quiesce: String,
39 pub registry: &'a [RegistryEntry],
40 pub control_authority: ControlAuthority,
41 pub snapshot_read_authority: SnapshotReadAuthority,
42 pub quiescence_policy: QuiescencePolicy,
43 pub identity_mode: IdentityMode,
44}
45
46pub fn build_backup_plan(input: BackupPlanBuildInput<'_>) -> Result<BackupPlan, BackupPlanError> {
48 let snapshot_read_authority = input.snapshot_read_authority.clone();
49 let quiescence_policy = input.quiescence_policy.clone();
50 let root_included = input.selected_scope_kind == BackupScopeKind::MaintenanceRoot;
51 let selected_subtree_root = selected_subtree_root(&input)?;
52 let snapshot_targets = snapshot_targets(&input)?;
53 let target_depths = target_depths(input.registry);
54 let targets = snapshot_targets
55 .into_iter()
56 .map(|target| {
57 backup_target(
58 target,
59 &target_depths,
60 input.control_authority.clone(),
61 input.snapshot_read_authority.clone(),
62 input.identity_mode.clone(),
63 )
64 })
65 .collect::<Vec<_>>();
66 let phases = build_backup_phases(&targets);
67
68 let plan = BackupPlan {
69 plan_version: 1,
70 plan_id: input.plan_id,
71 run_id: input.run_id,
72 fleet: input.fleet,
73 environment: input.environment,
74 root_canister_id: input.root_canister_id,
75 selected_subtree_root,
76 selected_scope_kind: input.selected_scope_kind,
77 include_descendants: input.include_descendants,
78 root_included,
79 requires_root_controller: input.control_authority.source
80 == ControlAuthoritySource::RootController,
81 snapshot_read_authority,
82 quiescence_policy,
83 topology_hash_before_quiesce: input.topology_hash_before_quiesce,
84 targets,
85 phases,
86 };
87 plan.validate()?;
88 Ok(plan)
89}