1use std::collections::{BTreeMap, HashMap};
4
5use serde::{Deserialize, Serialize};
6
7use crate::Result;
8
9#[derive(Serialize, Deserialize, Debug, Clone)]
12#[non_exhaustive]
13pub struct CtlResponse<T> {
14 pub(crate) success: bool,
16 pub(crate) message: String,
18 #[serde(skip_serializing_if = "Option::is_none")]
20 pub(crate) response: Option<T>,
21}
22
23impl<T> CtlResponse<T> {
24 #[must_use]
26 pub fn ok(response: T) -> Self {
27 CtlResponse {
28 success: true,
29 message: String::new(),
30 response: Some(response),
31 }
32 }
33
34 #[must_use]
36 pub fn succeeded(&self) -> bool {
37 self.success
38 }
39
40 #[must_use]
42 pub fn message(&self) -> &str {
43 &self.message
44 }
45
46 #[must_use]
48 pub fn data(&self) -> Option<&T> {
49 self.response.as_ref()
50 }
51
52 #[must_use]
54 pub fn into_data(self) -> Option<T> {
55 self.response
56 }
57}
58
59impl CtlResponse<()> {
60 #[must_use]
63 pub fn success(message: String) -> Self {
64 CtlResponse {
65 success: true,
66 message,
67 response: None,
68 }
69 }
70
71 #[must_use]
75 pub fn error(message: &str) -> Self {
76 CtlResponse {
77 success: false,
78 message: message.to_string(),
79 response: None,
80 }
81 }
82}
83
84#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
86#[non_exhaustive]
87pub struct ScaleComponentCommand {
88 #[serde(default)]
90 pub(crate) component_ref: String,
91 pub(crate) component_id: String,
93 #[serde(default, skip_serializing_if = "Option::is_none")]
96 pub(crate) annotations: Option<BTreeMap<String, String>>,
97 #[serde(default, alias = "count", rename = "count")]
101 pub(crate) max_instances: u32,
102 #[serde(default, skip_serializing_if = "Option::is_none")]
104 pub(crate) component_limits: Option<HashMap<String, String>>,
105 #[serde(default)]
107 pub(crate) host_id: String,
108 #[serde(default)]
114 pub(crate) config: Vec<String>,
115 #[serde(default)]
116 pub(crate) allow_update: bool,
122}
123
124impl ScaleComponentCommand {
125 #[must_use]
126 pub fn component_ref(&self) -> &str {
127 &self.component_ref
128 }
129
130 #[must_use]
131 pub fn component_id(&self) -> &str {
132 &self.component_id
133 }
134
135 #[must_use]
136 pub fn allow_update(&self) -> bool {
137 self.allow_update
138 }
139
140 #[must_use]
141 pub fn config(&self) -> &Vec<String> {
142 &self.config
143 }
144
145 #[must_use]
146 pub fn annotations(&self) -> Option<&BTreeMap<String, String>> {
147 self.annotations.as_ref()
148 }
149
150 #[must_use]
151 pub fn max_instances(&self) -> u32 {
152 self.max_instances
153 }
154
155 #[must_use]
156 pub fn component_limits(&self) -> Option<HashMap<String, String>> {
157 self.component_limits.clone()
158 }
159
160 #[must_use]
161 pub fn host_id(&self) -> &str {
162 &self.host_id
163 }
164
165 #[must_use]
166 pub fn builder() -> ScaleComponentCommandBuilder {
167 ScaleComponentCommandBuilder::default()
168 }
169}
170
171#[derive(Clone, Debug, Default, Eq, PartialEq)]
173#[non_exhaustive]
174pub struct ScaleComponentCommandBuilder {
175 component_ref: Option<String>,
176 component_id: Option<String>,
177 annotations: Option<BTreeMap<String, String>>,
178 max_instances: Option<u32>,
179 component_limits: Option<HashMap<String, String>>,
180 host_id: Option<String>,
181 config: Option<Vec<String>>,
182 allow_update: Option<bool>,
183}
184
185impl ScaleComponentCommandBuilder {
186 #[must_use]
187 pub fn new() -> Self {
188 Self::default()
189 }
190
191 #[must_use]
192 pub fn component_ref(mut self, v: &str) -> Self {
193 self.component_ref = Some(v.into());
194 self
195 }
196
197 #[must_use]
198 pub fn component_id(mut self, v: &str) -> Self {
199 self.component_id = Some(v.into());
200 self
201 }
202
203 #[must_use]
204 pub fn annotations(mut self, v: impl Into<BTreeMap<String, String>>) -> Self {
205 self.annotations = Some(v.into());
206 self
207 }
208
209 #[must_use]
210 pub fn max_instances(mut self, v: u32) -> Self {
211 self.max_instances = Some(v);
212 self
213 }
214
215 #[must_use]
216 pub fn component_limits(mut self, v: Option<HashMap<String, String>>) -> Self {
217 self.component_limits = v;
218 self
219 }
220
221 #[must_use]
222 pub fn host_id(mut self, v: &str) -> Self {
223 self.host_id = Some(v.into());
224 self
225 }
226
227 #[must_use]
228 pub fn config(mut self, v: Vec<String>) -> Self {
229 self.config = Some(v);
230 self
231 }
232
233 #[must_use]
234 pub fn allow_update(mut self, v: bool) -> Self {
235 self.allow_update = Some(v);
236 self
237 }
238
239 pub fn build(self) -> Result<ScaleComponentCommand> {
240 Ok(ScaleComponentCommand {
241 component_ref: self
242 .component_ref
243 .ok_or_else(|| "component ref is required for scaling components".to_string())?,
244 component_id: self
245 .component_id
246 .ok_or_else(|| "component id is required for scaling components".to_string())?,
247 annotations: self.annotations,
248 max_instances: self.max_instances.unwrap_or(0),
249 component_limits: self.component_limits,
250 host_id: self
251 .host_id
252 .ok_or_else(|| "host id is required for scaling hosts host".to_string())?,
253 config: self.config.unwrap_or_default(),
254 allow_update: self.allow_update.unwrap_or_default(),
255 })
256 }
257}
258
259#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
262#[non_exhaustive]
263pub struct StartProviderCommand {
264 provider_id: String,
266 #[serde(default)]
268 provider_ref: String,
269 #[serde(default)]
271 host_id: String,
272 #[serde(default)]
278 config: Vec<String>,
279 #[serde(default, skip_serializing_if = "Option::is_none")]
282 annotations: Option<BTreeMap<String, String>>,
283}
284
285impl StartProviderCommand {
286 #[must_use]
287 pub fn provider_id(&self) -> &str {
288 &self.provider_id
289 }
290
291 #[must_use]
292 pub fn provider_ref(&self) -> &str {
293 &self.provider_ref
294 }
295
296 #[must_use]
297 pub fn host_id(&self) -> &str {
298 &self.host_id
299 }
300
301 #[must_use]
302 pub fn config(&self) -> &Vec<String> {
303 &self.config
304 }
305
306 #[must_use]
307 pub fn annotations(&self) -> Option<&BTreeMap<String, String>> {
308 self.annotations.as_ref()
309 }
310
311 #[must_use]
312 pub fn builder() -> StartProviderCommandBuilder {
313 StartProviderCommandBuilder::default()
314 }
315}
316
317#[derive(Clone, Debug, Default, Eq, PartialEq)]
319#[non_exhaustive]
320pub struct StartProviderCommandBuilder {
321 host_id: Option<String>,
322 provider_id: Option<String>,
323 provider_ref: Option<String>,
324 annotations: Option<BTreeMap<String, String>>,
325 config: Option<Vec<String>>,
326}
327
328impl StartProviderCommandBuilder {
329 #[must_use]
330 pub fn new() -> Self {
331 Self::default()
332 }
333
334 #[must_use]
335 pub fn provider_ref(mut self, v: &str) -> Self {
336 self.provider_ref = Some(v.into());
337 self
338 }
339
340 #[must_use]
341 pub fn provider_id(mut self, v: &str) -> Self {
342 self.provider_id = Some(v.into());
343 self
344 }
345
346 #[must_use]
347 pub fn annotations(mut self, v: impl Into<BTreeMap<String, String>>) -> Self {
348 self.annotations = Some(v.into());
349 self
350 }
351
352 #[must_use]
353 pub fn host_id(mut self, v: &str) -> Self {
354 self.host_id = Some(v.into());
355 self
356 }
357
358 #[must_use]
359 pub fn config(mut self, v: Vec<String>) -> Self {
360 self.config = Some(v);
361 self
362 }
363
364 pub fn build(self) -> Result<StartProviderCommand> {
365 Ok(StartProviderCommand {
366 provider_ref: self
367 .provider_ref
368 .ok_or_else(|| "provider ref is required for starting providers".to_string())?,
369 provider_id: self
370 .provider_id
371 .ok_or_else(|| "provider id is required for starting providers".to_string())?,
372 annotations: self.annotations,
373 host_id: self
374 .host_id
375 .ok_or_else(|| "host id is required for starting providers".to_string())?,
376 config: self.config.unwrap_or_default(),
377 })
378 }
379}
380
381#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
383#[non_exhaustive]
384pub struct StopHostCommand {
385 #[serde(default)]
387 pub(crate) host_id: String,
388 #[serde(default, skip_serializing_if = "Option::is_none")]
390 pub(crate) timeout: Option<u64>,
391}
392
393impl StopHostCommand {
394 #[must_use]
395 pub fn host_id(&self) -> &str {
396 &self.host_id
397 }
398
399 #[must_use]
400 pub fn timeout(&self) -> Option<u64> {
401 self.timeout
402 }
403
404 #[must_use]
405 pub fn builder() -> StopHostCommandBuilder {
406 StopHostCommandBuilder::default()
407 }
408}
409
410#[derive(Clone, Debug, Default, Eq, PartialEq)]
411#[non_exhaustive]
412pub struct StopHostCommandBuilder {
413 host_id: Option<String>,
414 timeout: Option<u64>,
415}
416
417impl StopHostCommandBuilder {
418 #[must_use]
419 pub fn new() -> Self {
420 Self::default()
421 }
422
423 #[must_use]
424 pub fn host_id(mut self, v: &str) -> Self {
425 self.host_id = Some(v.into());
426 self
427 }
428
429 #[must_use]
430 pub fn timeout(mut self, v: u64) -> Self {
431 self.timeout = Some(v);
432 self
433 }
434
435 pub fn build(self) -> Result<StopHostCommand> {
436 Ok(StopHostCommand {
437 host_id: self
438 .host_id
439 .ok_or_else(|| "host id is required for stopping host".to_string())?,
440 timeout: self.timeout,
441 })
442 }
443}
444
445#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
447#[non_exhaustive]
448pub struct StopProviderCommand {
449 #[serde(default)]
451 pub(crate) host_id: String,
452 #[serde(default, alias = "provider_ref")]
454 pub(crate) provider_id: String,
455}
456
457impl StopProviderCommand {
458 #[must_use]
459 pub fn host_id(&self) -> &str {
460 &self.host_id
461 }
462
463 #[must_use]
464 pub fn provider_id(&self) -> &str {
465 &self.provider_id
466 }
467
468 #[must_use]
469 pub fn builder() -> StopProviderCommandBuilder {
470 StopProviderCommandBuilder::default()
471 }
472}
473
474#[derive(Clone, Debug, Default, Eq, PartialEq)]
476#[non_exhaustive]
477pub struct StopProviderCommandBuilder {
478 host_id: Option<String>,
479 provider_id: Option<String>,
480}
481
482impl StopProviderCommandBuilder {
483 #[must_use]
484 pub fn new() -> Self {
485 Self::default()
486 }
487
488 #[must_use]
489 pub fn host_id(mut self, v: &str) -> Self {
490 self.host_id = Some(v.into());
491 self
492 }
493
494 #[must_use]
495 pub fn provider_id(mut self, v: &str) -> Self {
496 self.provider_id = Some(v.into());
497 self
498 }
499
500 pub fn build(self) -> Result<StopProviderCommand> {
501 Ok(StopProviderCommand {
502 host_id: self
503 .host_id
504 .ok_or_else(|| "host id is required for stopping provider".to_string())?,
505 provider_id: self
506 .provider_id
507 .ok_or_else(|| "provider id is required for stopping provider".to_string())?,
508 })
509 }
510}
511
512#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
516#[non_exhaustive]
517pub struct UpdateComponentCommand {
518 #[serde(default)]
520 pub(crate) component_id: String,
521 #[serde(default, skip_serializing_if = "Option::is_none")]
525 pub(crate) annotations: Option<BTreeMap<String, String>>,
526 #[serde(default)]
528 pub(crate) host_id: String,
529 #[serde(default)]
531 pub(crate) new_component_ref: String,
532}
533
534impl UpdateComponentCommand {
535 #[must_use]
536 pub fn host_id(&self) -> &str {
537 &self.host_id
538 }
539
540 #[must_use]
541 pub fn component_id(&self) -> &str {
542 &self.component_id
543 }
544
545 #[must_use]
546 pub fn new_component_ref(&self) -> &str {
547 &self.new_component_ref
548 }
549
550 #[must_use]
551 pub fn annotations(&self) -> Option<&BTreeMap<String, String>> {
552 self.annotations.as_ref()
553 }
554
555 #[must_use]
556 pub fn builder() -> UpdateComponentCommandBuilder {
557 UpdateComponentCommandBuilder::default()
558 }
559}
560
561#[derive(Clone, Debug, Default, Eq, PartialEq)]
563#[non_exhaustive]
564pub struct UpdateComponentCommandBuilder {
565 host_id: Option<String>,
566 component_id: Option<String>,
567 new_component_ref: Option<String>,
568 annotations: Option<BTreeMap<String, String>>,
569}
570
571impl UpdateComponentCommandBuilder {
572 #[must_use]
573 pub fn new() -> Self {
574 Self::default()
575 }
576
577 #[must_use]
578 pub fn host_id(mut self, v: &str) -> Self {
579 self.host_id = Some(v.into());
580 self
581 }
582
583 #[must_use]
584 pub fn component_id(mut self, v: &str) -> Self {
585 self.component_id = Some(v.into());
586 self
587 }
588
589 #[must_use]
590 pub fn new_component_ref(mut self, v: &str) -> Self {
591 self.new_component_ref = Some(v.into());
592 self
593 }
594
595 #[must_use]
596 pub fn annotations(mut self, v: impl Into<BTreeMap<String, String>>) -> Self {
597 self.annotations = Some(v.into());
598 self
599 }
600
601 pub fn build(self) -> Result<UpdateComponentCommand> {
602 Ok(UpdateComponentCommand {
603 host_id: self
604 .host_id
605 .ok_or_else(|| "host id is required for updating components".to_string())?,
606 component_id: self
607 .component_id
608 .ok_or_else(|| "component id is required for updating components".to_string())?,
609 new_component_ref: self.new_component_ref.ok_or_else(|| {
610 "new component ref is required for updating components".to_string()
611 })?,
612 annotations: self.annotations,
613 })
614 }
615}
616
617#[cfg(test)]
618mod tests {
619 use std::collections::BTreeMap;
620
621 use super::{
622 ScaleComponentCommand, StartProviderCommand, StopHostCommand, StopProviderCommand,
623 UpdateComponentCommand,
624 };
625
626 #[test]
627 fn scale_component_command_builder() {
628 assert_eq!(
629 ScaleComponentCommand {
630 component_ref: "component_ref".into(),
631 component_id: "component_id".into(),
632 host_id: "host_id".into(),
633 config: vec!["c".into()],
634 allow_update: true,
635 annotations: Some(BTreeMap::from([("a".into(), "b".into())])),
636 max_instances: 1,
637 component_limits: None,
638 },
639 ScaleComponentCommand::builder()
640 .component_ref("component_ref")
641 .component_id("component_id")
642 .host_id("host_id")
643 .config(vec!["c".into()])
644 .allow_update(true)
645 .annotations(BTreeMap::from([("a".into(), "b".into())]))
646 .max_instances(1)
647 .build()
648 .unwrap()
649 )
650 }
651
652 #[test]
653 fn start_provider_command_builder() {
654 assert_eq!(
655 StartProviderCommand {
656 provider_id: "provider_id".into(),
657 provider_ref: "provider_ref".into(),
658 host_id: "host_id".into(),
659 config: vec!["p".into()],
660 annotations: Some(BTreeMap::from([("a".into(), "b".into())])),
661 },
662 StartProviderCommand::builder()
663 .provider_id("provider_id")
664 .provider_ref("provider_ref")
665 .host_id("host_id")
666 .config(vec!["p".into()])
667 .annotations(BTreeMap::from([("a".into(), "b".into())]))
668 .build()
669 .unwrap()
670 )
671 }
672
673 #[test]
674 fn stop_host_command_builder() {
675 assert_eq!(
676 StopHostCommand {
677 host_id: "host_id".into(),
678 timeout: Some(1),
679 },
680 StopHostCommand::builder()
681 .host_id("host_id")
682 .timeout(1)
683 .build()
684 .unwrap()
685 )
686 }
687
688 #[test]
689 fn stop_provider_command_builder() {
690 assert_eq!(
691 StopProviderCommand {
692 host_id: "host_id".into(),
693 provider_id: "provider_id".into(),
694 },
695 StopProviderCommand::builder()
696 .provider_id("provider_id")
697 .host_id("host_id")
698 .build()
699 .unwrap()
700 )
701 }
702
703 #[test]
704 fn update_component_command_builder() {
705 assert_eq!(
706 UpdateComponentCommand {
707 host_id: "host_id".into(),
708 component_id: "component_id".into(),
709 new_component_ref: "new_component_ref".into(),
710 annotations: Some(BTreeMap::from([("a".into(), "b".into())])),
711 },
712 UpdateComponentCommand::builder()
713 .host_id("host_id")
714 .component_id("component_id")
715 .new_component_ref("new_component_ref")
716 .annotations(BTreeMap::from([("a".into(), "b".into())]))
717 .build()
718 .unwrap()
719 )
720 }
721}