1use derive_builder::Builder;
16use kube::CustomResource;
17use schemars::JsonSchema;
18use serde::{Deserialize, Serialize};
19
20use super::common::{Mode, Selector};
21
22#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Builder, JsonSchema)]
23#[serde(rename_all = "camelCase")]
24pub struct Target {
25 mode: Mode,
26 selector: Selector,
27}
28
29#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema)]
30#[serde(rename_all = "kebab-case")]
31pub enum Action {
32 Netem,
33 Delay,
34 Loss,
35 Corrupt,
36 Partition,
37 Bandwidth,
38}
39
40#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema)]
41#[serde(rename_all = "kebab-case")]
42pub enum Direction {
43 From,
44 To,
45 Both,
46}
47
48#[derive(
49 CustomResource, Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Builder, JsonSchema,
50)]
51#[kube(
52 group = "chaos-mesh.org",
53 version = "v1alpha1",
54 namespaced,
55 kind = "NetworkChaos",
56 plural = "networkchaos",
57 singular = "networkchaos",
58 derive = "PartialEq"
59)]
60#[serde(rename_all = "camelCase")]
61pub struct NetworkChaosSpec {
62 action: Action,
68 #[builder(setter(into), default = "None")]
70 #[serde(skip_serializing_if = "Option::is_none")]
71 target: Option<Target>,
72 #[builder(setter(into), default = "None")]
76 #[serde(skip_serializing_if = "Option::is_none")]
77 direction: Option<Direction>,
78 mode: Mode,
83 #[builder(setter(into), default = "None")]
86 #[serde(skip_serializing_if = "Option::is_none")]
87 value: Option<String>,
88 selector: Selector,
90 #[builder(setter(into), default = "Vec::new()")]
93 #[serde(skip_serializing_if = "Vec::is_empty", default)]
94 external_targets: Vec<String>,
95 #[builder(setter(into), default = "None")]
97 #[serde(skip_serializing_if = "Option::is_none")]
98 device: Option<String>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 #[builder(setter(into), default = "None")]
101 delay: Option<Delay>,
102 #[serde(skip_serializing_if = "Option::is_none")]
103 #[builder(setter(into), default = "None")]
104 loss: Option<Loss>,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 #[builder(setter(into), default = "None")]
107 duplicate: Option<Duplicate>,
108 #[serde(skip_serializing_if = "Option::is_none")]
109 #[builder(setter(into), default = "None")]
110 corrupt: Option<Corrupt>,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 #[builder(setter(into), default = "None")]
113 bandwidth: Option<Bandwidth>,
114 #[serde(skip_serializing_if = "Option::is_none")]
115 #[builder(setter(into), default = "None")]
116 duration: Option<String>,
117}
118
119#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize, Builder, JsonSchema)]
120#[serde(default)]
121#[builder(default)]
122pub struct Delay {
123 #[serde(skip_serializing_if = "Option::is_none")]
124 #[builder(setter(into, strip_option))]
125 latency: Option<String>,
127 #[serde(skip_serializing_if = "Option::is_none")]
130 #[builder(setter(into, strip_option))]
131 correlation: Option<String>,
132 #[serde(skip_serializing_if = "Option::is_none")]
134 #[builder(setter(into, strip_option))]
135 jitter: Option<String>,
136 #[serde(skip_serializing_if = "Option::is_none")]
138 #[builder(setter(into, strip_option))]
139 reorder: Option<Reorder>,
140}
141
142#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema, Builder)]
143#[serde(default)]
144#[builder(default)]
145pub struct Reorder {
146 #[serde(skip_serializing_if = "Option::is_none")]
148 #[builder(setter(into, strip_option))]
149 reorder: Option<String>,
150 #[serde(skip_serializing_if = "Option::is_none")]
153 #[builder(setter(into, strip_option))]
154 correlation: Option<String>,
155 #[serde(skip_serializing_if = "Option::is_none")]
157 #[builder(setter(into, strip_option))]
158 gap: Option<i32>,
159}
160
161#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema, Builder)]
162#[serde(default)]
163#[builder(default, setter(into, strip_option))]
164pub struct Loss {
165 #[serde(skip_serializing_if = "Option::is_none")]
168 loss: Option<String>,
169 #[serde(skip_serializing_if = "Option::is_none")]
172 correlation: Option<String>,
173}
174
175#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema, Builder)]
176#[serde(default)]
177#[builder(default, setter(into, strip_option))]
178pub struct Duplicate {
179 #[serde(skip_serializing_if = "Option::is_none")]
182 duplicate: Option<String>,
183 #[serde(skip_serializing_if = "Option::is_none")]
186 correlation: Option<String>,
187}
188
189#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema, Builder)]
190#[serde(default)]
191#[builder(default, setter(into, strip_option))]
192pub struct Corrupt {
193 #[serde(skip_serializing_if = "Option::is_none")]
195 corrupt: Option<String>,
196 #[serde(skip_serializing_if = "Option::is_none")]
199 correlation: Option<String>,
200}
201
202#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize, JsonSchema, Builder)]
203#[serde(default)]
204#[builder(default)]
205pub struct Bandwidth {
206 rate: String,
208 limit: u32,
210 buffer: u32,
212 #[serde(skip_serializing_if = "Option::is_none")]
214 #[builder(setter(into, strip_option))]
215 peakrate: Option<u64>,
216 #[serde(skip_serializing_if = "Option::is_none")]
218 #[builder(setter(into, strip_option))]
219 minburst: Option<u32>,
220}
221
222#[cfg(test)]
223mod tests {
224 use std::collections::BTreeMap;
225
226 use super::{Action, Direction, NetworkChaosSpecBuilder, TargetBuilder};
227 use crate::utils::crd::common::{Mode, SelectorBuilder};
228 use crate::utils::crd::network::{DelayBuilder, NetworkChaos};
229
230 #[test]
231 fn test_serde() {
232 let mut fs = BTreeMap::new();
233 fs.insert("app".into(), "datanode".into());
234 let selector = SelectorBuilder::default()
235 .namespaces(vec!["default".into()])
236 .label_selectors(fs)
237 .build()
238 .unwrap();
239 let target = TargetBuilder::default()
240 .mode(Mode::All)
241 .selector(selector.clone())
242 .build()
243 .unwrap();
244 let delay = DelayBuilder::default()
245 .latency("100ms")
246 .correlation("100")
247 .jitter("0ms")
248 .build()
249 .unwrap();
250 let spec = NetworkChaosSpecBuilder::default()
251 .action(Action::Delay)
252 .target(target)
253 .direction(Direction::Both)
254 .mode(Mode::One)
255 .selector(selector)
256 .delay(delay)
257 .duration(Some("10s".to_string()))
258 .build()
259 .unwrap();
260 let crd = NetworkChaos::new("my-delay", spec);
261 let ser = serde_yaml::to_string(&crd).unwrap();
262
263 let expected = r#"apiVersion: chaos-mesh.org/v1alpha1
264kind: NetworkChaos
265metadata:
266 name: my-delay
267spec:
268 action: delay
269 target:
270 mode: all
271 selector:
272 namespaces:
273 - default
274 labelSelectors:
275 app: datanode
276 direction: both
277 mode: one
278 selector:
279 namespaces:
280 - default
281 labelSelectors:
282 app: datanode
283 delay:
284 latency: 100ms
285 correlation: '100'
286 jitter: 0ms
287 duration: 10s
288"#;
289 assert_eq!(expected, ser);
290 }
291}