winterbaume_accessanalyzer/
views.rs1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4use winterbaume_core::{StateChangeNotifier, StateViewError, StatefulService};
5
6use crate::handlers::AccessAnalyzerService;
7use crate::state::{AccessAnalyzerState, AnalyzerState};
8use crate::types::{Analyzer, ArchiveRule, CriterionValue};
9
10#[derive(Debug, Clone, Serialize, Deserialize, Default)]
11pub struct AccessAnalyzerStateView {
12 #[serde(default)]
13 pub analyzers: HashMap<String, AnalyzerView>,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct AnalyzerView {
18 pub arn: String,
19 pub name: String,
20 pub analyzer_type: String,
21 pub status: String,
22 pub created_at: String,
23 #[serde(default)]
24 pub tags: HashMap<String, String>,
25 #[serde(default)]
26 pub archive_rules: HashMap<String, ArchiveRuleView>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct ArchiveRuleView {
31 pub rule_name: String,
32 pub filter: HashMap<String, CriterionValueView>,
33 pub created_at: String,
34 pub updated_at: String,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct CriterionValueView {
39 #[serde(default)]
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub eq: Option<Vec<String>>,
42 #[serde(default)]
43 #[serde(skip_serializing_if = "Option::is_none")]
44 pub neq: Option<Vec<String>>,
45 #[serde(default)]
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub contains: Option<Vec<String>>,
48 #[serde(default)]
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub exists: Option<bool>,
51}
52
53impl From<&AccessAnalyzerState> for AccessAnalyzerStateView {
56 fn from(state: &AccessAnalyzerState) -> Self {
57 AccessAnalyzerStateView {
58 analyzers: state
59 .analyzers
60 .iter()
61 .map(|(k, v)| (k.clone(), AnalyzerView::from(v)))
62 .collect(),
63 }
64 }
65}
66
67impl From<&AnalyzerState> for AnalyzerView {
68 fn from(s: &AnalyzerState) -> Self {
69 AnalyzerView {
70 arn: s.analyzer.arn.clone(),
71 name: s.analyzer.name.clone(),
72 analyzer_type: s.analyzer.analyzer_type.clone(),
73 status: s.analyzer.status.clone(),
74 created_at: s.analyzer.created_at.clone(),
75 tags: s.analyzer.tags.clone(),
76 archive_rules: s
77 .archive_rules
78 .iter()
79 .map(|(k, v)| (k.clone(), ArchiveRuleView::from(v)))
80 .collect(),
81 }
82 }
83}
84
85impl From<&ArchiveRule> for ArchiveRuleView {
86 fn from(r: &ArchiveRule) -> Self {
87 ArchiveRuleView {
88 rule_name: r.rule_name.clone(),
89 filter: r
90 .filter
91 .iter()
92 .map(|(k, v)| (k.clone(), CriterionValueView::from(v)))
93 .collect(),
94 created_at: r.created_at.clone(),
95 updated_at: r.updated_at.clone(),
96 }
97 }
98}
99
100impl From<&CriterionValue> for CriterionValueView {
101 fn from(c: &CriterionValue) -> Self {
102 CriterionValueView {
103 eq: c.eq.clone(),
104 neq: c.neq.clone(),
105 contains: c.contains.clone(),
106 exists: c.exists,
107 }
108 }
109}
110
111impl From<AccessAnalyzerStateView> for AccessAnalyzerState {
114 fn from(view: AccessAnalyzerStateView) -> Self {
115 AccessAnalyzerState {
116 analyzers: view
117 .analyzers
118 .into_iter()
119 .map(|(k, v)| (k, AnalyzerState::from(v)))
120 .collect(),
121 }
122 }
123}
124
125impl From<AnalyzerView> for AnalyzerState {
126 fn from(v: AnalyzerView) -> Self {
127 AnalyzerState {
128 analyzer: Analyzer {
129 arn: v.arn,
130 name: v.name,
131 analyzer_type: v.analyzer_type,
132 status: v.status,
133 created_at: v.created_at,
134 tags: v.tags,
135 },
136 archive_rules: v
137 .archive_rules
138 .into_iter()
139 .map(|(k, v)| (k, ArchiveRule::from(v)))
140 .collect(),
141 }
142 }
143}
144
145impl From<ArchiveRuleView> for ArchiveRule {
146 fn from(v: ArchiveRuleView) -> Self {
147 ArchiveRule {
148 rule_name: v.rule_name,
149 filter: v
150 .filter
151 .into_iter()
152 .map(|(k, v)| (k, CriterionValue::from(v)))
153 .collect(),
154 created_at: v.created_at,
155 updated_at: v.updated_at,
156 }
157 }
158}
159
160impl From<CriterionValueView> for CriterionValue {
161 fn from(v: CriterionValueView) -> Self {
162 CriterionValue {
163 eq: v.eq,
164 neq: v.neq,
165 contains: v.contains,
166 exists: v.exists,
167 }
168 }
169}
170
171impl StatefulService for AccessAnalyzerService {
174 type StateView = AccessAnalyzerStateView;
175
176 async fn snapshot(&self, account_id: &str, region: &str) -> Self::StateView {
177 let state = self.state.get(account_id, region);
178 let guard = state.read().await;
179 AccessAnalyzerStateView::from(&*guard)
180 }
181
182 async fn restore(
183 &self,
184 account_id: &str,
185 region: &str,
186 view: Self::StateView,
187 ) -> Result<(), StateViewError> {
188 let state = self.state.get(account_id, region);
189 {
190 let mut guard = state.write().await;
191 *guard = AccessAnalyzerState::from(view);
192 }
193 self.notify_state_changed(account_id, region).await;
194 Ok(())
195 }
196
197 async fn merge(
198 &self,
199 account_id: &str,
200 region: &str,
201 view: Self::StateView,
202 ) -> Result<(), StateViewError> {
203 let state = self.state.get(account_id, region);
204 {
205 let mut guard = state.write().await;
206 for (k, v) in view.analyzers {
207 guard.analyzers.insert(k, AnalyzerState::from(v));
208 }
209 }
210 self.notify_state_changed(account_id, region).await;
211 Ok(())
212 }
213
214 fn notifier(&self) -> &StateChangeNotifier<Self::StateView> {
215 &self.notifier
216 }
217}