Skip to content

Commit d5bed8b

Browse files
authored
Merge pull request containerd#3812 from coderbirju/add-hostconfig-inspect-response
Add HostConfig to `nerdctl inspect` response
2 parents 24bb81a + 37d9958 commit d5bed8b

File tree

7 files changed

+704
-15
lines changed

7 files changed

+704
-15
lines changed

cmd/nerdctl/container/container_inspect_linux_test.go

+236-2
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@ package container
1818

1919
import (
2020
"fmt"
21+
"os"
22+
"slices"
2123
"strings"
2224
"testing"
2325

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

29+
"github.com/containerd/nerdctl/v2/pkg/infoutil"
2730
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat"
2831
"github.com/containerd/nerdctl/v2/pkg/labels"
32+
"github.com/containerd/nerdctl/v2/pkg/rootlessutil"
2933
"github.com/containerd/nerdctl/v2/pkg/testutil"
3034
)
3135

@@ -68,13 +72,12 @@ func TestContainerInspectContainsMounts(t *testing.T) {
6872
testutil.NginxAlpineImage).AssertOK()
6973

7074
inspect := base.InspectContainer(testContainer)
71-
7275
// convert array to map to get by key of Destination
7376
actual := make(map[string]dockercompat.MountPoint)
7477
for i := range inspect.Mounts {
7578
actual[inspect.Mounts[i].Destination] = inspect.Mounts[i]
7679
}
77-
80+
t.Logf("actual in TestContainerInspectContainsMounts: %+v", actual)
7881
const localDriver = "local"
7982

