docker_wrapper/command/network/
disconnect.rs

1//! Docker network disconnect command implementation.
2
3use crate::command::{CommandExecutor, CommandOutput, DockerCommand};
4use crate::error::Result;
5use async_trait::async_trait;
6
7/// Docker network disconnect command builder
8#[derive(Debug, Clone)]
9pub struct NetworkDisconnectCommand {
10    /// Network name
11    network: String,
12    /// Container name or ID
13    container: String,
14    /// Force disconnection
15    force: bool,
16    /// Command executor
17    pub executor: CommandExecutor,
18}
19
20impl NetworkDisconnectCommand {
21    /// Create a new network disconnect command
22    #[must_use]
23    pub fn new(network: impl Into<String>, container: impl Into<String>) -> Self {
24        Self {
25            network: network.into(),
26            container: container.into(),
27            force: false,
28            executor: CommandExecutor::new(),
29        }
30    }
31
32    /// Force disconnection
33    #[must_use]
34    pub fn force(mut self) -> Self {
35        self.force = true;
36        self
37    }
38
39    /// Execute the command
40    ///
41    /// # Errors
42    ///
43    /// Returns an error if the Docker daemon is not running or the command fails
44    pub async fn run(&self) -> Result<NetworkDisconnectResult> {
45        self.execute().await.map(NetworkDisconnectResult::from)
46    }
47}
48
49#[async_trait]
50impl DockerCommand for NetworkDisconnectCommand {
51    type Output = CommandOutput;
52
53    fn build_command_args(&self) -> Vec<String> {
54        let mut args = vec!["network".to_string(), "disconnect".to_string()];
55
56        if self.force {
57            args.push("--force".to_string());
58        }
59
60        args.push(self.network.clone());
61        args.push(self.container.clone());
62        args.extend(self.executor.raw_args.clone());
63        args
64    }
65
66    fn get_executor(&self) -> &CommandExecutor {
67        &self.executor
68    }
69
70    fn get_executor_mut(&mut self) -> &mut CommandExecutor {
71        &mut self.executor
72    }
73
74    async fn execute(&self) -> Result<Self::Output> {
75        let args = self.build_command_args();
76        let command_name = args[0].clone();
77        let command_args = args[1..].to_vec();
78        self.executor
79            .execute_command(&command_name, command_args)
80            .await
81    }
82}
83
84/// Result from network disconnect command
85#[derive(Debug, Clone)]
86pub struct NetworkDisconnectResult {
87    /// Raw command output
88    pub raw_output: CommandOutput,
89}
90
91impl From<CommandOutput> for NetworkDisconnectResult {
92    fn from(output: CommandOutput) -> Self {
93        Self { raw_output: output }
94    }
95}
96
97impl NetworkDisconnectResult {
98    /// Check if the command was successful
99    #[must_use]
100    pub fn is_success(&self) -> bool {
101        self.raw_output.success
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_network_disconnect_basic() {
111        let cmd = NetworkDisconnectCommand::new("my-network", "my-container");
112        let args = cmd.build_command_args();
113        assert_eq!(
114            args,
115            vec!["network", "disconnect", "my-network", "my-container"]
116        );
117    }
118
119    #[test]
120    fn test_network_disconnect_force() {
121        let cmd = NetworkDisconnectCommand::new("my-network", "my-container").force();
122        let args = cmd.build_command_args();
123        assert_eq!(
124            args,
125            vec![
126                "network",
127                "disconnect",
128                "--force",
129                "my-network",
130                "my-container"
131            ]
132        );
133    }
134}