1use std::collections::BTreeMap;
2use std::sync::Arc;
3
4use parking_lot::RwLock;
5
6pub type SharedLogsState = Arc<RwLock<fakecloud_core::multi_account::MultiAccountState<LogsState>>>;
7
8impl fakecloud_core::multi_account::AccountState for LogsState {
9 fn new_for_account(account_id: &str, region: &str, _endpoint: &str) -> Self {
10 Self::new(account_id, region)
11 }
12}
13
14mod account_policy_map_serde {
18 use super::AccountPolicy;
19 use serde::{Deserialize, Deserializer, Serialize, Serializer};
20 use std::collections::BTreeMap;
21
22 pub fn serialize<S: Serializer>(
23 map: &BTreeMap<(String, String), AccountPolicy>,
24 s: S,
25 ) -> Result<S::Ok, S::Error> {
26 let entries: Vec<(&String, &String, &AccountPolicy)> = map
27 .iter()
28 .map(|((name, kind), p)| (name, kind, p))
29 .collect();
30 entries.serialize(s)
31 }
32
33 pub fn deserialize<'de, D: Deserializer<'de>>(
34 d: D,
35 ) -> Result<BTreeMap<(String, String), AccountPolicy>, D::Error> {
36 let entries: Vec<(String, String, AccountPolicy)> = Vec::deserialize(d)?;
37 Ok(entries
38 .into_iter()
39 .map(|(name, kind, p)| ((name, kind), p))
40 .collect())
41 }
42}
43
44#[derive(Clone, serde::Serialize, serde::Deserialize)]
45pub struct LogsState {
46 pub account_id: String,
47 pub region: String,
48 pub log_groups: BTreeMap<String, LogGroup>,
49 pub metric_filters: Vec<MetricFilter>,
50 pub resource_policies: BTreeMap<String, ResourcePolicy>,
51 pub destinations: BTreeMap<String, Destination>,
52 pub queries: BTreeMap<String, QueryInfo>,
53 pub export_tasks: Vec<ExportTask>,
54 pub delivery_destinations: BTreeMap<String, DeliveryDestination>,
55 pub delivery_sources: BTreeMap<String, DeliverySource>,
56 pub deliveries: BTreeMap<String, Delivery>,
57 pub query_definitions: BTreeMap<String, QueryDefinition>,
58 #[serde(with = "account_policy_map_serde")]
60 pub account_policies: BTreeMap<(String, String), AccountPolicy>,
61 pub anomaly_detectors: BTreeMap<String, AnomalyDetector>,
63 pub import_tasks: BTreeMap<String, ImportTask>,
65 pub integrations: BTreeMap<String, Integration>,
67 pub lookup_tables: BTreeMap<String, LookupTable>,
69 pub scheduled_queries: BTreeMap<String, ScheduledQuery>,
71 pub s3_table_sources: BTreeMap<String, Vec<String>>,
73 pub bearer_token_auth: BTreeMap<String, bool>,
75 pub export_storage: BTreeMap<String, Vec<u8>>,
78 #[serde(default)]
82 pub anomalies: BTreeMap<String, LogAnomaly>,
83 #[serde(default)]
87 pub syslog_configurations: BTreeMap<String, SyslogConfiguration>,
88}
89
90#[derive(Clone, serde::Serialize, serde::Deserialize)]
91pub struct SyslogConfiguration {
92 pub log_group_arn: String,
93 pub source_type: String,
94 pub vpc_endpoint_id: Option<String>,
95 pub created_at: i64,
96}
97
98#[derive(Clone, serde::Serialize, serde::Deserialize)]
99pub struct LogAnomaly {
100 pub anomaly_id: String,
101 pub anomaly_detector_arn: String,
102 pub log_group_arn_list: Vec<String>,
103 pub pattern_id: String,
104 pub pattern_string: String,
105 pub first_seen: i64,
106 pub last_seen: i64,
107 pub priority: String,
108 pub state: String,
109 pub suppressed: bool,
110}
111
112impl LogsState {
113 pub fn new(account_id: &str, region: &str) -> Self {
114 Self {
115 account_id: account_id.to_string(),
116 region: region.to_string(),
117 log_groups: BTreeMap::new(),
118 metric_filters: Vec::new(),
119 resource_policies: BTreeMap::new(),
120 destinations: BTreeMap::new(),
121 queries: BTreeMap::new(),
122 export_tasks: Vec::new(),
123 delivery_destinations: BTreeMap::new(),
124 delivery_sources: BTreeMap::new(),
125 deliveries: BTreeMap::new(),
126 query_definitions: BTreeMap::new(),
127 account_policies: BTreeMap::new(),
128 anomaly_detectors: BTreeMap::new(),
129 import_tasks: BTreeMap::new(),
130 integrations: BTreeMap::new(),
131 lookup_tables: BTreeMap::new(),
132 scheduled_queries: BTreeMap::new(),
133 s3_table_sources: BTreeMap::new(),
134 bearer_token_auth: BTreeMap::new(),
135 export_storage: BTreeMap::new(),
136 anomalies: BTreeMap::new(),
137 syslog_configurations: BTreeMap::new(),
138 }
139 }
140
141 pub fn reset(&mut self) {
142 self.log_groups.clear();
143 self.metric_filters.clear();
144 self.resource_policies.clear();
145 self.destinations.clear();
146 self.queries.clear();
147 self.export_tasks.clear();
148 self.delivery_destinations.clear();
149 self.delivery_sources.clear();
150 self.deliveries.clear();
151 self.query_definitions.clear();
152 self.account_policies.clear();
153 self.anomaly_detectors.clear();
154 self.import_tasks.clear();
155 self.integrations.clear();
156 self.lookup_tables.clear();
157 self.scheduled_queries.clear();
158 self.s3_table_sources.clear();
159 self.bearer_token_auth.clear();
160 self.export_storage.clear();
161 self.anomalies.clear();
162 self.syslog_configurations.clear();
163 }
164}
165
166#[derive(Clone, serde::Serialize, serde::Deserialize)]
167pub struct LogGroup {
168 pub name: String,
169 pub arn: String,
170 pub creation_time: i64,
171 pub retention_in_days: Option<i32>,
172 pub kms_key_id: Option<String>,
173 pub tags: BTreeMap<String, String>,
174 pub log_streams: BTreeMap<String, LogStream>,
175 pub stored_bytes: i64,
176 pub subscription_filters: Vec<SubscriptionFilter>,
177 pub data_protection_policy: Option<DataProtectionPolicy>,
178 pub index_policies: Vec<IndexPolicy>,
179 pub transformer: Option<Transformer>,
180 pub deletion_protection: bool,
181 pub log_group_class: Option<String>,
185}
186
187#[derive(Clone, serde::Serialize, serde::Deserialize)]
188pub struct LogStream {
189 pub name: String,
190 pub arn: String,
191 pub creation_time: i64,
192 pub first_event_timestamp: Option<i64>,
193 pub last_event_timestamp: Option<i64>,
194 pub last_ingestion_time: Option<i64>,
195 pub upload_sequence_token: String,
196 pub events: Vec<LogEvent>,
197}
198
199#[derive(Clone, serde::Serialize, serde::Deserialize)]
200pub struct LogEvent {
201 pub timestamp: i64,
202 pub message: String,
203 pub ingestion_time: i64,
204}
205
206#[derive(Clone, serde::Serialize, serde::Deserialize)]
207pub struct SubscriptionFilter {
208 pub filter_name: String,
209 pub log_group_name: String,
210 pub filter_pattern: String,
211 pub destination_arn: String,
212 pub role_arn: Option<String>,
213 pub distribution: String,
214 pub creation_time: i64,
215}
216
217#[derive(Clone, serde::Serialize, serde::Deserialize)]
218pub struct MetricFilter {
219 pub filter_name: String,
220 pub filter_pattern: String,
221 pub log_group_name: String,
222 pub metric_transformations: Vec<MetricTransformation>,
223 pub creation_time: i64,
224}
225
226#[derive(Clone, serde::Serialize, serde::Deserialize)]
227pub struct MetricTransformation {
228 pub metric_name: String,
229 pub metric_namespace: String,
230 pub metric_value: String,
231 pub default_value: Option<f64>,
232 #[serde(default)]
236 pub unit: Option<String>,
237}
238
239#[derive(Clone, serde::Serialize, serde::Deserialize)]
240pub struct ResourcePolicy {
241 pub policy_name: String,
242 pub policy_document: String,
243 pub last_updated_time: i64,
244}
245
246#[derive(Clone, serde::Serialize, serde::Deserialize)]
247pub struct Destination {
248 pub destination_name: String,
249 pub target_arn: String,
250 pub role_arn: String,
251 pub arn: String,
252 pub access_policy: Option<String>,
253 pub creation_time: i64,
254 pub tags: BTreeMap<String, String>,
255}
256
257#[derive(Clone, serde::Serialize, serde::Deserialize)]
258pub struct QueryInfo {
259 pub query_id: String,
260 pub log_group_name: String,
261 #[serde(default)]
266 pub log_group_identifiers: Vec<String>,
267 pub query_string: String,
268 pub start_time: i64,
269 pub end_time: i64,
270 pub status: String,
271 pub create_time: i64,
272}
273
274#[derive(Clone, serde::Serialize, serde::Deserialize)]
275pub struct ExportTask {
276 pub task_id: String,
277 pub task_name: Option<String>,
278 pub log_group_name: String,
279 pub log_stream_name_prefix: Option<String>,
280 pub from_time: i64,
281 pub to_time: i64,
282 pub destination: String,
283 pub destination_prefix: String,
284 pub status_code: String,
285 pub status_message: String,
286 #[serde(default)]
287 pub creation_time: i64,
288 #[serde(default)]
289 pub completion_time: Option<i64>,
290}
291
292#[derive(Clone, serde::Serialize, serde::Deserialize)]
293pub struct DeliveryDestination {
294 pub name: String,
295 pub arn: String,
296 pub output_format: Option<String>,
297 pub delivery_destination_configuration: BTreeMap<String, String>,
298 #[serde(default)]
301 pub delivery_destination_type: String,
302 pub tags: BTreeMap<String, String>,
303 pub delivery_destination_policy: Option<String>,
304}
305
306#[derive(Clone, serde::Serialize, serde::Deserialize)]
307pub struct DeliverySource {
308 pub name: String,
309 pub arn: String,
310 pub resource_arns: Vec<String>,
311 pub service: String,
312 pub log_type: String,
313 pub tags: BTreeMap<String, String>,
314 #[serde(default)]
315 pub created_at: i64,
316}
317
318#[derive(Clone, serde::Serialize, serde::Deserialize)]
319pub struct Delivery {
320 pub id: String,
321 pub delivery_source_name: String,
322 pub delivery_destination_arn: String,
323 pub delivery_destination_type: String,
324 pub arn: String,
325 pub tags: BTreeMap<String, String>,
326 #[serde(default)]
327 pub field_delimiter: Option<String>,
328 #[serde(default)]
329 pub record_fields: Vec<String>,
330 #[serde(default)]
331 pub s3_delivery_configuration: Option<serde_json::Value>,
332 #[serde(default)]
333 pub created_at: i64,
334}
335
336#[derive(Clone, serde::Serialize, serde::Deserialize)]
337pub struct QueryDefinition {
338 pub query_definition_id: String,
339 pub name: String,
340 pub query_string: String,
341 pub log_group_names: Vec<String>,
342 pub last_modified: i64,
343}
344
345#[derive(Clone, serde::Serialize, serde::Deserialize)]
346pub struct AccountPolicy {
347 pub policy_name: String,
348 pub policy_type: String,
349 pub policy_document: String,
350 pub scope: Option<String>,
351 pub selection_criteria: Option<String>,
352 pub account_id: String,
353 pub last_updated_time: i64,
354}
355
356#[derive(Clone, serde::Serialize, serde::Deserialize)]
357pub struct DataProtectionPolicy {
358 pub policy_document: String,
359 pub last_updated_time: i64,
360}
361
362#[derive(Clone, serde::Serialize, serde::Deserialize)]
363pub struct IndexPolicy {
364 pub policy_name: String,
365 pub policy_document: String,
366 pub last_updated_time: i64,
367}
368
369#[derive(Clone, serde::Serialize, serde::Deserialize)]
370pub struct Transformer {
371 pub transformer_config: serde_json::Value,
372 pub creation_time: i64,
373 pub last_modified_time: i64,
374}
375
376#[derive(Clone, serde::Serialize, serde::Deserialize)]
377pub struct AnomalyDetector {
378 pub detector_name: String,
379 pub arn: String,
380 pub log_group_arn_list: Vec<String>,
381 pub evaluation_frequency: Option<String>,
382 pub filter_pattern: Option<String>,
383 pub anomaly_visibility_time: Option<i64>,
384 pub creation_time: i64,
385 pub last_modified_time: i64,
386 pub enabled: bool,
387 #[serde(default)]
388 pub tags: BTreeMap<String, String>,
389}
390
391#[derive(Clone, serde::Serialize, serde::Deserialize)]
392pub struct ImportTask {
393 pub import_id: String,
394 pub import_source_arn: String,
395 pub import_role_arn: String,
396 pub log_group_name: Option<String>,
397 pub status: String,
398 pub creation_time: i64,
399}
400
401#[derive(Clone, serde::Serialize, serde::Deserialize)]
402pub struct Integration {
403 pub integration_name: String,
404 pub integration_type: String,
405 pub resource_config: serde_json::Value,
406 pub status: String,
407 pub creation_time: i64,
408}
409
410#[derive(Clone, serde::Serialize, serde::Deserialize)]
411pub struct LookupTable {
412 pub lookup_table_name: String,
413 pub arn: String,
414 pub table_body: String,
415 pub creation_time: i64,
416 pub last_modified_time: i64,
417}
418
419#[derive(Clone, serde::Serialize, serde::Deserialize)]
420pub struct ScheduledQuery {
421 pub name: String,
422 pub arn: String,
423 pub query_string: String,
424 pub query_language: String,
425 pub schedule_expression: String,
426 pub execution_role_arn: String,
427 pub status: String,
428 pub creation_time: i64,
429 pub last_modified_time: i64,
430}
431
432#[derive(Clone, serde::Serialize, serde::Deserialize)]
435pub struct LogsSnapshot {
436 pub schema_version: u32,
437 #[serde(default)]
438 pub accounts: Option<fakecloud_core::multi_account::MultiAccountState<LogsState>>,
439 #[serde(default)]
440 pub state: Option<LogsState>,
441}
442
443pub const LOGS_SNAPSHOT_SCHEMA_VERSION: u32 = 2;
444
445#[cfg(test)]
446mod tests {
447 use super::*;
448
449 #[test]
450 fn new_initializes_empty() {
451 let state = LogsState::new("123456789012", "us-east-1");
452 assert_eq!(state.account_id, "123456789012");
453 assert_eq!(state.region, "us-east-1");
454 assert!(state.log_groups.is_empty());
455 assert!(state.queries.is_empty());
456 }
457
458 #[test]
459 fn reset_clears_state() {
460 let mut state = LogsState::new("123456789012", "us-east-1");
461 state.bearer_token_auth.insert("g".to_string(), true);
462 state.reset();
463 assert!(state.bearer_token_auth.is_empty());
464 }
465}