8083
expected := []struct {
@@ -229,3 +232,234 @@ func TestContainerInspectState(t *testing.T) {
229232
}
230233

231234
}
235+
236+
func TestContainerInspectHostConfig(t *testing.T) {
237+
testContainer := testutil.Identifier(t)
238+
if rootlessutil.IsRootless() && infoutil.CgroupsVersion() == "1" {
239+
t.Skip("test skipped for rootless containers on cgroup v1")
240+
}
241+
242+
base := testutil.NewBase(t)
243+
defer base.Cmd("rm", "-f", testContainer).Run()
244+
245+
// Run a container with various HostConfig options
246+
base.Cmd("run", "-d", "--name", testContainer,
247+
"--cpuset-cpus", "0-1",
248+
"--cpuset-mems", "0",
249+
"--blkio-weight", "500",
250+
"--cpu-shares", "1024",
251+
"--cpu-quota", "100000",
252+
"--group-add", "1000",
253+
"--group-add", "2000",
254+
"--add-host", "host1:10.0.0.1",
255+
"--add-host", "host2:10.0.0.2",
256+
"--ipc", "host",
257+
"--memory", "512m",
258+
"--read-only",
259+
"--shm-size", "256m",
260+
"--uts", "host",
261+
"--sysctl", "net.core.somaxconn=1024",
262+
"--runtime", "io.containerd.runc.v2",
263+
testutil.AlpineImage, "sleep", "infinity").AssertOK()
264+
265+
inspect := base.InspectContainer(testContainer)
266+
267+
assert.Equal(t, "0-1", inspect.HostConfig.CPUSetCPUs)
268+
assert.Equal(t, "0", inspect.HostConfig.CPUSetMems)
269+
assert.Equal(t, uint16(500), inspect.HostConfig.BlkioWeight)
270+
assert.Equal(t, uint64(1024), inspect.HostConfig.CPUShares)
271+
assert.Equal(t, int64(100000), inspect.HostConfig.CPUQuota)
272+
assert.Assert(t, slices.Contains(inspect.HostConfig.GroupAdd, "1000"), "Expected '1000' to be in GroupAdd")
273+
assert.Assert(t, slices.Contains(inspect.HostConfig.GroupAdd, "2000"), "Expected '2000' to be in GroupAdd")
274+
expectedExtraHosts := []string{"host1:10.0.0.1", "host2:10.0.0.2"}
275+
assert.DeepEqual(t, expectedExtraHosts, inspect.HostConfig.ExtraHosts)
276+
assert.Equal(t, "host", inspect.HostConfig.IpcMode)
277+
assert.Equal(t, int64(536870912), inspect.HostConfig.Memory)
278+
assert.Equal(t, int64(1073741824), inspect.HostConfig.MemorySwap)
279+
assert.Equal(t, true, inspect.HostConfig.ReadonlyRootfs)
280+
assert.Equal(t, "host", inspect.HostConfig.UTSMode)
281+
assert.Equal(t, int64(268435456), inspect.HostConfig.ShmSize)
282+
}
283+
284+
func TestContainerInspectHostConfigDefaults(t *testing.T) {
285+
testContainer := testutil.Identifier(t)
286+
287+
base := testutil.NewBase(t)
288+
defer base.Cmd("rm", "-f", testContainer).Run()
289+
290+
var hc hostConfigValues
291+
292+
// Hostconfig default values differ with Docker.
293+
// This is because we directly retrieve the configured values instead of using preset defaults.
294+
if testutil.GetTarget() == testutil.Docker {
295+
hc.Driver = ""
296+
hc.GroupAddSize = 0
297+
hc.ShmSize = int64(67108864) // Docker default 64M
298+
hc.Runtime = "runc"
299+
} else {
300+
hc.GroupAddSize = 10
301+
hc.Driver = "json-file"
302+
hc.ShmSize = int64(0)
303+
hc.Runtime = "io.containerd.runc.v2"
304+
}
305+
306+
// Run a container without specifying HostConfig options
307+
base.Cmd("run", "-d", "--name", testContainer, testutil.AlpineImage, "sleep", "infinity").AssertOK()
308+
309+
inspect := base.InspectContainer(testContainer)
310+
t.Logf("HostConfig in TestContainerInspectHostConfigDefaults: %+v", inspect.HostConfig)
311+
assert.Equal(t, "", inspect.HostConfig.CPUSetCPUs)
312+
assert.Equal(t, "", inspect.HostConfig.CPUSetMems)
313+
assert.Equal(t, uint16(0), inspect.HostConfig.BlkioWeight)
314+
assert.Equal(t, uint64(0), inspect.HostConfig.CPUShares)
315+
assert.Equal(t, int64(0), inspect.HostConfig.CPUQuota)
316+
assert.Equal(t, hc.GroupAddSize, len(inspect.HostConfig.GroupAdd))
317+
assert.Equal(t, 0, len(inspect.HostConfig.ExtraHosts))
318+
assert.Equal(t, "private", inspect.HostConfig.IpcMode)
319+
assert.Equal(t, hc.Driver, inspect.HostConfig.LogConfig.Driver)
320+
assert.Equal(t, int64(0), inspect.HostConfig.Memory)
321+
assert.Equal(t, int64(0), inspect.HostConfig.MemorySwap)
322+
assert.Equal(t, bool(false), inspect.HostConfig.OomKillDisable)
323+
assert.Equal(t, bool(false), inspect.HostConfig.ReadonlyRootfs)
324+
assert.Equal(t, "", inspect.HostConfig.UTSMode)
325+
assert.Equal(t, hc.ShmSize, inspect.HostConfig.ShmSize)
326+
assert.Equal(t, hc.Runtime, inspect.HostConfig.Runtime)
327+
assert.Equal(t, 0, len(inspect.HostConfig.Sysctls))
328+
assert.Equal(t, 0, len(inspect.HostConfig.Devices))
329+
}
330+
331+
func TestContainerInspectHostConfigDNS(t *testing.T) {
332+
testContainer := testutil.Identifier(t)
333+
334+
base := testutil.NewBase(t)
335+
defer base.Cmd("rm", "-f", testContainer).Run()
336+
337+
// Run a container with DNS options
338+
base.Cmd("run", "-d", "--name", testContainer,
339+
"--dns", "8.8.8.8",
340+
"--dns", "1.1.1.1",
341+
"--dns-search", "example.com",
342+
"--dns-search", "test.local",
343+
"--dns-option", "ndots:5",
344+
"--dns-option", "timeout:3",
345+
testutil.AlpineImage, "sleep", "infinity").AssertOK()
346+
347+
inspect := base.InspectContainer(testContainer)
348+
349+
// Check DNS servers
350+
expectedDNSServers := []string{"8.8.8.8", "1.1.1.1"}
351+
assert.DeepEqual(t, expectedDNSServers, inspect.HostConfig.DNS)
352+
353+
// Check DNS search domains
354+
expectedDNSSearch := []string{"example.com", "test.local"}
355+
assert.DeepEqual(t, expectedDNSSearch, inspect.HostConfig.DNSSearch)
356+
357+
// Check DNS options
358+
expectedDNSOptions := []string{"ndots:5", "timeout:3"}
359+
assert.DeepEqual(t, expectedDNSOptions, inspect.HostConfig.DNSOptions)
360+
}
361+
362+
func TestContainerInspectHostConfigDNSDefaults(t *testing.T) {
363+
testContainer := testutil.Identifier(t)
364+
365+
base := testutil.NewBase(t)
366+
defer base.Cmd("rm", "-f", testContainer).Run()
367+
368+
// Run a container without specifying DNS options
369+
base.Cmd("run", "-d", "--name", testContainer, testutil.AlpineImage, "sleep", "infinity").AssertOK()
370+
371+
inspect := base.InspectContainer(testContainer)
372+
373+
// Check that DNS settings are empty by default
374+
assert.Equal(t, 0, len(inspect.HostConfig.DNS))
375+
assert.Equal(t, 0, len(inspect.HostConfig.DNSSearch))
376+
assert.Equal(t, 0, len(inspect.HostConfig.DNSOptions))
377+
}
378+
379+
func TestContainerInspectHostConfigPID(t *testing.T) {
380+
testContainer1 := testutil.Identifier(t) + "-container1"
381+
testContainer2 := testutil.Identifier(t) + "-container2"
382+
383+
base := testutil.NewBase(t)
384+
defer base.Cmd("rm", "-f", testContainer1, testContainer2).Run()
385+
386+
// Run the first container
387+
base.Cmd("run", "-d", "--name", testContainer1, testutil.AlpineImage, "sleep", "infinity").AssertOK()
388+
389+
containerID1 := strings.TrimSpace(base.Cmd("inspect", "-f", "{{.Id}}", testContainer1).Out())
390+
391+
var hc hostConfigValues
392+
393+
if testutil.GetTarget() == testutil.Docker {
394+
hc.PidMode = "container:" + containerID1
395+
} else {
396+
hc.PidMode = containerID1
397+
}
398+
399+
base.Cmd("run", "-d", "--name", testContainer2,
400+
"--pid", fmt.Sprintf("container:%s", testContainer1),
401+
testutil.AlpineImage, "sleep", "infinity").AssertOK()
402+
403+
inspect := base.InspectContainer(testContainer2)
404+
405+
assert.Equal(t, hc.PidMode, inspect.HostConfig.PidMode)
406+
407+
}
408+
409+
func TestContainerInspectHostConfigPIDDefaults(t *testing.T) {
410+
testContainer := testutil.Identifier(t)
411+
412+
base := testutil.NewBase(t)
413+
defer base.Cmd("rm", "-f", testContainer).Run()
414+
415+
base.Cmd("run", "-d", "--name", testContainer, testutil.AlpineImage, "sleep", "infinity").AssertOK()
416+
417+
inspect := base.InspectContainer(testContainer)
418+
419+
assert.Equal(t, "", inspect.HostConfig.PidMode)
420+
}
421+
422+
func TestContainerInspectDevices(t *testing.T) {
423+
testContainer := testutil.Identifier(t)
424+
425+
base := testutil.NewBase(t)
426+
defer base.Cmd("rm", "-f", testContainer).Run()
427+
428+
if rootlessutil.IsRootless() && infoutil.CgroupsVersion() == "1" {
429+
t.Skip("test skipped for rootless containers on cgroup v1")
430+
}
431+
432+
// Create a temporary directory
433+
dir, err := os.MkdirTemp(t.TempDir(), "device-dir")
434+
if err != nil {
435+
t.Fatal(err)
436+
}
437+
438+
if testutil.GetTarget() == testutil.Docker {
439+
dir = "/dev/zero"
440+
}
441+
442+
// Run the container with the directory mapped as a device
443+
base.Cmd("run", "-d", "--name", testContainer,
444+
"--device", dir+":/dev/xvda",
445+
testutil.AlpineImage, "sleep", "infinity").AssertOK()
446+
447+
inspect := base.InspectContainer(testContainer)
448+
449+
expectedDevices := []dockercompat.DeviceMapping{
450+
{
451+
PathOnHost: dir,
452+
PathInContainer: "/dev/xvda",
453+
CgroupPermissions: "rwm",
454+
},
455+
}
456+
assert.DeepEqual(t, expectedDevices, inspect.HostConfig.Devices)
457+
}
458+
459+
type hostConfigValues struct {
460+
Driver string
461+
ShmSize int64
462+
PidMode string
463+
GroupAddSize int
464+
Runtime string
465+
}

0 commit comments

Comments
 (0)