1pub mod cfs_configuration_request;
2
3use std::{collections::HashMap, fmt};
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Serialize, Deserialize, Clone)]
8pub struct CfsSessionGetResponseList {
9 pub sessions: Vec<CfsSessionGetResponse>,
10 pub next: Option<Next>,
11}
12
13#[derive(Debug, Serialize, Deserialize, Clone)] pub struct Next {
15 pub limit: Option<u8>,
16 pub after_id: Option<String>,
17 pub in_use: Option<bool>,
18}
19
20#[derive(Debug, Serialize, Deserialize, Clone)]
21pub struct Configuration {
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub name: Option<String>,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub limit: Option<String>,
26}
27
28#[derive(Debug, Serialize, Deserialize, Clone)]
29pub struct Ansible {
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub config: Option<String>,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub limit: Option<String>,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub verbosity: Option<u64>,
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub passthrough: Option<String>,
38}
39
40#[derive(Debug, Serialize, Deserialize, Clone)]
41pub struct Group {
42 pub name: String,
43 pub members: Vec<String>,
44}
45
46#[derive(Debug, Serialize, Deserialize, Clone)]
47pub struct ImageMap {
48 pub source_id: String,
49 pub result_name: String,
50}
51
52#[derive(Debug, Serialize, Deserialize, Clone, Default)]
53pub struct Target {
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub definition: Option<String>,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub groups: Option<Vec<Group>>,
58 pub image_map: Option<Vec<ImageMap>>,
59}
60
61#[derive(Debug, Serialize, Deserialize, Clone)]
62pub struct Artifact {
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub image_id: Option<String>,
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub result_id: Option<String>,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub r#type: Option<String>,
69}
70
71#[derive(Debug, Serialize, Deserialize, Clone)]
72pub struct Session {
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub job: Option<String>,
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub ims_job: Option<String>,
77 #[serde(skip_serializing_if = "Option::is_none")]
78 pub completion_time: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
80 pub start_time: Option<String>,
81 #[serde(skip_serializing_if = "Option::is_none")]
82 pub status: Option<String>,
83 #[serde(skip_serializing_if = "Option::is_none")]
84 pub succeeded: Option<String>,
85}
86
87#[derive(Debug, Serialize, Deserialize, Clone)]
88pub struct Status {
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub artifacts: Option<Vec<Artifact>>,
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub session: Option<Session>,
93}
94
95#[derive(Debug, Serialize, Deserialize, Clone)]
96pub struct CfsSessionGetResponse {
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub name: Option<String>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub configuration: Option<Configuration>,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub ansible: Option<Ansible>,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 pub target: Option<Target>,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub status: Option<Status>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub tags: Option<HashMap<String, String>>,
109 pub debug_on_failure: bool,
110 pub logs: Option<String>,
111}
112
113impl CfsSessionGetResponse {
114 pub fn get_start_time(&self) -> Option<String> {
116 self.status.as_ref().and_then(|status| {
117 status
118 .session
119 .as_ref()
120 .and_then(|session| session.start_time.clone())
121 })
122 }
123
124 pub fn get_result_id_vec(&self) -> Vec<String> {
126 if let Some(status) = &self.status {
127 status
128 .artifacts
129 .as_ref()
130 .unwrap_or(&Vec::new())
131 .into_iter()
132 .filter(|artifact| artifact.result_id.is_some())
133 .map(|artifact| artifact.result_id.clone().unwrap())
134 .collect()
135 } else {
136 Vec::new()
137 }
138 }
139
140 pub fn get_first_result_id(&self) -> Option<String> {
142 CfsSessionGetResponse::get_result_id_vec(&self)
143 .first()
144 .cloned()
145 }
146
147 pub fn get_targets(&self) -> Option<Vec<String>> {
160 Some(
161 self.get_target_hsm()
162 .unwrap_or(self.get_target_xname().unwrap()),
163 )
164 }
165
166 pub fn get_target_hsm(&self) -> Option<Vec<String>> {
168 self.target.as_ref().and_then(|target| {
169 target
170 .groups
171 .as_ref()
172 .map(|group_vec| group_vec.iter().map(|group| group.name.clone()).collect())
173 })
174 }
175
176 pub fn get_target_xname(&self) -> Option<Vec<String>> {
178 self.ansible.as_ref().and_then(|ansible| {
179 ansible.limit.as_ref().map(|limit| {
180 limit
181 .split(',')
182 .map(|xname| xname.trim().to_string())
183 .collect()
184 })
185 })
186 }
187
188 pub fn is_target_def_image(&self) -> bool {
191 self.get_target_def()
192 .is_some_and(|target_def| target_def == "image")
193 }
194
195 pub fn get_target_def(&self) -> Option<String> {
199 self.target
200 .as_ref()
201 .and_then(|target| target.definition.clone())
202 }
203
204 pub fn get_configuration_name(&self) -> Option<String> {
205 self.configuration
206 .as_ref()
207 .and_then(|configuration| configuration.name.clone())
208 }
209
210 pub fn is_success(&self) -> bool {
212 self.status
213 .as_ref()
214 .unwrap()
215 .session
216 .as_ref()
217 .unwrap()
218 .succeeded
219 .as_ref()
220 .unwrap()
221 == "true"
222 }
223}
224
225#[derive(Debug, Serialize, Deserialize, Clone, Default)]
226pub struct CfsSessionPostRequest {
227 pub name: String,
228 pub configuration_name: String,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub configuration_limit: Option<String>,
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub ansible_limit: Option<String>,
233 #[serde(skip_serializing_if = "Option::is_none")]
234 pub ansible_config: Option<String>,
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub ansible_verbosity: Option<u8>,
237 #[serde(skip_serializing_if = "Option::is_none")]
238 pub ansible_passthrough: Option<String>,
239 #[serde(default)]
240 pub target: Target,
241 #[serde(skip_serializing_if = "Option::is_none")]
242 pub tags: Option<HashMap<String, String>>,
243 pub debug_on_failure: bool,
244}
245
246#[derive(Debug, Serialize, Deserialize, Clone, Default)]
247pub struct Layer {
248 pub name: String,
249 pub clone_url: String,
251 pub source: Option<String>,
252 #[serde(skip_serializing_if = "Option::is_none")] pub commit: Option<String>,
254 pub playbook: String,
255 #[serde(skip_serializing_if = "Option::is_none")] pub branch: Option<String>,
257}
258
259#[derive(Debug, Serialize, Deserialize, Clone, Default)]
260pub struct AdditionalInventory {
261 #[serde(rename = "cloneUrl")]
262 pub clone_url: String,
263 #[serde(skip_serializing_if = "Option::is_none")] pub commit: Option<String>,
265 pub name: String,
266 #[serde(skip_serializing_if = "Option::is_none")] pub branch: Option<String>,
268}
269
270#[derive(Debug, Serialize, Deserialize, Clone)]
271pub struct CfsConfigurationResponse {
272 pub name: String,
273 pub last_updated: String,
275 pub layers: Vec<Layer>,
276 #[serde(skip_serializing_if = "Option::is_none")] pub additional_inventory: Option<AdditionalInventory>,
278}
279
280#[derive(Debug, Serialize, Deserialize, Clone)]
281pub struct CfsConfigurationVecResponse {
282 pub configurations: Vec<CfsConfigurationResponse>,
283 pub next: Option<Next>,
284}
285
286pub struct LayerDetails {
287 pub name: String,
288 pub repo_name: String,
289 pub commit_id: String,
290 pub author: String,
291 pub commit_date: String,
292 pub branch: String,
293 pub tag: String,
294 pub playbook: String, }
296
297impl LayerDetails {
298 pub fn new(
299 name: &str,
300 repo_name: &str,
301 commit_id: &str,
302 author: &str,
303 commit_date: &str,
304 branch: &str,
305 tag: &str,
306 playbook: &str,
307 ) -> Self {
309 Self {
310 name: String::from(name),
311 repo_name: String::from(repo_name),
312 commit_id: String::from(commit_id),
313 author: String::from(author),
314 commit_date: String::from(commit_date),
315 branch: branch.to_string(),
316 tag: tag.to_string(),
317 playbook: playbook.to_string(),
318 }
320 }
321}
322
323impl fmt::Display for LayerDetails {
324 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
325 write!(
326 f,
327 "\n - name: {}\n - repo name: {}\n - commit id: {}\n - commit date: {}\n - author: {}\n - branch: {}\n - tag: {}\n - playbook: {}",
328 self.name, self.repo_name, self.commit_id, self.commit_date, self.author, self.branch, self.tag, self.playbook
329 )
330 }
331}
332
333pub struct ConfigurationDetails {
336 pub name: String,
337 pub last_updated: String,
338 pub config_layers: Vec<LayerDetails>,
339}
340
341impl ConfigurationDetails {
342 pub fn new(name: &str, last_updated: &str, config_layers: Vec<LayerDetails>) -> Self {
343 Self {
344 name: String::from(name),
345 last_updated: String::from(last_updated),
346 config_layers,
347 }
348 }
349}
350
351impl fmt::Display for ConfigurationDetails {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 write!(
354 f,
355 "\nConfig Details:\n - name: {}\n - last updated: {}\nLayers:",
356 self.name, self.last_updated
357 )?;
358
359 for (i, config_layer) in self.config_layers.iter().enumerate() {
360 write!(f, "\n Layer {}:{}", i, config_layer)?;
361 }
362
363 Ok(())
364 }
365}