From dc79e90541ed85d988e9481db561a00f8b960afc Mon Sep 17 00:00:00 2001 From: Shubharanshu Mahapatra Date: Thu, 13 Mar 2025 17:29:08 -0700 Subject: [PATCH 1/2] add env to inspect Signed-off-by: Shubharanshu Mahapatra --- pkg/inspecttypes/dockercompat/dockercompat.go | 5 +++++ pkg/inspecttypes/dockercompat/dockercompat_test.go | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/inspecttypes/dockercompat/dockercompat.go b/pkg/inspecttypes/dockercompat/dockercompat.go index 568bf6fcb40..7c6113e64bf 100644 --- a/pkg/inspecttypes/dockercompat/dockercompat.go +++ b/pkg/inspecttypes/dockercompat/dockercompat.go @@ -561,6 +561,11 @@ func ContainerFromNative(n *native.Container) (*Container, error) { return nil, fmt.Errorf("failed to get blkio settings: %w", err) } + if n.Spec != nil { + if spec, ok := n.Spec.(*specs.Spec); ok && spec.Process != nil { + c.Config.Env = spec.Process.Env + } + } return c, nil } diff --git a/pkg/inspecttypes/dockercompat/dockercompat_test.go b/pkg/inspecttypes/dockercompat/dockercompat_test.go index ddb621b9f39..b8ff88a4791 100644 --- a/pkg/inspecttypes/dockercompat/dockercompat_test.go +++ b/pkg/inspecttypes/dockercompat/dockercompat_test.go @@ -57,7 +57,11 @@ func TestContainerFromNative(t *testing.T) { "nerdctl/hostname": "host1", }, }, - Spec: &specs.Spec{}, + Spec: &specs.Spec{ + Process: &specs.Process{ + Env: []string{"/some/path"}, + }, + }, Process: &native.Process{ Pid: 10000, Status: containerd.Status{ @@ -103,6 +107,7 @@ func TestContainerFromNative(t *testing.T) { "nerdctl/hostname": "host1", }, Hostname: "host1", + Env: []string{"/some/path"}, }, NetworkSettings: &NetworkSettings{ Ports: &nat.PortMap{}, From bbf2ab73b541107217d6190d957f90d534fdcc1f Mon Sep 17 00:00:00 2001 From: Shubharanshu Mahapatra Date: Fri, 14 Mar 2025 10:53:13 -0700 Subject: [PATCH 2/2] add user to inspect Signed-off-by: Shubharanshu Mahapatra --- .../container/container_inspect_linux_test.go | 34 +++++++++++++++++++ pkg/cmd/container/create.go | 16 +++++++++ pkg/inspecttypes/dockercompat/dockercompat.go | 5 +++ .../dockercompat/dockercompat_test.go | 3 ++ pkg/labels/labels.go | 3 ++ 5 files changed, 61 insertions(+) diff --git a/cmd/nerdctl/container/container_inspect_linux_test.go b/cmd/nerdctl/container/container_inspect_linux_test.go index 610c17e45f2..3617f37e273 100644 --- a/cmd/nerdctl/container/container_inspect_linux_test.go +++ b/cmd/nerdctl/container/container_inspect_linux_test.go @@ -20,6 +20,7 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "slices" "strings" "testing" @@ -27,11 +28,14 @@ import ( "github.com/docker/go-connections/nat" "gotest.tools/v3/assert" + "github.com/containerd/nerdctl/mod/tigron/expect" + "github.com/containerd/nerdctl/mod/tigron/test" "github.com/containerd/nerdctl/v2/pkg/infoutil" "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" "github.com/containerd/nerdctl/v2/pkg/labels" "github.com/containerd/nerdctl/v2/pkg/rootlessutil" "github.com/containerd/nerdctl/v2/pkg/testutil" + "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" ) func TestContainerInspectContainsPortConfig(t *testing.T) { @@ -514,6 +518,36 @@ func TestContainerInspectBlkioSettings(t *testing.T) { assert.Equal(t, uint64(2000), inspect.HostConfig.BlkioDeviceWriteIOps[0].Rate) } +func TestContainerInspectUser(t *testing.T) { + nerdtest.Setup() + testCase := &test.Case{ + Description: "Container inspect contains User", + Require: nerdtest.Build, + Setup: func(data test.Data, helpers test.Helpers) { + dockerfile := fmt.Sprintf(` +FROM %s +RUN groupadd -r test && useradd -r -g test test +USER test +`, testutil.UbuntuImage) + + err := os.WriteFile(filepath.Join(data.TempDir(), "Dockerfile"), []byte(dockerfile), 0o600) + assert.NilError(helpers.T(), err) + + helpers.Ensure("build", "-t", data.Identifier(), data.TempDir()) + helpers.Ensure("create", "--name", data.Identifier(), "--user", "test", data.Identifier()) + }, + Cleanup: func(data test.Data, helpers test.Helpers) { + helpers.Anyhow("rm", "-f", data.Identifier()) + }, + Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { + return helpers.Command("inspect", "--format", "{{.Config.User}}", data.Identifier()) + }, + Expected: test.Expects(0, nil, expect.Equals("test\n")), + } + + testCase.Run(t) +} + type hostConfigValues struct { Driver string ShmSize int64 diff --git a/pkg/cmd/container/create.go b/pkg/cmd/container/create.go index 7127e364302..61e7686aebd 100644 --- a/pkg/cmd/container/create.go +++ b/pkg/cmd/container/create.go @@ -179,6 +179,15 @@ func Create(ctx context.Context, client *containerd.Client, args []string, netMa } } + if ensuredImage != nil && ensuredImage.ImageConfig.User != "" { + internalLabels.user = ensuredImage.ImageConfig.User + } + + // Override it if User is passed + if options.User != "" { + internalLabels.user = options.User + } + rootfsOpts, rootfsCOpts, err := generateRootfsOpts(args, id, ensuredImage, options) if err != nil { return nil, generateRemoveStateDirFunc(ctx, id, internalLabels), err @@ -271,6 +280,7 @@ func Create(ctx context.Context, client *containerd.Client, args []string, netMa if err != nil { return nil, generateRemoveOrphanedDirsFunc(ctx, id, dataStore, internalLabels), err } + opts = append(opts, uOpts...) gOpts, err := generateGroupsOpts(options.GroupAdd) internalLabels.groupAdd = options.GroupAdd @@ -662,6 +672,8 @@ type internalLabels struct { // label for device mapping set by the --device flag deviceMapping []dockercompat.DeviceMapping + + user string } // WithInternalLabels sets the internal labels for a container. @@ -783,6 +795,10 @@ func withInternalLabels(internalLabels internalLabels) (containerd.NewContainerO } m[labels.DNSSetting] = string(dnsSettingsJSON) + if internalLabels.user != "" { + m[labels.User] = internalLabels.user + } + return containerd.WithAdditionalContainerLabels(m), nil } diff --git a/pkg/inspecttypes/dockercompat/dockercompat.go b/pkg/inspecttypes/dockercompat/dockercompat.go index 7c6113e64bf..4605de3d1e7 100644 --- a/pkg/inspecttypes/dockercompat/dockercompat.go +++ b/pkg/inspecttypes/dockercompat/dockercompat.go @@ -566,6 +566,11 @@ func ContainerFromNative(n *native.Container) (*Container, error) { c.Config.Env = spec.Process.Env } } + + if n.Labels[labels.User] != "" { + c.Config.User = n.Labels[labels.User] + } + return c, nil } diff --git a/pkg/inspecttypes/dockercompat/dockercompat_test.go b/pkg/inspecttypes/dockercompat/dockercompat_test.go index b8ff88a4791..4966ce89604 100644 --- a/pkg/inspecttypes/dockercompat/dockercompat_test.go +++ b/pkg/inspecttypes/dockercompat/dockercompat_test.go @@ -55,6 +55,7 @@ func TestContainerFromNative(t *testing.T) { "nerdctl/mounts": "[{\"Type\":\"bind\",\"Source\":\"/mnt/foo\",\"Destination\":\"/mnt/foo\",\"Mode\":\"rshared,rw\",\"RW\":true,\"Propagation\":\"rshared\"}]", "nerdctl/state-dir": tempStateDir, "nerdctl/hostname": "host1", + "nerdctl/user": "test-user", }, }, Spec: &specs.Spec{ @@ -105,9 +106,11 @@ func TestContainerFromNative(t *testing.T) { "nerdctl/mounts": "[{\"Type\":\"bind\",\"Source\":\"/mnt/foo\",\"Destination\":\"/mnt/foo\",\"Mode\":\"rshared,rw\",\"RW\":true,\"Propagation\":\"rshared\"}]", "nerdctl/state-dir": tempStateDir, "nerdctl/hostname": "host1", + "nerdctl/user": "test-user", }, Hostname: "host1", Env: []string{"/some/path"}, + User: "test-user", }, NetworkSettings: &NetworkSettings{ Ports: &nat.PortMap{}, diff --git a/pkg/labels/labels.go b/pkg/labels/labels.go index 0376497ad9e..9356ad03a68 100644 --- a/pkg/labels/labels.go +++ b/pkg/labels/labels.go @@ -115,4 +115,7 @@ const ( // DNSSettings sets the dockercompat DNS config values DNSSetting = Prefix + "dns" + + // User is the username of the container + User = Prefix + "user" )