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
246impl CfsSessionPostRequest {
247 pub fn new(
248 name: String,
249 configuration_name: String,
250 configuration_limit: Option<String>,
251 ansible_limit: Option<String>,
252 ansible_config: Option<String>,
253 ansible_verbosity: Option<u8>,
254 ansible_passthrough: Option<String>,
255 is_target_definition_image: bool,
256 groups_name: Option<Vec<String>>,
257 base_image_id: Option<String>,
258 tags: Option<HashMap<String, String>>,
259 debug_on_failure: bool,
260 result_image_name: Option<String>,
261 ) -> Self {
262 let mut cfs_session = Self {
266 name,
267 configuration_name,
268 configuration_limit,
269 ansible_config,
270 ansible_limit,
271 ansible_verbosity,
272 ansible_passthrough,
273 ..Default::default()
274 };
275
276 if is_target_definition_image {
277 let target_groups: Vec<Group> = groups_name
278 .unwrap()
279 .into_iter()
280 .map(|group_name| Group {
281 name: group_name,
282 members: vec![base_image_id.as_ref().unwrap().to_string()],
283 })
284 .collect();
285
286 cfs_session.target.definition = Some("image".to_string());
287 cfs_session.target.groups = Some(target_groups);
288 cfs_session.target.image_map = Some(vec![ImageMap {
289 source_id: base_image_id.expect("ERROR - can't create a CFS session to build an image without base image id"),
290 result_name: result_image_name.expect("ERROR - can't create a CFS sessions to build an image without result image name"),
291 }]);
292 } else {
293 cfs_session.target.definition = Some("dynamic".to_string());
294 cfs_session.target.groups = None;
295 cfs_session.target.image_map = Some(Vec::new());
296 }
297
298 cfs_session.tags = tags;
299 cfs_session.debug_on_failure = debug_on_failure;
300
301 cfs_session
302 }
303}
304
305#[derive(Debug, Serialize, Deserialize, Clone, Default)]
306pub struct Layer {
307 pub name: String,
308 pub clone_url: String,
310 pub source: Option<String>,
311 #[serde(skip_serializing_if = "Option::is_none")] pub commit: Option<String>,
313 pub playbook: String,
314 #[serde(skip_serializing_if = "Option::is_none")] pub branch: Option<String>,
316}
317
318#[derive(Debug, Serialize, Deserialize, Clone, Default)]
319pub struct AdditionalInventory {
320 #[serde(rename = "cloneUrl")]
321 pub clone_url: String,
322 #[serde(skip_serializing_if = "Option::is_none")] pub commit: Option<String>,
324 pub name: String,
325 #[serde(skip_serializing_if = "Option::is_none")] pub branch: Option<String>,
327}
328
329#[derive(Debug, Serialize, Deserialize, Clone)]
330pub struct CfsConfigurationResponse {
331 pub name: String,
332 pub last_updated: String,
334 pub layers: Vec<Layer>,
335 #[serde(skip_serializing_if = "Option::is_none")] pub additional_inventory: Option<AdditionalInventory>,
337}
338
339#[derive(Debug, Serialize, Deserialize, Clone)]
340pub struct CfsConfigurationVecResponse {
341 pub configurations: Vec<CfsConfigurationResponse>,
342 pub next: Option<Next>,
343}
344
345pub struct LayerDetails {
346 pub name: String,
347 pub repo_name: String,
348 pub commit_id: String,
349 pub author: String,
350 pub commit_date: String,
351 pub branch: String,
352 pub tag: String,
353 pub playbook: String, }
355
356impl LayerDetails {
357 pub fn new(
358 name: &str,
359 repo_name: &str,
360 commit_id: &str,
361 author: &str,
362 commit_date: &str,
363 branch: &str,
364 tag: &str,
365 playbook: &str,
366 ) -> Self {
368 Self {
369 name: String::from(name),
370 repo_name: String::from(repo_name),
371 commit_id: String::from(commit_id),
372 author: String::from(author),
373 commit_date: String::from(commit_date),
374 branch: branch.to_string(),
375 tag: tag.to_string(),
376 playbook: playbook.to_string(),
377 }
379 }
380}
381
382impl fmt::Display for LayerDetails {
383 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384 write!(
385 f,
386 "\n - name: {}\n - repo name: {}\n - commit id: {}\n - commit date: {}\n - author: {}\n - branch: {}\n - tag: {}\n - playbook: {}",
387 self.name, self.repo_name, self.commit_id, self.commit_date, self.author, self.branch, self.tag, self.playbook
388 )
389 }
390}
391
392pub struct ConfigurationDetails {
395 pub name: String,
396 pub last_updated: String,
397 pub config_layers: Vec<LayerDetails>,
398}
399
400impl ConfigurationDetails {
401 pub fn new(name: &str, last_updated: &str, config_layers: Vec<LayerDetails>) -> Self {
402 Self {
403 name: String::from(name),
404 last_updated: String::from(last_updated),
405 config_layers,
406 }
407 }
408}
409
410impl fmt::Display for ConfigurationDetails {
411 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
412 write!(
413 f,
414 "\nConfig Details:\n - name: {}\n - last updated: {}\nLayers:",
415 self.name, self.last_updated
416 )?;
417
418 for (i, config_layer) in self.config_layers.iter().enumerate() {
419 write!(f, "\n Layer {}:{}", i, config_layer)?;
420 }
421
422 Ok(())
423 }
424}