docker_wrapper/command/swarm/
update.rs1use crate::command::{CommandExecutor, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7#[derive(Debug, Clone)]
9pub struct SwarmUpdateResult {
10 pub success: bool,
12 pub output: String,
14}
15
16#[derive(Debug, Clone, Default)]
20pub struct SwarmUpdateCommand {
21 autolock: Option<bool>,
23 cert_expiry: Option<String>,
25 dispatcher_heartbeat: Option<String>,
27 external_ca: Option<String>,
29 max_snapshots: Option<u32>,
31 snapshot_interval: Option<u32>,
33 task_history_limit: Option<i32>,
35 pub executor: CommandExecutor,
37}
38
39impl SwarmUpdateCommand {
40 #[must_use]
42 pub fn new() -> Self {
43 Self::default()
44 }
45
46 #[must_use]
48 pub fn autolock(mut self, enabled: bool) -> Self {
49 self.autolock = Some(enabled);
50 self
51 }
52
53 #[must_use]
55 pub fn cert_expiry(mut self, expiry: impl Into<String>) -> Self {
56 self.cert_expiry = Some(expiry.into());
57 self
58 }
59
60 #[must_use]
62 pub fn dispatcher_heartbeat(mut self, heartbeat: impl Into<String>) -> Self {
63 self.dispatcher_heartbeat = Some(heartbeat.into());
64 self
65 }
66
67 #[must_use]
69 pub fn external_ca(mut self, spec: impl Into<String>) -> Self {
70 self.external_ca = Some(spec.into());
71 self
72 }
73
74 #[must_use]
76 pub fn max_snapshots(mut self, count: u32) -> Self {
77 self.max_snapshots = Some(count);
78 self
79 }
80
81 #[must_use]
83 pub fn snapshot_interval(mut self, interval: u32) -> Self {
84 self.snapshot_interval = Some(interval);
85 self
86 }
87
88 #[must_use]
90 pub fn task_history_limit(mut self, limit: i32) -> Self {
91 self.task_history_limit = Some(limit);
92 self
93 }
94
95 fn build_args(&self) -> Vec<String> {
97 let mut args = vec!["swarm".to_string(), "update".to_string()];
98
99 if let Some(enabled) = self.autolock {
100 args.push("--autolock".to_string());
101 args.push(enabled.to_string());
102 }
103
104 if let Some(ref expiry) = self.cert_expiry {
105 args.push("--cert-expiry".to_string());
106 args.push(expiry.clone());
107 }
108
109 if let Some(ref heartbeat) = self.dispatcher_heartbeat {
110 args.push("--dispatcher-heartbeat".to_string());
111 args.push(heartbeat.clone());
112 }
113
114 if let Some(ref spec) = self.external_ca {
115 args.push("--external-ca".to_string());
116 args.push(spec.clone());
117 }
118
119 if let Some(count) = self.max_snapshots {
120 args.push("--max-snapshots".to_string());
121 args.push(count.to_string());
122 }
123
124 if let Some(interval) = self.snapshot_interval {
125 args.push("--snapshot-interval".to_string());
126 args.push(interval.to_string());
127 }
128
129 if let Some(limit) = self.task_history_limit {
130 args.push("--task-history-limit".to_string());
131 args.push(limit.to_string());
132 }
133
134 args
135 }
136}
137
138#[async_trait]
139impl DockerCommand for SwarmUpdateCommand {
140 type Output = SwarmUpdateResult;
141
142 fn get_executor(&self) -> &CommandExecutor {
143 &self.executor
144 }
145
146 fn get_executor_mut(&mut self) -> &mut CommandExecutor {
147 &mut self.executor
148 }
149
150 fn build_command_args(&self) -> Vec<String> {
151 self.build_args()
152 }
153
154 async fn execute(&self) -> Result<Self::Output> {
155 let args = self.build_args();
156 let output = self.execute_command(args).await?;
157 Ok(SwarmUpdateResult {
158 success: true,
159 output: output.stdout,
160 })
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn test_swarm_update_basic() {
170 let cmd = SwarmUpdateCommand::new();
171 let args = cmd.build_args();
172 assert_eq!(args, vec!["swarm", "update"]);
173 }
174
175 #[test]
176 fn test_swarm_update_autolock_enable() {
177 let cmd = SwarmUpdateCommand::new().autolock(true);
178 let args = cmd.build_args();
179 assert!(args.contains(&"--autolock".to_string()));
180 assert!(args.contains(&"true".to_string()));
181 }
182
183 #[test]
184 fn test_swarm_update_autolock_disable() {
185 let cmd = SwarmUpdateCommand::new().autolock(false);
186 let args = cmd.build_args();
187 assert!(args.contains(&"--autolock".to_string()));
188 assert!(args.contains(&"false".to_string()));
189 }
190
191 #[test]
192 fn test_swarm_update_cert_expiry() {
193 let cmd = SwarmUpdateCommand::new().cert_expiry("90d");
194 let args = cmd.build_args();
195 assert!(args.contains(&"--cert-expiry".to_string()));
196 assert!(args.contains(&"90d".to_string()));
197 }
198
199 #[test]
200 fn test_swarm_update_all_options() {
201 let cmd = SwarmUpdateCommand::new()
202 .autolock(true)
203 .cert_expiry("90d")
204 .dispatcher_heartbeat("5s")
205 .external_ca("protocol=cfssl,url=https://ca.example.com")
206 .max_snapshots(5)
207 .snapshot_interval(10000)
208 .task_history_limit(10);
209
210 let args = cmd.build_args();
211 assert!(args.contains(&"--autolock".to_string()));
212 assert!(args.contains(&"--cert-expiry".to_string()));
213 assert!(args.contains(&"--dispatcher-heartbeat".to_string()));
214 assert!(args.contains(&"--external-ca".to_string()));
215 assert!(args.contains(&"--max-snapshots".to_string()));
216 assert!(args.contains(&"--snapshot-interval".to_string()));
217 assert!(args.contains(&"--task-history-limit".to_string()));
218 }
219}