From 903c05d107f535b66401b9b28f0154be423a7bc8 Mon Sep 17 00:00:00 2001 From: Linken Quy Dinh Date: Mon, 22 Dec 2025 13:38:06 +0100 Subject: [PATCH 1/7] nerdctl remove network --no-trunc --- rustainers/src/cmd/mod.rs | 2 +- rustainers/src/runner/inner.rs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/rustainers/src/cmd/mod.rs b/rustainers/src/cmd/mod.rs index ce57026..615c80d 100644 --- a/rustainers/src/cmd/mod.rs +++ b/rustainers/src/cmd/mod.rs @@ -14,7 +14,7 @@ pub use self::error::*; #[derive(Debug, Clone)] pub(crate) struct Cmd<'a> { - command: &'a str, + pub(crate) command: &'a str, args: Vec, dir: Option<&'a Path>, env: IndexMap, diff --git a/rustainers/src/runner/inner.rs b/rustainers/src/runner/inner.rs index 3b1b1bb..d440b73 100644 --- a/rustainers/src/runner/inner.rs +++ b/rustainers/src/runner/inner.rs @@ -228,7 +228,12 @@ pub(crate) trait InnerRunner: Display + Debug + Send + Sync { #[tracing::instrument(level = "debug", skip(self), fields(runner = %self))] async fn list_custom_networks(&self) -> Result, ContainerError> { let mut cmd = self.command(); - cmd.push_args(["network", "ls", "--no-trunc", "--format={{json .}}"]); + cmd.push_args(["network", "ls", "--format={{json .}}"]); + + if cmd.command != "nerctl" { + cmd.push_arg("--no-trunc"); + } + let mut result = cmd.json_stream::().await?; result.retain(|x| ["bridge", "host", "none"].contains(&x.name.as_str())); Ok(result) From b054ae017e9c32dbf2a4f58e56b05c59fa448b95 Mon Sep 17 00:00:00 2001 From: Linken Quy Dinh Date: Mon, 22 Dec 2025 13:49:18 +0100 Subject: [PATCH 2/7] nerdctl remove network --no-trunc --- rustainers/src/cmd/mod.rs | 2 +- rustainers/src/runner/inner.rs | 6 +----- rustainers/src/runner/nerdctl.rs | 11 +++++++++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/rustainers/src/cmd/mod.rs b/rustainers/src/cmd/mod.rs index 615c80d..ce57026 100644 --- a/rustainers/src/cmd/mod.rs +++ b/rustainers/src/cmd/mod.rs @@ -14,7 +14,7 @@ pub use self::error::*; #[derive(Debug, Clone)] pub(crate) struct Cmd<'a> { - pub(crate) command: &'a str, + command: &'a str, args: Vec, dir: Option<&'a Path>, env: IndexMap, diff --git a/rustainers/src/runner/inner.rs b/rustainers/src/runner/inner.rs index d440b73..4d0d25b 100644 --- a/rustainers/src/runner/inner.rs +++ b/rustainers/src/runner/inner.rs @@ -228,11 +228,7 @@ pub(crate) trait InnerRunner: Display + Debug + Send + Sync { #[tracing::instrument(level = "debug", skip(self), fields(runner = %self))] async fn list_custom_networks(&self) -> Result, ContainerError> { let mut cmd = self.command(); - cmd.push_args(["network", "ls", "--format={{json .}}"]); - - if cmd.command != "nerctl" { - cmd.push_arg("--no-trunc"); - } + 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())); diff --git a/rustainers/src/runner/nerdctl.rs b/rustainers/src/runner/nerdctl.rs index 2e9d2f1..e89558c 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::NetworkInfo; const MINIMAL_VERSION: Version = Version::new(1, 5); @@ -24,6 +26,15 @@ 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(); + cmd.push_args(["network", "ls", "--format={{json .}}"]); + let mut result = cmd.json_stream::().await?; + result.retain(|x| ["bridge", "host", "none"].contains(&x.name.as_str())); + Ok(result) + } } impl Display for Nerdctl { From 32158350bf7ac0a03b1dfe6e08a52a2075321b8d Mon Sep 17 00:00:00 2001 From: Linken Quy Dinh Date: Mon, 22 Dec 2025 13:56:58 +0100 Subject: [PATCH 3/7] check for later versions of nerdctl --- rustainers/src/runner/nerdctl.rs | 13 ++++++++++++- rustainers/src/version.rs | 6 +++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/rustainers/src/runner/nerdctl.rs b/rustainers/src/runner/nerdctl.rs index e89558c..3323a97 100644 --- a/rustainers/src/runner/nerdctl.rs +++ b/rustainers/src/runner/nerdctl.rs @@ -30,7 +30,18 @@ impl InnerRunner for Nerdctl { #[tracing::instrument(level = "debug", skip(self), fields(runner = %self))] async fn list_custom_networks(&self) -> Result, ContainerError> { let mut cmd = self.command(); - cmd.push_args(["network", "ls", "--format={{json .}}"]); + + if self.version.major > 1 && self.version.minor > 1 { + 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) 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 { From ed45296c683f5d8097480cb296e9872a428f6e87 Mon Sep 17 00:00:00 2001 From: Linken Quy Dinh Date: Mon, 22 Dec 2025 13:59:02 +0100 Subject: [PATCH 4/7] check for later versions of nerdctl --- rustainers/src/runner/nerdctl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustainers/src/runner/nerdctl.rs b/rustainers/src/runner/nerdctl.rs index 3323a97..975f9c5 100644 --- a/rustainers/src/runner/nerdctl.rs +++ b/rustainers/src/runner/nerdctl.rs @@ -36,7 +36,7 @@ impl InnerRunner for Nerdctl { "network", "ls", // Remove empty IDs. - r#"--format='{{if ne .ID ""}}{{json .}}{{end}}'"#, + "{{if ne .ID \"\"}}{{json .}}{{end}}", ]); } else { cmd.push_args(["network", "ls", "--no-trunc", "--format={{json .}}"]); From a671f0eb3fa974b2840cb95f75214caf6a6aafd7 Mon Sep 17 00:00:00 2001 From: Linken Quy Dinh Date: Mon, 22 Dec 2025 14:00:25 +0100 Subject: [PATCH 5/7] check for later versions of nerdctl --- rustainers/src/runner/nerdctl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustainers/src/runner/nerdctl.rs b/rustainers/src/runner/nerdctl.rs index 975f9c5..a5404f0 100644 --- a/rustainers/src/runner/nerdctl.rs +++ b/rustainers/src/runner/nerdctl.rs @@ -36,7 +36,7 @@ impl InnerRunner for Nerdctl { "network", "ls", // Remove empty IDs. - "{{if ne .ID \"\"}}{{json .}}{{end}}", + r#"--format={{if ne .ID ""}}{{json .}}{{end}}"#, ]); } else { cmd.push_args(["network", "ls", "--no-trunc", "--format={{json .}}"]); From ed4e1a00016d35f005a375870116513a7ec012f6 Mon Sep 17 00:00:00 2001 From: Linken Quy Dinh Date: Mon, 22 Dec 2025 14:06:28 +0100 Subject: [PATCH 6/7] check for later versions of nerdctl --- rustainers/src/runner/nerdctl.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/rustainers/src/runner/nerdctl.rs b/rustainers/src/runner/nerdctl.rs index a5404f0..7bc2883 100644 --- a/rustainers/src/runner/nerdctl.rs +++ b/rustainers/src/runner/nerdctl.rs @@ -7,7 +7,7 @@ use super::{InnerRunner, RunnerError}; use crate::cmd::Cmd; use crate::runner::ContainerError; use crate::version::Version; -use crate::NetworkInfo; +use crate::{ContainerId, IpamNetworkConfig, NetworkInfo}; const MINIMAL_VERSION: Version = Version::new(1, 5); @@ -22,6 +22,12 @@ 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") @@ -31,7 +37,7 @@ impl InnerRunner for Nerdctl { async fn list_custom_networks(&self) -> Result, ContainerError> { let mut cmd = self.command(); - if self.version.major > 1 && self.version.minor > 1 { + if self.is_modern_version() { cmd.push_args([ "network", "ls", @@ -46,6 +52,24 @@ impl InnerRunner for Nerdctl { 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 { From a1cbf1d3b554758960cccdaf6b80d6ad23c6ce05 Mon Sep 17 00:00:00 2001 From: Linken Quy Dinh Date: Mon, 22 Dec 2025 14:26:52 +0100 Subject: [PATCH 7/7] correct port mapping syntax --- rustainers/src/port/exposed.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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)