Skip to main content

cfgd_core/state/
drift.rs

1use rusqlite::params;
2
3use super::StateStore;
4use super::types::DriftEvent;
5use crate::errors::Result;
6
7impl StateStore {
8    /// Record a drift event.
9    pub fn record_drift(
10        &self,
11        resource_type: &str,
12        resource_id: &str,
13        expected: Option<&str>,
14        actual: Option<&str>,
15        source: &str,
16    ) -> Result<i64> {
17        let timestamp = crate::utc_now_iso8601();
18        self.conn
19            .execute(
20                "INSERT INTO drift_events (timestamp, resource_type, resource_id, expected, actual, source) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
21                params![timestamp, resource_type, resource_id, expected, actual, source],
22            )
23            ?;
24        Ok(self.conn.last_insert_rowid())
25    }
26
27    /// Resolve drift events by linking them to an apply.
28    pub fn resolve_drift(
29        &self,
30        apply_id: i64,
31        resource_type: &str,
32        resource_id: &str,
33    ) -> Result<()> {
34        self.conn
35            .execute(
36                "UPDATE drift_events SET resolved_by = ?1 WHERE resource_type = ?2 AND resource_id = ?3 AND resolved_by IS NULL",
37                params![apply_id, resource_type, resource_id],
38            )
39            ?;
40        Ok(())
41    }
42
43    /// Get unresolved drift events.
44    pub fn unresolved_drift(&self) -> Result<Vec<DriftEvent>> {
45        let mut stmt = self
46            .conn
47            .prepare(
48                "SELECT id, timestamp, resource_type, resource_id, expected, actual, resolved_by, source FROM drift_events WHERE resolved_by IS NULL ORDER BY timestamp DESC",
49            )
50            ?;
51
52        let events = stmt
53            .query_map([], |row| {
54                Ok(DriftEvent {
55                    id: row.get(0)?,
56                    timestamp: row.get(1)?,
57                    resource_type: row.get(2)?,
58                    resource_id: row.get(3)?,
59                    expected: row.get(4)?,
60                    actual: row.get(5)?,
61                    resolved_by: row.get(6)?,
62                    source: row.get(7)?,
63                })
64            })?
65            .collect::<std::result::Result<Vec<_>, _>>()?;
66
67        Ok(events)
68    }
69}