From eb3ccbceb62a8925da833314b032f498a0cfdea7 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 30 Sep 2025 16:38:46 +0900 Subject: [PATCH] Add TestReservePorts TestReservePorts tests that a published port appears as a listening port on the host. Follow-up to PR 4526 Signed-off-by: Akihiro Suda --- .../container_run_network_linux_test.go | 55 +++++++++++++++++++ pkg/testutil/images.yaml | 4 ++ pkg/testutil/nerdtest/requirements.go | 18 ++++++ pkg/testutil/testutil_linux.go | 1 + 4 files changed, 78 insertions(+) diff --git a/cmd/nerdctl/container/container_run_network_linux_test.go b/cmd/nerdctl/container/container_run_network_linux_test.go index 02f01677cee..6d7b353cdea 100644 --- a/cmd/nerdctl/container/container_run_network_linux_test.go +++ b/cmd/nerdctl/container/container_run_network_linux_test.go @@ -1080,3 +1080,58 @@ dns_search = ["example.com", "test.local"]` } testCase.Run(t) } + +// TestReservePorts tests that a published port appears +// as a listening port on the host. +// See https://github.com/containerd/nerdctl/pull/4526 +func TestReservePorts(t *testing.T) { + nerdtest.Setup() + testCase := &test.Case{ + Require: require.All( + require.Not(require.Windows), + require.Not(nerdtest.RootlessWithoutDetachNetNS), // RootlessKit v1 + ), + NoParallel: true, + SubTests: []*test.Case{ + { + Description: "TCP", + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("nginx"), + "-p", "60080:80", testutil.NginxAlpineImage) + nerdtest.EnsureContainerStarted(helpers, data.Identifier("nginx")) + time.Sleep(3 * time.Second) + }, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier("nginx")) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("run", "--rm", + "--network=host", testutil.CommonImage, "netstat", "-lnt") + }, + Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.All( + expect.Contains(":60080"), + )), + }, + { + Description: "UDP", + Setup: func(data test.Data, helpers test.Helpers) { + helpers.Ensure("run", "-d", "--name", data.Identifier("coredns"), + "-p", "60053:53/udp", testutil.CoreDNSImage) + nerdtest.EnsureContainerStarted(helpers, data.Identifier("coredns")) + time.Sleep(3 * time.Second) + }, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier("coredns")) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("run", "--rm", + "--network=host", testutil.CommonImage, "netstat", "-lnu") + }, + Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.All( + expect.Contains(":60053"), + )), + }, + }, + } + testCase.Run(t) +} diff --git a/pkg/testutil/images.yaml b/pkg/testutil/images.yaml index 67c0e3a3551..089273231e7 100644 --- a/pkg/testutil/images.yaml +++ b/pkg/testutil/images.yaml @@ -75,6 +75,10 @@ ubuntu: ref: "public.ecr.aws/docker/library/ubuntu" tag: "23.10" +coredns: + ref: "public.ecr.aws/eks-distro/coredns/coredns" + tag: "v1.12.2-eks-1-31-latest" + # Future: images to add or update soon. # busybox:1.37.0@sha256:37f7b378a29ceb4c551b1b5582e27747b855bbfaa73fa11914fe0df028dc581f # debian:bookworm-slim@sha256:b1211f6d19afd012477bd34fdcabb6b663d680e0f4b0537da6e6b0fd057a3ec3 diff --git a/pkg/testutil/nerdtest/requirements.go b/pkg/testutil/nerdtest/requirements.go index 3741b8f9aa5..d4af8490339 100644 --- a/pkg/testutil/nerdtest/requirements.go +++ b/pkg/testutil/nerdtest/requirements.go @@ -161,6 +161,24 @@ var Rootless = &test.Requirement{ }, } +// RootlessWithDetachNetNS marks a test as suitable only for rootless environment with detached netns support. +var RootlessWithDetachNetNS = &test.Requirement{ + Check: func(data test.Data, helpers test.Helpers) (ret bool, mess string) { + ns, err := rootlessutil.DetachedNetNS() + if err != nil { + return false, fmt.Sprintf("failed to check for detached netns: %+v", err) + } + if ns == "" { + return false, "detached netns is not supported" + } + return true, "detached netns is supported" + }, +} + +// RootlessWithoutDetachNetNS marks a test as suitable only for rootless environment without detached netns support. +// i.e., RootlessKit v1. +var RootlessWithoutDetachNetNS = require.All(Rootless, require.Not(RootlessWithDetachNetNS)) + // Rootful marks a test as suitable only for rootful env var Rootful = require.Not(Rootless) diff --git a/pkg/testutil/testutil_linux.go b/pkg/testutil/testutil_linux.go index d50d6e30489..3f7f2c85337 100644 --- a/pkg/testutil/testutil_linux.go +++ b/pkg/testutil/testutil_linux.go @@ -34,6 +34,7 @@ var ( FedoraESGZImage = GetTestImage("fedora_esgz") // eStargz FfmpegSociImage = GetTestImage("ffmpeg_soci") // SOCI UbuntuImage = GetTestImage("ubuntu") // Large enough for testing soci index creation + CoreDNSImage = GetTestImage("coredns") ) const (