Skip to main content

signstar_config/nethsm/
state.rs

1//! Common types for state representation of a NetHSM.
2
3use crate::{
4    nethsm::{NetHsmConfigState, backend::NetHsmBackendState},
5    state::{StateDiff, StateDiffFailure, StateDiffFailureTarget, StateDiffReport},
6};
7
8/// The diff between [`NetHsmConfigState`] and [`NetHsmBackendState`].
9#[derive(Debug)]
10pub struct NetHsmDiff<'config_state, 'backend_state, 'config_items> {
11    /// The reference to the state of a NetHSM config.
12    pub config: &'config_state NetHsmConfigState<'config_items>,
13
14    /// The reference to the state of a NetHSM backend.
15    pub backend: &'backend_state NetHsmBackendState,
16}
17
18impl<'config_state, 'backend_state, 'config_items> StateDiff<'config_state, 'backend_state>
19    for NetHsmDiff<'config_state, 'backend_state, 'config_items>
20{
21    fn diff(&self) -> StateDiffReport<'config_state, 'backend_state> {
22        if self.config == self.backend {
23            return StateDiffReport::Success;
24        }
25
26        let user_state_discrepancies = {
27            let mut matched_config_states = Vec::new();
28            let mut state_discrepancies = Vec::new();
29
30            'outer: for backend_user_state in self.backend.user_states.iter() {
31                for config_user_state in self.config.user_data.iter() {
32                    // The states match.
33                    if config_user_state == backend_user_state {
34                        matched_config_states.push(config_user_state);
35                        continue 'outer;
36                    }
37
38                    // The unique backend user name matches, but not the remaining data.
39                    if &backend_user_state.name == config_user_state.user {
40                        matched_config_states.push(config_user_state);
41                        state_discrepancies.push(StateDiffFailure::Mismatch {
42                            one: Box::new(self.config),
43                            other: Box::new(self.backend),
44                            one_state: config_user_state.to_string(),
45                            other_state: backend_user_state.to_string(),
46                        });
47                        continue 'outer;
48                    }
49                }
50
51                // No match has been found.
52                state_discrepancies.push(StateDiffFailure::DoesNotExist {
53                    one: Box::new(self.config),
54                    other: Box::new(self.backend),
55                    target: StateDiffFailureTarget::One,
56                    state: backend_user_state.to_string(),
57                });
58            }
59
60            // Unmatched config states.
61            self.config
62                .user_data
63                .iter()
64                .filter(|state| !matched_config_states.contains(state))
65                .for_each(|config_user_state| {
66                    state_discrepancies.push(StateDiffFailure::DoesNotExist {
67                        one: Box::new(self.config),
68                        other: Box::new(self.backend),
69                        target: StateDiffFailureTarget::Other,
70                        state: config_user_state.to_string(),
71                    })
72                });
73
74            state_discrepancies
75        };
76
77        let key_state_discrepancies = {
78            let mut matched_config_states = Vec::new();
79            let mut state_discrepancies = Vec::new();
80
81            'outer: for backend_key_state in self.backend.key_states.iter() {
82                for config_key_state in self.config.key_data.iter() {
83                    // The states match.
84                    if config_key_state == backend_key_state {
85                        matched_config_states.push(config_key_state);
86                        continue 'outer;
87                    }
88
89                    // The unique backend name and namespace matches, but not the remaining data.
90                    if &backend_key_state.name == config_key_state.key_id
91                        && backend_key_state.namespace.as_ref() == config_key_state.user.namespace()
92                    {
93                        matched_config_states.push(config_key_state);
94                        state_discrepancies.push(StateDiffFailure::Mismatch {
95                            one: Box::new(self.config),
96                            other: Box::new(self.backend),
97                            one_state: config_key_state.to_string(),
98                            other_state: backend_key_state.to_string(),
99                        });
100                        continue 'outer;
101                    }
102                }
103
104                // No match has been found.
105                state_discrepancies.push(StateDiffFailure::DoesNotExist {
106                    one: Box::new(self.config),
107                    other: Box::new(self.backend),
108                    target: StateDiffFailureTarget::One,
109                    state: backend_key_state.to_string(),
110                });
111            }
112
113            // Unmatched other states.
114            self.config
115                .key_data
116                .iter()
117                .filter(|state| !matched_config_states.contains(state))
118                .for_each(|key_state| {
119                    state_discrepancies.push(StateDiffFailure::DoesNotExist {
120                        one: Box::new(self.config),
121                        other: Box::new(self.backend),
122                        target: StateDiffFailureTarget::Other,
123                        state: key_state.to_string(),
124                    })
125                });
126
127            state_discrepancies
128        };
129
130        let messages = {
131            let mut output = Vec::new();
132            output.extend(user_state_discrepancies);
133            output.extend(key_state_discrepancies);
134            output
135        };
136
137        if messages.is_empty() {
138            return StateDiffReport::Success;
139        }
140
141        StateDiffReport::Failure { messages }
142    }
143}