Skip to main content

cdk_ansible/types/
mod.rs

1pub(crate) mod trait_impl;
2use crate::{Play, Playbook};
3use std::fmt;
4
5/// Play execution definition
6///
7/// ```rust
8/// use cdk_ansible::{Play, PlayOptions, ExeSequential, ExeSingle, ExeParallel};
9///
10/// /// Helper function to create sample play
11/// fn create_play_helper(name: &str) -> Play {
12///     Play {
13///         name: name.to_string(),
14///         hosts: "localhost".into(),
15///         options: PlayOptions::default(),
16///         tasks: vec![],
17///     }
18/// }
19///
20/// // Example of creating ExePlay simply
21/// let _play_exec = ExeSequential(vec![
22///     ExeSingle(Box::new(create_play_helper("sample1"))),
23///     ExeSingle(Box::new(create_play_helper("sample2"))),
24///     ExeParallel(vec![
25///         ExeSingle(Box::new(create_play_helper("sample3"))),
26///         ExeSequential(vec![
27///             ExeSingle(Box::new(create_play_helper("sample4"))),
28///             ExeSingle(Box::new(create_play_helper("sample5"))),
29///         ]),
30///     ]),
31/// ]);
32///
33/// // Example of creating ExePlay using IntoExePlayParallel and IntoExePlaySequential
34/// use cdk_ansible::prelude::*;
35///
36/// let _play_exec = vec![
37///     create_play_helper("sample1").into(),
38///     create_play_helper("sample2").into(),
39///     vec![
40///         create_play_helper("sample3").into(),
41///         vec![
42///             create_play_helper("sample4").into(),
43///             create_play_helper("sample5").into(),
44///         ]
45///         .into_exe_play_parallel(),
46///     ]
47///     .into_exe_play_sequential(),
48/// ]
49/// .into_exe_play_sequential();
50///
51/// ```
52#[derive(Debug, Clone)]
53pub enum ExePlay {
54    /// Sequential execution
55    Sequential(Vec<ExePlay>),
56    /// Parallel execution
57    Parallel(Vec<ExePlay>),
58    /// Single Play
59    Single(Box<Play>),
60}
61
62pub use ExePlay::Parallel as ExeParallel;
63pub use ExePlay::Sequential as ExeSequential;
64pub use ExePlay::Single as ExeSingle;
65
66#[derive(Debug, Clone, PartialEq, Eq, Hash)]
67pub struct StackName(String);
68
69impl From<&str> for StackName {
70    fn from(s: &str) -> Self {
71        StackName(s.to_string())
72    }
73}
74
75impl fmt::Display for StackName {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        write!(f, "{}", self.0)
78    }
79}
80
81#[cfg(test)]
82mod test_exe_play_struct {
83    use super::*;
84    use crate::utils::test::*;
85
86    #[test]
87    fn test_sequential_play_exec() {
88        let _play_exec = ExeSequential(vec![
89            ExeSingle(Box::new(create_play_helper("sample1"))),
90            ExeSingle(Box::new(create_play_helper("sample2"))),
91            ExeParallel(vec![
92                ExeSingle(Box::new(create_play_helper("sample3"))),
93                ExeSingle(Box::new(create_play_helper("sample4"))),
94            ]),
95        ]);
96    }
97}
98
99impl ExePlay {
100    /// Experimental feature: Push a play to the end of the execution
101    ///
102    /// - ExeSingle -> ExeSequential
103    /// - ExeSequential -> ExeSequential
104    /// - ExeParallel -> ExeParallel
105    ///
106    /// # Example
107    ///
108    /// TODO: fill in
109    pub fn push(&mut self, p: ExePlay) {
110        match self {
111            ExePlay::Sequential(plays) => plays.push(p),
112            ExePlay::Parallel(plays) => plays.push(p),
113            ExePlay::Single(_) => {
114                let p1 = self.clone();
115                *self = ExeSequential(vec![p1, p]);
116            }
117        }
118    }
119    pub fn push_play(&mut self, p: Play) {
120        match self {
121            ExePlay::Sequential(plays) => plays.push(p.into()),
122            ExePlay::Parallel(plays) => plays.push(p.into()),
123            ExePlay::Single(_) => {
124                let p1 = self.clone();
125                *self = ExeSequential(vec![p1, p.into()]);
126            }
127        }
128    }
129}
130
131#[cfg(test)]
132mod test_exe_play {
133    use super::*;
134    use crate::utils::test::*;
135
136    #[test]
137    fn test_exe_play_single_push() {
138        let mut exe_play = ExeSingle(create_play_helper("sample1").into());
139        exe_play.push(create_play_helper("sample2").into());
140        match exe_play {
141            ExePlay::Sequential(plays) => {
142                assert_eq!(plays.len(), 2);
143                // OK
144            }
145            _ => unreachable!("exe_play should be ExeSequential"),
146        }
147    }
148    #[test]
149    fn test_exe_play_sequential_push() {
150        let mut exe_play = ExeSequential(vec![create_play_helper("sample1").into()]);
151        exe_play.push(create_play_helper("sample2").into());
152        match exe_play {
153            ExePlay::Sequential(plays) => {
154                assert_eq!(plays.len(), 2);
155                // OK
156            }
157            _ => unreachable!("exe_play should be ExeSequential"),
158        }
159    }
160    #[test]
161    fn test_exe_play_parallel_push() {
162        let mut exe_play = ExeParallel(vec![create_play_helper("sample1").into()]);
163        exe_play.push(create_play_helper("sample2").into());
164        match exe_play {
165            ExePlay::Parallel(plays) => {
166                assert_eq!(plays.len(), 2);
167                // OK
168            }
169            _ => unreachable!("exe_play should be ExeParallel"),
170        }
171    }
172}
173
174impl From<Play> for ExePlay {
175    fn from(play: Play) -> Self {
176        ExePlay::Single(Box::new(play))
177    }
178}
179
180impl From<Box<Play>> for ExePlay {
181    fn from(play: Box<Play>) -> Self {
182        ExePlay::Single(play)
183    }
184}
185
186impl From<Vec<ExePlay>> for ExePlay {
187    fn from(plays: Vec<ExePlay>) -> Self {
188        ExePlay::Sequential(plays)
189    }
190}
191
192#[cfg(test)]
193mod test_exe_play_from_impl {
194    use super::*;
195    use crate::utils::test::*;
196
197    #[test]
198    fn test_exe_play_from_play() {
199        let play = create_play_helper("sample");
200        let exe_play: ExePlay = play.into();
201        match exe_play {
202            ExePlay::Single(_) => {
203                // OK
204            }
205            _ => unreachable!("exe_play should be ExeSingle"),
206        }
207    }
208    #[test]
209    fn test_exe_play_from_play_vec() {
210        let plays = vec![
211            create_play_helper("sample1").into(),
212            create_play_helper("sample2").into(),
213            create_play_helper("sample3").into(),
214        ];
215        let exe_play: ExePlay = plays.into();
216        match exe_play {
217            ExePlay::Sequential(_) => {
218                // OK
219            }
220            _ => unreachable!("exe_play should be ExeSequential"),
221        }
222    }
223}
224
225/// Playbook execution definition for deployment
226#[derive(Debug, Clone)]
227pub enum ExePlaybook {
228    Sequential(Vec<ExePlaybook>),
229    Parallel(Vec<ExePlaybook>),
230    Single(Box<Playbook>),
231}
232
233impl ExePlaybook {
234    pub fn from_exe_play(name: &str, exe_play: ExePlay) -> Self {
235        match exe_play {
236            ExePlay::Sequential(plays) => Self::Sequential(
237                plays
238                    .into_iter()
239                    .enumerate()
240                    .map(|(i, exe_play)| Self::from_exe_play(&format!("{name}_seq{i}"), exe_play))
241                    .collect(),
242            ),
243            ExePlay::Parallel(plays) => Self::Parallel(
244                plays
245                    .into_iter()
246                    .enumerate()
247                    .map(|(i, exe_play)| Self::from_exe_play(&format!("{name}_par{i}"), exe_play))
248                    .collect(),
249            ),
250            ExePlay::Single(play) => Self::Single(Box::new(Playbook {
251                name: format!(
252                    "{name}_{}",
253                    play.name.as_str().to_lowercase().replace(' ', "_")
254                ),
255                plays: vec![*play],
256            })),
257        }
258    }
259}