diff --git a/rustainers/src/port/exposed.rs b/rustainers/src/port/exposed.rs index d293ba9..b449e50 100644 --- a/rustainers/src/port/exposed.rs +++ b/rustainers/src/port/exposed.rs @@ -72,9 +72,13 @@ impl ExposedPort { pub(crate) async fn to_publish(&self) -> String { let port = self.host_port.lock().await; - port.map_or(self.container_port.to_string(), |host| { - format!("{host}:{}", self.container_port) - }) + port.map_or( + format!( + "{container_port}:{container_port}", + container_port = self.container_port + ), + |host| format!("{host}:{}", self.container_port), + ) } /// Bind the host port (if it's not already bound) diff --git a/rustainers/src/runner/inner.rs b/rustainers/src/runner/inner.rs index 3b1b1bb..4d0d25b 100644 --- a/rustainers/src/runner/inner.rs +++ b/rustainers/src/runner/inner.rs @@ -229,6 +229,7 @@ pub(crate) trait InnerRunner: Display + Debug + Send + Sync { async fn list_custom_networks(&self) -> Result, ContainerError> { let mut cmd = self.command(); cmd.push_args(["network", "ls", "--no-trunc", "--format={{json .}}"]); + let mut result = cmd.json_stream::().await?; result.retain(|x| ["bridge", "host", "none"].contains(&x.name.as_str())); Ok(result) diff --git a/rustainers/src/runner/nerdctl.rs b/rustainers/src/runner/nerdctl.rs index 2e9d2f1..7bc2883 100644 --- a/rustainers/src/runner/nerdctl.rs +++ b/rustainers/src/runner/nerdctl.rs @@ -5,7 +5,9 @@ use tracing::debug; use super::{InnerRunner, RunnerError}; use crate::cmd::Cmd; +use crate::runner::ContainerError; use crate::version::Version; +use crate::{ContainerId, IpamNetworkConfig, NetworkInfo}; const MINIMAL_VERSION: Version = Version::new(1, 5); @@ -20,10 +22,54 @@ pub struct Nerdctl { pub version: Version, } +impl Nerdctl { + fn is_modern_version(&self) -> bool { + self.version.major > 1 && self.version.minor > 1 + } +} + impl InnerRunner for Nerdctl { fn command(&self) -> Cmd<'static> { Cmd::new("nerdctl") } + + #[tracing::instrument(level = "debug", skip(self), fields(runner = %self))] + async fn list_custom_networks(&self) -> Result, ContainerError> { + let mut cmd = self.command(); + + if self.is_modern_version() { + cmd.push_args([ + "network", + "ls", + // Remove empty IDs. + r#"--format={{if ne .ID ""}}{{json .}}{{end}}"#, + ]); + } else { + cmd.push_args(["network", "ls", "--no-trunc", "--format={{json .}}"]); + } + + let mut result = cmd.json_stream::().await?; + result.retain(|x| ["bridge", "host", "none"].contains(&x.name.as_str())); + Ok(result) + } + + #[tracing::instrument(level = "debug", skip(self), fields(runner = %self))] + async fn list_network_config( + &self, + network_id: ContainerId, + ) -> Result, ContainerError> { + let results = if self.is_modern_version() { + let mut cmd = self.command(); + cmd.push_args(["network", "inspect", "--format={{json .IPAM.Config}}"]); + cmd.push_arg(network_id); + cmd.json::>>().await? + } else { + self.inspect::>>(network_id, ".IPAM.Config") + .await? + }; + + Ok(results.unwrap_or_default()) + } } impl Display for Nerdctl { diff --git a/rustainers/src/version.rs b/rustainers/src/version.rs index 6517392..d87f732 100644 --- a/rustainers/src/version.rs +++ b/rustainers/src/version.rs @@ -15,9 +15,9 @@ use crate::VersionError; /// we could implement [`Copy`] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Version { - major: u64, - minor: u64, - patch: Option, + pub(crate) major: u64, + pub(crate) minor: u64, + pub(crate) patch: Option, } impl Version {