backend_dispatcher/types/
cfs.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Serialize, Deserialize, Clone)]
6pub struct CfsSessionGetResponseList {
7    pub sessions: Vec<CfsSessionGetResponse>,
8    pub next: Option<Next>,
9}
10
11#[derive(Debug, Serialize, Deserialize, Clone)] // TODO: investigate why serde can Deserialize dynamically syzed structs `Vec<Layer>`
12pub struct Next {
13    pub limit: Option<u8>,
14    pub after_id: Option<String>,
15    pub in_use: Option<bool>,
16}
17
18#[derive(Debug, Serialize, Deserialize, Clone)]
19pub struct Configuration {
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub name: Option<String>,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub limit: Option<String>,
24}
25
26#[derive(Debug, Serialize, Deserialize, Clone)]
27pub struct Ansible {
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub config: Option<String>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub limit: Option<String>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub verbosity: Option<u64>,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub passthrough: Option<String>,
36}
37
38#[derive(Debug, Serialize, Deserialize, Clone)]
39pub struct Group {
40    pub name: String,
41    pub members: Vec<String>,
42}
43
44#[derive(Debug, Serialize, Deserialize, Clone)]
45pub struct ImageMap {
46    pub source_id: String,
47    pub result_name: String,
48}
49
50#[derive(Debug, Serialize, Deserialize, Clone, Default)]
51pub struct Target {
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub definition: Option<String>,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub groups: Option<Vec<Group>>,
56    pub image_map: Option<Vec<ImageMap>>,
57}
58
59#[derive(Debug, Serialize, Deserialize, Clone)]
60pub struct Artifact {
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub image_id: Option<String>,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub result_id: Option<String>,
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub r#type: Option<String>,
67}
68
69#[derive(Debug, Serialize, Deserialize, Clone)]
70pub struct Session {
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub job: Option<String>,
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub ims_job: Option<String>,
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub completion_time: Option<String>,
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub start_time: Option<String>,
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub status: Option<String>,
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub succeeded: Option<String>,
83}
84
85#[derive(Debug, Serialize, Deserialize, Clone)]
86pub struct Status {
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub artifacts: Option<Vec<Artifact>>,
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub session: Option<Session>,
91}
92
93#[derive(Debug, Serialize, Deserialize, Clone)]
94pub struct CfsSessionGetResponse {
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub name: Option<String>,
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub configuration: Option<Configuration>,
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub ansible: Option<Ansible>,
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub target: Option<Target>,
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub status: Option<Status>,
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub tags: Option<HashMap<String, String>>,
107    pub debug_on_failure: bool,
108    pub logs: Option<String>,
109}
110
111impl CfsSessionGetResponse {
112    /// Get start time
113    pub fn get_start_time(&self) -> Option<String> {
114        self.status.as_ref().and_then(|status| {
115            status
116                .session
117                .as_ref()
118                .and_then(|session| session.start_time.clone())
119        })
120    }
121
122    /// Returns list of result_ids
123    pub fn get_result_id_vec(&self) -> Vec<String> {
124        if let Some(status) = &self.status {
125            status
126                .artifacts
127                .as_ref()
128                .unwrap_or(&Vec::new())
129                .into_iter()
130                .filter(|artifact| artifact.result_id.is_some())
131                .map(|artifact| artifact.result_id.clone().unwrap())
132                .collect()
133        } else {
134            Vec::new()
135        }
136    }
137
138    /// Returns list of result_ids
139    pub fn get_first_result_id(&self) -> Option<String> {
140        CfsSessionGetResponse::get_result_id_vec(&self)
141            .first()
142            .cloned()
143    }
144
145    /* /// Returns list of result_ids
146    pub fn get_result_id(&self) -> Option<String> {
147        self.status.as_ref().and_then(|status| {
148            status.artifacts.as_ref().and_then(|artifacts| {
149                artifacts
150                    .first()
151                    .and_then(|artifact| artifact.result_id.clone())
152            })
153        })
154    } */
155
156    /// Returns list of targets (either groups or xnames)
157    pub fn get_targets(&self) -> Option<Vec<String>> {
158        Some(
159            self.get_target_hsm()
160                .unwrap_or(self.get_target_xname().unwrap()),
161        )
162    }
163
164    /// Returns list of HSM groups targeted
165    pub fn get_target_hsm(&self) -> Option<Vec<String>> {
166        self.target.as_ref().and_then(|target| {
167            target
168                .groups
169                .as_ref()
170                .map(|group_vec| group_vec.iter().map(|group| group.name.clone()).collect())
171        })
172    }
173
174    /// Returns list of xnames targeted
175    pub fn get_target_xname(&self) -> Option<Vec<String>> {
176        self.ansible.as_ref().and_then(|ansible| {
177            ansible.limit.as_ref().map(|limit| {
178                limit
179                    .split(',')
180                    .map(|xname| xname.trim().to_string())
181                    .collect()
182            })
183        })
184    }
185
186    /// Returns 'true' if the CFS session target definition is 'image'. Otherwise (target
187    /// definiton dynamic) will return 'false'
188    pub fn is_target_def_image(&self) -> bool {
189        self.get_target_def()
190            .is_some_and(|target_def| target_def == "image")
191    }
192
193    /// Returns target definition of the CFS session:
194    /// image --> CFS session to build an image
195    /// dynamic --> CFS session to configure a node
196    pub fn get_target_def(&self) -> Option<String> {
197        self.target
198            .as_ref()
199            .and_then(|target| target.definition.clone())
200    }
201
202    pub fn get_configuration_name(&self) -> Option<String> {
203        self.configuration
204            .as_ref()
205            .and_then(|configuration| configuration.name.clone())
206    }
207
208    /// Returns 'true' if CFS session succeeded
209    pub fn is_success(&self) -> bool {
210        self.status
211            .as_ref()
212            .unwrap()
213            .session
214            .as_ref()
215            .unwrap()
216            .succeeded
217            .as_ref()
218            .unwrap()
219            == "true"
220    }
221}
222
223#[derive(Debug, Serialize, Deserialize, Clone, Default)]
224pub struct CfsSessionPostRequest {
225    pub name: String,
226    pub configuration_name: String,
227    #[serde(skip_serializing_if = "Option::is_none")]
228    pub configuration_limit: Option<String>,
229    #[serde(skip_serializing_if = "Option::is_none")]
230    pub ansible_limit: Option<String>,
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub ansible_config: Option<String>,
233    #[serde(skip_serializing_if = "Option::is_none")]
234    pub ansible_verbosity: Option<u8>,
235    #[serde(skip_serializing_if = "Option::is_none")]
236    pub ansible_passthrough: Option<String>,
237    #[serde(default)]
238    pub target: Target,
239    #[serde(skip_serializing_if = "Option::is_none")]
240    pub tags: Option<HashMap<String, String>>,
241    pub debug_on_failure: bool,
242}