@@ -18,14 +18,18 @@ package container
1818
1919import (
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