use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
use crate::error::Result;
use async_trait::async_trait;
#[derive(Debug, Clone)]
pub struct SwarmJoinResult {
pub success: bool,
pub output: String,
}
impl SwarmJoinResult {
fn parse(output: &CommandOutput) -> Self {
Self {
success: output.success,
output: output.stdout.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct SwarmJoinCommand {
remote_addr: String,
token: String,
advertise_addr: Option<String>,
availability: Option<String>,
data_path_addr: Option<String>,
listen_addr: Option<String>,
pub executor: CommandExecutor,
}
impl SwarmJoinCommand {
#[must_use]
pub fn new(token: impl Into<String>, remote_addr: impl Into<String>) -> Self {
Self {
remote_addr: remote_addr.into(),
token: token.into(),
advertise_addr: None,
availability: None,
data_path_addr: None,
listen_addr: None,
executor: CommandExecutor::new(),
}
}
#[must_use]
pub fn advertise_addr(mut self, addr: impl Into<String>) -> Self {
self.advertise_addr = Some(addr.into());
self
}
#[must_use]
pub fn availability(mut self, availability: impl Into<String>) -> Self {
self.availability = Some(availability.into());
self
}
#[must_use]
pub fn data_path_addr(mut self, addr: impl Into<String>) -> Self {
self.data_path_addr = Some(addr.into());
self
}
#[must_use]
pub fn listen_addr(mut self, addr: impl Into<String>) -> Self {
self.listen_addr = Some(addr.into());
self
}
fn build_args(&self) -> Vec<String> {
let mut args = vec!["swarm".to_string(), "join".to_string()];
if let Some(ref addr) = self.advertise_addr {
args.push("--advertise-addr".to_string());
args.push(addr.clone());
}
if let Some(ref availability) = self.availability {
args.push("--availability".to_string());
args.push(availability.clone());
}
if let Some(ref addr) = self.data_path_addr {
args.push("--data-path-addr".to_string());
args.push(addr.clone());
}
if let Some(ref addr) = self.listen_addr {
args.push("--listen-addr".to_string());
args.push(addr.clone());
}
args.push("--token".to_string());
args.push(self.token.clone());
args.push(self.remote_addr.clone());
args
}
}
#[async_trait]
impl DockerCommand for SwarmJoinCommand {
type Output = SwarmJoinResult;
fn get_executor(&self) -> &CommandExecutor {
&self.executor
}
fn get_executor_mut(&mut self) -> &mut CommandExecutor {
&mut self.executor
}
fn build_command_args(&self) -> Vec<String> {
self.build_args()
}
async fn execute(&self) -> Result<Self::Output> {
let args = self.build_args();
let output = self.execute_command(args).await?;
Ok(SwarmJoinResult::parse(&output))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_swarm_join_basic() {
let cmd = SwarmJoinCommand::new("SWMTKN-1-xxx", "192.168.1.1:2377");
let args = cmd.build_args();
assert_eq!(args[0], "swarm");
assert_eq!(args[1], "join");
assert!(args.contains(&"--token".to_string()));
assert!(args.contains(&"SWMTKN-1-xxx".to_string()));
assert!(args.contains(&"192.168.1.1:2377".to_string()));
}
#[test]
fn test_swarm_join_with_options() {
let cmd = SwarmJoinCommand::new("SWMTKN-1-xxx", "192.168.1.1:2377")
.advertise_addr("192.168.1.2:2377")
.availability("active")
.data_path_addr("192.168.1.2")
.listen_addr("0.0.0.0:2377");
let args = cmd.build_args();
assert!(args.contains(&"--advertise-addr".to_string()));
assert!(args.contains(&"--availability".to_string()));
assert!(args.contains(&"--data-path-addr".to_string()));
assert!(args.contains(&"--listen-addr".to_string()));
}
}