Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HostConfig to nerdctl inspect response #3812

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 242 additions & 2 deletions cmd/nerdctl/container/container_inspect_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ package container

import (
"fmt"
"os"
"strings"
"testing"

"github.com/docker/go-connections/nat"
"gotest.tools/v3/assert"

"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"
)

Expand Down Expand Up @@ -68,13 +71,12 @@ func TestContainerInspectContainsMounts(t *testing.T) {
testutil.NginxAlpineImage).AssertOK()

inspect := base.InspectContainer(testContainer)

// convert array to map to get by key of Destination
actual := make(map[string]dockercompat.MountPoint)
for i := range inspect.Mounts {
actual[inspect.Mounts[i].Destination] = inspect.Mounts[i]
}

t.Logf("actual in TestContainerInspectContainsMounts: %+v", actual)
const localDriver = "local"

expected := []struct {
Expand Down Expand Up @@ -229,3 +231,241 @@ func TestContainerInspectState(t *testing.T) {
}

}

func TestContainerInspectHostConfig(t *testing.T) {
testContainer := testutil.Identifier(t)
if rootlessutil.IsRootless() && infoutil.CgroupsVersion() == "1" {
t.Skip("test skipped for rootless containers on cgroup v1")
}

base := testutil.NewBase(t)
defer base.Cmd("rm", "-f", testContainer).Run()

// Run a container with various HostConfig options
base.Cmd("run", "-d", "--name", testContainer,
"--cpuset-cpus", "0-1",
"--cpuset-mems", "0",
"--blkio-weight", "500",
"--cpu-shares", "1024",
"--cpu-quota", "100000",
"--group-add", "1000",
"--group-add", "2000",
"--add-host", "host1:10.0.0.1",
"--add-host", "host2:10.0.0.2",
"--ipc", "host",
"--memory", "512m",
"--read-only",
"--shm-size", "256m",
"--uts", "host",
"--sysctl", "net.core.somaxconn=1024",
"--runtime", "io.containerd.runc.v2",
testutil.AlpineImage, "sleep", "infinity").AssertOK()

inspect := base.InspectContainer(testContainer)

assert.Equal(t, "0-1", inspect.HostConfig.CPUSetCPUs)
assert.Equal(t, "0", inspect.HostConfig.CPUSetMems)
assert.Equal(t, uint16(500), inspect.HostConfig.BlkioWeight)
assert.Equal(t, uint64(1024), inspect.HostConfig.CPUShares)
assert.Equal(t, int64(100000), inspect.HostConfig.CPUQuota)
assert.Assert(t, contains(inspect.HostConfig.GroupAdd, "1000"), "Expected '1000' to be in GroupAdd")
assert.Assert(t, contains(inspect.HostConfig.GroupAdd, "2000"), "Expected '2000' to be in GroupAdd")
expectedExtraHosts := []string{"host1:10.0.0.1", "host2:10.0.0.2"}
assert.DeepEqual(t, expectedExtraHosts, inspect.HostConfig.ExtraHosts)
assert.Equal(t, "host", inspect.HostConfig.IpcMode)
assert.Equal(t, int64(536870912), inspect.HostConfig.Memory)
assert.Equal(t, int64(1073741824), inspect.HostConfig.MemorySwap)
assert.Equal(t, true, inspect.HostConfig.ReadonlyRootfs)
assert.Equal(t, "host", inspect.HostConfig.UTSMode)
assert.Equal(t, int64(268435456), inspect.HostConfig.ShmSize)
}

func TestContainerInspectHostConfigDefaults(t *testing.T) {
testContainer := testutil.Identifier(t)

base := testutil.NewBase(t)
defer base.Cmd("rm", "-f", testContainer).Run()

var hc hostConfigValues

if testutil.GetTarget() == testutil.Docker {
hc.Driver = ""
hc.GroupAddSize = 0
hc.ShmSize = int64(67108864)
hc.Runtime = "runc"
} else {
hc.GroupAddSize = 10
hc.Driver = "json-file"
hc.ShmSize = int64(0)
hc.Runtime = "io.containerd.runc.v2"
}

// Run a container without specifying HostConfig options
base.Cmd("run", "-d", "--name", testContainer, testutil.AlpineImage, "sleep", "infinity").AssertOK()

inspect := base.InspectContainer(testContainer)
t.Logf("HostConfig in TestContainerInspectHostConfigDefaults: %+v", inspect.HostConfig)
assert.Equal(t, "", inspect.HostConfig.CPUSetCPUs)
assert.Equal(t, "", inspect.HostConfig.CPUSetMems)
assert.Equal(t, uint16(0), inspect.HostConfig.BlkioWeight)
assert.Equal(t, uint64(0), inspect.HostConfig.CPUShares)
assert.Equal(t, int64(0), inspect.HostConfig.CPUQuota)
assert.Equal(t, hc.GroupAddSize, len(inspect.HostConfig.GroupAdd))
assert.Equal(t, 0, len(inspect.HostConfig.ExtraHosts))
assert.Equal(t, "private", inspect.HostConfig.IpcMode)
assert.Equal(t, hc.Driver, inspect.HostConfig.LogConfig.Driver)
assert.Equal(t, int64(0), inspect.HostConfig.Memory)
assert.Equal(t, int64(0), inspect.HostConfig.MemorySwap)
assert.Equal(t, bool(false), inspect.HostConfig.OomKillDisable)
assert.Equal(t, bool(false), inspect.HostConfig.ReadonlyRootfs)
assert.Equal(t, "", inspect.HostConfig.UTSMode)
assert.Equal(t, hc.ShmSize, inspect.HostConfig.ShmSize)
assert.Equal(t, hc.Runtime, inspect.HostConfig.Runtime)
assert.Equal(t, 0, len(inspect.HostConfig.Sysctls))
assert.Equal(t, 0, len(inspect.HostConfig.Devices))
}

