ic_backup/model/ic_snapshot_upload_observation/
mod.rs1use crate::model::{
4 attempt_journal::{AttemptAuthorityRecord, AttemptJournalRecord},
5 ic_observation::{IcObservationRequestError, ObservationReservation},
6 ic_request::{IcManagementMethodRecord, IcManagementRequestRecord},
7 ic_snapshot_upload::{
8 IcSnapshotUploadAttemptError, IcSnapshotUploadKind, IcSnapshotUploadRequest,
9 original_authority,
10 },
11 operation_plan::OperationPlanRecord,
12};
13use thiserror::Error;
14
15#[derive(Debug)]
22pub struct IcSnapshotUploadObservationRequest<'request, 'source> {
23 plan: &'request OperationPlanRecord,
24 mutation: &'request IcSnapshotUploadRequest<'source>,
25 payload: &'request IcManagementRequestRecord,
26 authority: AttemptAuthorityRecord,
27 mutation_attempt: u32,
28 observation_attempt: u32,
29}
30
31impl<'request, 'source> IcSnapshotUploadObservationRequest<'request, 'source> {
32 pub fn new(
39 plan: &'request OperationPlanRecord,
40 operation_sequence: u64,
41 journal: &AttemptJournalRecord,
42 mutation: &'request IcSnapshotUploadRequest<'source>,
43 payload: &'request IcManagementRequestRecord,
44 ) -> Result<Self, IcSnapshotUploadObservationError> {
45 if !matches!(mutation.kind(), IcSnapshotUploadKind::Metadata) {
46 return Err(IcSnapshotUploadObservationError::UnsupportedUpload);
47 }
48 if payload.method() != IcManagementMethodRecord::ListCanisterSnapshots {
49 return Err(IcSnapshotUploadObservationError::UnsupportedObservation);
50 }
51 let authority = original_authority(plan, operation_sequence, journal, mutation)?;
52 payload
53 .validate_observation_binding(authority.binding(), &payload.digest())
54 .map_err(IcObservationRequestError::from)?;
55 let current = journal.view();
56 let request = Self {
57 plan,
58 mutation,
59 payload,
60 authority,
61 mutation_attempt: current
62 .pending_mutation
63 .ok_or(IcObservationRequestError::NoPendingMutation)?,
64 observation_attempt: current
65 .pending_observation
66 .ok_or(IcObservationRequestError::NoPendingObservation)?,
67 };
68 request.validate_journal(journal)?;
69 Ok(request)
70 }
71
72 #[must_use]
74 pub const fn plan(&self) -> &OperationPlanRecord {
75 self.plan
76 }
77 #[must_use]
79 pub const fn mutation(&self) -> &'request IcSnapshotUploadRequest<'source> {
80 self.mutation
81 }
82 #[must_use]
84 pub const fn payload(&self) -> &'request IcManagementRequestRecord {
85 self.payload
86 }
87 #[must_use]
89 pub const fn authority(&self) -> &AttemptAuthorityRecord {
90 &self.authority
91 }
92 #[must_use]
94 pub const fn mutation_attempt(&self) -> u32 {
95 self.mutation_attempt
96 }
97 #[must_use]
99 pub const fn observation_attempt(&self) -> u32 {
100 self.observation_attempt
101 }
102 pub fn validate_journal(
106 &self,
107 journal: &AttemptJournalRecord,
108 ) -> Result<(), IcObservationRequestError> {
109 ObservationReservation {
110 authority: &self.authority,
111 mutation_attempt: self.mutation_attempt,
112 observation_attempt: self.observation_attempt,
113 payload: self.payload,
114 }
115 .validate(journal)
116 }
117}
118
119#[derive(Debug, Error)]
121pub enum IcSnapshotUploadObservationError {
122 #[error("snapshot upload observation requires metadata intent")]
124 UnsupportedUpload,
125 #[error("snapshot upload observation requires snapshot list")]
127 UnsupportedObservation,
128 #[error(transparent)]
130 Upload(#[from] IcSnapshotUploadAttemptError),
131 #[error(transparent)]
133 Observation(#[from] IcObservationRequestError),
134}
135
136#[cfg(test)]
137mod tests;