ic_backup/ops/persistence/operation_plan/
mod.rs1use super::{
4 BackupLayoutGuard, JournalLock, JournalLockError, PersistenceError, create_json_durable,
5 read_json,
6};
7use crate::model::{
8 artifacts::ArtifactChecksumRecord,
9 operation_plan::{MAX_OPERATION_PLAN_BYTES, OperationPlanRecord},
10};
11use thiserror::Error;
12
13pub fn create_operation_plan(
21 layout: &BackupLayoutGuard,
22 record: &OperationPlanRecord,
23) -> Result<(), OperationPlanPersistenceError> {
24 layout.check_root()?;
25 let path = layout.root().join("operation-plan.json");
26 let _lock = JournalLock::acquire(&path)?;
27 check_size(record)?;
28 create_json_durable(&path, record)?;
29 Ok(())
30}
31
32pub fn read_operation_plan(
40 layout: &BackupLayoutGuard,
41 expected: &ArtifactChecksumRecord,
42) -> Result<OperationPlanRecord, OperationPlanPersistenceError> {
43 layout.check_root()?;
44 let path = layout.root().join("operation-plan.json");
45 let _lock = JournalLock::acquire(&path)?;
46 let record: OperationPlanRecord = read_json(&path, MAX_OPERATION_PLAN_BYTES)?;
47 check_size(&record)?;
48 if &record.digest() != expected {
49 return Err(OperationPlanPersistenceError::DigestMismatch);
50 }
51 Ok(record)
52}
53fn check_size(record: &OperationPlanRecord) -> Result<(), PersistenceError> {
54 if serde_json::to_vec_pretty(record)?.len() as u64 > MAX_OPERATION_PLAN_BYTES {
55 return Err(PersistenceError::RecordTooLarge {
56 limit: MAX_OPERATION_PLAN_BYTES,
57 });
58 }
59 Ok(())
60}
61
62#[derive(Debug, Error)]
64pub enum OperationPlanPersistenceError {
65 #[error("operation plan digest mismatch")]
67 DigestMismatch,
68 #[error(transparent)]
70 Lock(#[from] JournalLockError),
71 #[error(transparent)]
73 Persistence(#[from] PersistenceError),
74}
75
76#[cfg(all(test, unix))]
77mod tests;