ic_backup/ops/persistence/restore_safety/
mod.rs1use super::{
4 BackupLayoutGuard, JournalLock, JournalLockError, OperationPlanPersistenceError,
5 PersistenceError, create_json_durable, read_json, read_operation_plan,
6};
7use crate::model::{
8 artifacts::ArtifactChecksumRecord,
9 operation_plan::OperationPlanRecord,
10 restore_safety::{
11 MAX_RESTORE_SAFETY_REQUIREMENT_BYTES, RestoreSafetyRequirementError,
12 RestoreSafetyRequirementRecord,
13 },
14};
15use thiserror::Error;
16
17pub fn create_restore_safety_requirement(
25 layout: &BackupLayoutGuard,
26 source_layout: &BackupLayoutGuard,
27 plan: &OperationPlanRecord,
28 source: &OperationPlanRecord,
29 record: &RestoreSafetyRequirementRecord,
30) -> Result<(), RestoreSafetyPersistenceError> {
31 record.validate_plans(plan, source)?;
32 read_operation_plan(layout, &plan.digest())?;
33 read_operation_plan(source_layout, &source.digest())?;
34 let path = layout.root().join("restore-safety-requirement.json");
35 let _lock = JournalLock::acquire(&path)?;
36 check_size(record)?;
37 create_json_durable(&path, record)?;
38 Ok(())
39}
40pub fn read_restore_safety_requirement(
47 layout: &BackupLayoutGuard,
48 source_layout: &BackupLayoutGuard,
49 plan: &OperationPlanRecord,
50 source: &OperationPlanRecord,
51 expected: &ArtifactChecksumRecord,
52) -> Result<RestoreSafetyRequirementRecord, RestoreSafetyPersistenceError> {
53 read_operation_plan(layout, &plan.digest())?;
54 read_operation_plan(source_layout, &source.digest())?;
55 let path = layout.root().join("restore-safety-requirement.json");
56 let _lock = JournalLock::acquire(&path)?;
57 let record: RestoreSafetyRequirementRecord =
58 read_json(&path, MAX_RESTORE_SAFETY_REQUIREMENT_BYTES)?;
59 check_size(&record)?;
60 record.validate_plans(plan, source)?;
61 if &record.digest() != expected {
62 return Err(RestoreSafetyPersistenceError::DigestMismatch);
63 }
64 Ok(record)
65}
66fn check_size(record: &RestoreSafetyRequirementRecord) -> Result<(), PersistenceError> {
67 if serde_json::to_vec_pretty(record)?.len() as u64 > MAX_RESTORE_SAFETY_REQUIREMENT_BYTES {
68 return Err(PersistenceError::RecordTooLarge {
69 limit: MAX_RESTORE_SAFETY_REQUIREMENT_BYTES,
70 });
71 }
72 Ok(())
73}
74#[derive(Debug, Error)]
76pub enum RestoreSafetyPersistenceError {
77 #[error("restore safety requirement digest mismatch")]
79 DigestMismatch,
80 #[error(transparent)]
82 Requirement(#[from] RestoreSafetyRequirementError),
83 #[error(transparent)]
85 Plan(#[from] OperationPlanPersistenceError),
86 #[error(transparent)]
88 Lock(#[from] JournalLockError),
89 #[error(transparent)]
91 Persistence(#[from] PersistenceError),
92}
93
94#[cfg(all(test, unix))]
95mod tests;