func TestContainerInspectHostConfigDNS(t *testing.T) {
testContainer := testutil.Identifier(t)

base := testutil.NewBase(t)
defer base.Cmd("rm", "-f", testContainer).Run()

// Run a container with DNS options
base.Cmd("run", "-d", "--name", testContainer,
"--dns", "8.8.8.8",
"--dns", "1.1.1.1",
"--dns-search", "example.com",
"--dns-search", "test.local",
"--dns-option", "ndots:5",
"--dns-option", "timeout:3",
testutil.AlpineImage, "sleep", "infinity").AssertOK()

inspect := base.InspectContainer(testContainer)

// Check DNS servers
expectedDNSServers := []string{"8.8.8.8", "1.1.1.1"}
assert.DeepEqual(t, expectedDNSServers, inspect.HostConfig.DNS)

// Check DNS search domains
expectedDNSSearch := []string{"example.com", "test.local"}
assert.DeepEqual(t, expectedDNSSearch, inspect.HostConfig.DNSSearch)

// Check DNS options
expectedDNSOptions := []string{"ndots:5", "timeout:3"}
assert.DeepEqual(t, expectedDNSOptions, inspect.HostConfig.DNSOptions)
}

func TestContainerInspectHostConfigDNSDefaults(t *testing.T) {
testContainer := testutil.Identifier(t)

base := testutil.NewBase(t)
defer base.Cmd("rm", "-f", testContainer).Run()

// Run a container without specifying DNS options
base.Cmd("run", "-d", "--name", testContainer, testutil.AlpineImage, "sleep", "infinity").AssertOK()

inspect := base.InspectContainer(testContainer)

// Check that DNS settings are empty by default
assert.Equal(t, 0, len(inspect.HostConfig.DNS))
assert.Equal(t, 0, len(inspect.HostConfig.DNSSearch))
assert.Equal(t, 0, len(inspect.HostConfig.DNSOptions))
}

func TestContainerInspectHostConfigPID(t *testing.T) {
testContainer1 := testutil.Identifier(t) + "-container1"
testContainer2 := testutil.Identifier(t) + "-container2"

base := testutil.NewBase(t)
defer base.Cmd("rm", "-f", testContainer1, testContainer2).Run()

// Run the first container
base.Cmd("run", "-d", "--name", testContainer1, testutil.AlpineImage, "sleep", "infinity").AssertOK()

containerID1 := strings.TrimSpace(base.Cmd("inspect", "-f", "{{.Id}}", testContainer1).Out())

var hc hostConfigValues

if testutil.GetTarget() == testutil.Docker {
hc.PidMode = "container:" + containerID1
} else {
hc.PidMode = containerID1
}

base.Cmd("run", "-d", "--name", testContainer2,
"--pid", fmt.Sprintf("container:%s", testContainer1),
testutil.AlpineImage, "sleep", "infinity").AssertOK()

inspect := base.InspectContainer(testContainer2)

assert.Equal(t, hc.PidMode, inspect.HostConfig.PidMode)

}

func TestContainerInspectHostConfigPIDDefaults(t *testing.T) {
testContainer := testutil.Identifier(t)

base := testutil.NewBase(t)
defer base.Cmd("rm", "-f", testContainer).Run()

base.Cmd("run", "-d", "--name", testContainer, testutil.AlpineImage, "sleep", "infinity").AssertOK()

inspect := base.InspectContainer(testContainer)

assert.Equal(t, "", inspect.HostConfig.PidMode)
}

func TestContainerInspectDevices(t *testing.T) {
testContainer := testutil.Identifier(t)

base := testutil.NewBase(t)
defer base.Cmd("rm", "-f", testContainer).Run()

if rootlessutil.IsRootless() && infoutil.CgroupsVersion() == "1" {
t.Skip("test skipped for rootless containers on cgroup v1")
}

// Create a temporary directory
dir, err := os.MkdirTemp(t.TempDir(), "device-dir")
if err != nil {
t.Fatal(err)
}

if testutil.GetTarget() == testutil.Docker {
dir = "/dev/zero"
}

// Run the container with the directory mapped as a device
base.Cmd("run", "-d", "--name", testContainer,
"--device", dir+":/dev/xvda",
testutil.AlpineImage, "sleep", "infinity").AssertOK()

inspect := base.InspectContainer(testContainer)

expectedDevices := []dockercompat.DeviceMapping{
{
PathOnHost: dir,
PathInContainer: "/dev/xvda",
CgroupPermissions: "rwm",
},
}
assert.DeepEqual(t, expectedDevices, inspect.HostConfig.Devices)
}

func contains(slice []string, item string) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}

type hostConfigValues struct {
Driver string
ShmSize int64
PidMode string
GroupAddSize int
Runtime string
}
Loading
Loading