scouter_types/contracts/
types.rs

1use std::fmt::Display;
2
3use crate::error::ContractError;
4use crate::CustomInterval;
5use crate::{DriftType, TimeInterval};
6use chrono::{DateTime, Utc};
7use pyo3::prelude::*;
8use serde::Deserialize;
9use serde::Serialize;
10use tracing::error;
11
12#[pyclass]
13#[derive(Serialize, Deserialize, Debug, Clone)]
14pub struct GetProfileRequest {
15    pub name: String,
16    pub space: String,
17    pub version: String,
18    pub drift_type: DriftType,
19}
20
21#[pymethods]
22impl GetProfileRequest {
23    #[new]
24    #[pyo3(signature = (name, space, version, drift_type))]
25    pub fn new(name: String, space: String, version: String, drift_type: DriftType) -> Self {
26        GetProfileRequest {
27            name,
28            space,
29            version,
30            drift_type,
31        }
32    }
33}
34
35#[pyclass]
36#[derive(Serialize, Deserialize, Debug, Clone, Default)]
37pub struct DriftRequest {
38    pub space: String,
39    pub name: String,
40    pub version: String,
41    pub time_interval: TimeInterval,
42    pub max_data_points: i32,
43    pub drift_type: DriftType,
44    pub begin_custom_datetime: Option<DateTime<Utc>>,
45    pub end_custom_datetime: Option<DateTime<Utc>>,
46}
47
48#[pymethods]
49impl DriftRequest {
50    #[new]
51    #[pyo3(signature = (name, space, version, time_interval, max_data_points, drift_type, begin_datetime=None, end_datetime=None))]
52    #[allow(clippy::too_many_arguments)]
53    pub fn new(
54        name: String,
55        space: String,
56        version: String,
57        time_interval: TimeInterval,
58        max_data_points: i32,
59        drift_type: DriftType,
60        begin_datetime: Option<DateTime<Utc>>,
61        end_datetime: Option<DateTime<Utc>>,
62    ) -> Result<Self, ContractError> {
63        // validate time interval
64        let custom_interval = match (begin_datetime, end_datetime) {
65            (Some(begin), Some(end)) => Some(CustomInterval::new(begin, end)?),
66            _ => None,
67        };
68
69        Ok(DriftRequest {
70            name,
71            space,
72            version,
73            time_interval,
74            max_data_points,
75            drift_type,
76            begin_custom_datetime: custom_interval.as_ref().map(|interval| interval.start),
77            end_custom_datetime: custom_interval.as_ref().map(|interval| interval.end),
78        })
79    }
80}
81
82impl DriftRequest {
83    pub fn has_custom_interval(&self) -> bool {
84        self.begin_custom_datetime.is_some() && self.end_custom_datetime.is_some()
85    }
86
87    pub fn to_custom_interval(&self) -> Option<CustomInterval> {
88        if self.has_custom_interval() {
89            Some(
90                CustomInterval::new(
91                    self.begin_custom_datetime.unwrap(),
92                    self.end_custom_datetime.unwrap(),
93                )
94                .unwrap(),
95            )
96        } else {
97            None
98        }
99    }
100}
101
102#[pyclass]
103#[derive(Serialize, Deserialize, Debug, Clone)]
104pub struct ProfileRequest {
105    pub space: String,
106    pub drift_type: DriftType,
107    pub profile: String,
108}
109
110#[pyclass]
111#[derive(Serialize, Deserialize, Debug, Clone)]
112pub struct ProfileStatusRequest {
113    pub name: String,
114    pub space: String,
115    pub version: String,
116    pub active: bool,
117    pub drift_type: Option<DriftType>,
118    pub deactivate_others: bool,
119}
120
121#[pymethods]
122impl ProfileStatusRequest {
123    #[new]
124    #[pyo3(signature = (name, space, version, drift_type=None, active=false, deactivate_others=false))]
125    pub fn new(
126        name: String,
127        space: String,
128        version: String,
129        drift_type: Option<DriftType>,
130        active: bool,
131        deactivate_others: bool,
132    ) -> Self {
133        ProfileStatusRequest {
134            name,
135            space,
136            version,
137            active,
138            drift_type,
139            deactivate_others,
140        }
141    }
142}
143
144#[pyclass]
145#[derive(Serialize, Deserialize, Debug, Clone)]
146pub struct DriftAlertRequest {
147    pub name: String,
148    pub space: String,
149    pub version: String,
150    pub limit_datetime: Option<DateTime<Utc>>,
151    pub active: Option<bool>,
152    pub limit: Option<i32>,
153}
154
155#[pymethods]
156impl DriftAlertRequest {
157    #[new]
158    #[pyo3(signature = (name, space, version, active=false, limit_datetime=None, limit=None))]
159    pub fn new(
160        name: String,
161        space: String,
162        version: String,
163        active: bool,
164        limit_datetime: Option<DateTime<Utc>>,
165        limit: Option<i32>,
166    ) -> Self {
167        DriftAlertRequest {
168            name,
169            space,
170            version,
171            limit_datetime,
172            active: Some(active),
173            limit,
174        }
175    }
176}
177
178#[derive(Serialize, Deserialize, Debug, Clone)]
179pub struct ServiceInfo {
180    pub space: String,
181    pub name: String,
182    pub version: String,
183}
184
185#[derive(Serialize, Deserialize, Debug, Clone)]
186pub struct DriftTaskInfo {
187    pub space: String,
188    pub name: String,
189    pub version: String,
190    pub uid: String,
191    pub drift_type: DriftType,
192}
193
194#[derive(Serialize, Deserialize, Debug, Clone)]
195pub struct ObservabilityMetricRequest {
196    pub name: String,
197    pub space: String,
198    pub version: String,
199    pub time_interval: String,
200    pub max_data_points: i32,
201}
202
203#[derive(Serialize, Deserialize, Debug, Clone)]
204pub struct UpdateAlertStatus {
205    pub id: i32,
206    pub active: bool,
207    pub space: String,
208}
209
210/// Common struct for returning errors from scouter server (axum response)
211#[derive(Serialize, Deserialize, Debug, Clone)]
212pub struct ScouterServerError {
213    pub error: String,
214}
215
216impl ScouterServerError {
217    pub fn permission_denied() -> Self {
218        ScouterServerError {
219            error: "Permission denied".to_string(),
220        }
221    }
222
223    pub fn need_admin_permission() -> Self {
224        error!("User does not have admin permissions");
225        ScouterServerError {
226            error: "Need admin permission".to_string(),
227        }
228    }
229
230    pub fn user_already_exists() -> Self {
231        ScouterServerError {
232            error: "User already exists".to_string(),
233        }
234    }
235
236    pub fn create_user_error<T: Display>(e: T) -> Self {
237        error!("Failed to create user: {}", e);
238        ScouterServerError {
239            error: "Failed to create user".to_string(),
240        }
241    }
242
243    pub fn user_not_found() -> Self {
244        ScouterServerError {
245            error: "User not found".to_string(),
246        }
247    }
248
249    pub fn get_user_error<T: Display>(e: T) -> Self {
250        error!("Failed to get user: {}", e);
251        ScouterServerError {
252            error: "Failed to get user".to_string(),
253        }
254    }
255
256    pub fn list_users_error<T: Display>(e: T) -> Self {
257        error!("Failed to list users: {}", e);
258        ScouterServerError {
259            error: "Failed to list users".to_string(),
260        }
261    }
262
263    pub fn update_user_error<T: Display>(e: T) -> Self {
264        error!("Failed to update user: {}", e);
265        ScouterServerError {
266            error: "Failed to update user".to_string(),
267        }
268    }
269    pub fn delete_user_error<T: Display>(e: T) -> Self {
270        error!("Failed to delete user: {}", e);
271        ScouterServerError {
272            error: "Failed to delete user".to_string(),
273        }
274    }
275
276    pub fn check_last_admin_error<T: Display>(e: T) -> Self {
277        error!("Failed to check admin status: {}", e);
278        ScouterServerError {
279            error: "Failed to check admin status".to_string(),
280        }
281    }
282
283    pub fn cannot_delete_last_admin() -> Self {
284        error!("Cannot delete the last admin user");
285        ScouterServerError {
286            error: "Cannot delete the last admin user".to_string(),
287        }
288    }
289    pub fn username_header_not_found() -> Self {
290        error!("Username header not found");
291        ScouterServerError {
292            error: "Username header not found".to_string(),
293        }
294    }
295
296    pub fn invalid_username_format() -> Self {
297        error!("Invalid username format");
298        ScouterServerError {
299            error: "Invalid username format".to_string(),
300        }
301    }
302
303    pub fn password_header_not_found() -> Self {
304        error!("Password header not found");
305        ScouterServerError {
306            error: "Password header not found".to_string(),
307        }
308    }
309    pub fn invalid_password_format() -> Self {
310        error!("Invalid password format");
311        ScouterServerError {
312            error: "Invalid password format".to_string(),
313        }
314    }
315
316    pub fn user_validation_error() -> Self {
317        error!("User validation failed");
318        ScouterServerError {
319            error: "User validation failed".to_string(),
320        }
321    }
322
323    pub fn failed_token_validation() -> Self {
324        error!("Failed to validate token");
325        ScouterServerError {
326            error: "Failed to validate token".to_string(),
327        }
328    }
329
330    pub fn bearer_token_not_found() -> Self {
331        error!("Bearer token not found");
332        ScouterServerError {
333            error: "Bearer token not found".to_string(),
334        }
335    }
336
337    pub fn refresh_token_error<T: Display>(e: T) -> Self {
338        error!("Failed to refresh token: {}", e);
339        ScouterServerError {
340            error: "Failed to refresh token".to_string(),
341        }
342    }
343
344    pub fn unauthorized<T: Display>(e: T) -> Self {
345        error!("Unauthorized: {}", e);
346        ScouterServerError {
347            error: "Unauthorized".to_string(),
348        }
349    }
350
351    pub fn jwt_decode_error(e: String) -> Self {
352        error!("Failed to decode JWT token: {}", e);
353        ScouterServerError {
354            error: "Failed to decode JWT token".to_string(),
355        }
356    }
357
358    pub fn no_refresh_token() -> Self {
359        error!("No refresh token provided");
360        ScouterServerError {
361            error: "No refresh token provided".to_string(),
362        }
363    }
364
365    pub fn new(error: String) -> Self {
366        ScouterServerError { error }
367    }
368
369    pub fn query_records_error<T: Display>(e: T) -> Self {
370        let msg = format!("Failed to query records: {e}");
371        ScouterServerError { error: msg }
372    }
373
374    pub fn query_alerts_error<T: Display>(e: T) -> Self {
375        let msg = format!("Failed to query alerts: {e}");
376        ScouterServerError { error: msg }
377    }
378
379    pub fn query_profile_error<T: Display>(e: T) -> Self {
380        let msg = format!("Failed to query profile: {e}");
381        ScouterServerError { error: msg }
382    }
383}
384
385#[derive(Serialize, Deserialize, Debug, Clone)]
386pub struct ScouterResponse {
387    pub status: String,
388    pub message: String,
389}
390
391impl ScouterResponse {
392    pub fn new(status: String, message: String) -> Self {
393        ScouterResponse { status, message }
394    }
395}
396
397#[derive(Serialize, Deserialize, Debug, Clone)]
398pub struct UpdateAlertResponse {
399    pub updated: bool,
400}