Skip to content

Add hostconfig inspect response dirty2 #9

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

Open
wants to merge 17 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
200 changes: 198 additions & 2 deletions cmd/nerdctl/container/container_inspect_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package container

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

Expand Down Expand Up @@ -68,13 +69,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 +229,199 @@ func TestContainerInspectState(t *testing.T) {
}

}

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

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, "json-file", inspect.HostConfig.LogConfig.Driver)
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()

// 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, 10, len(inspect.HostConfig.GroupAdd))
assert.Equal(t, 0, len(inspect.HostConfig.ExtraHosts))
assert.Equal(t, "private", inspect.HostConfig.IpcMode)
assert.Equal(t, "json-file", 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, int64(0), inspect.HostConfig.ShmSize)
assert.Equal(t, "io.containerd.runc.v2", 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())

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

inspect := base.InspectContainer(testContainer2)

assert.Equal(t, containerID1, 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()

dir, err := os.MkdirTemp(t.TempDir(), "rw")
if err != nil {
t.Fatal(err)
}

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
}
88 changes: 78 additions & 10 deletions pkg/cmd/container/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func Create(ctx context.Context, client *containerd.Client, args []string, netMa
if err := writeCIDFile(options.CidFile, id); err != nil {
return nil, nil, err
}
internalLabels.cidFile = options.CidFile
}
dataStore, err := clientutil.DataStore(options.GOptions.DataRoot, options.GOptions.Address)
if err != nil {
Expand Down Expand Up @@ -222,6 +223,10 @@ func Create(ctx context.Context, client *containerd.Client, args []string, netMa
return nil, generateRemoveStateDirFunc(ctx, id, internalLabels), err
}
internalLabels.logURI = logConfig.LogURI
internalLabels.logConfig = logConfig
if logConfig.Driver == "" && logConfig.Address == options.GOptions.Address {
internalLabels.logConfig.Driver = "json-file"
}

restartOpts, err := generateRestartOpts(ctx, client, options.Restart, logConfig.LogURI, options.InRun)
if err != nil {
Expand Down Expand Up @@ -268,6 +273,7 @@ func Create(ctx context.Context, client *containerd.Client, args []string, netMa
}
opts = append(opts, uOpts...)
gOpts, err := generateGroupsOpts(options.GroupAdd)
internalLabels.groupAdd = options.GroupAdd
if err != nil {
return nil, generateRemoveOrphanedDirsFunc(ctx, id, dataStore, internalLabels), err
}
Expand Down Expand Up @@ -325,6 +331,8 @@ func Create(ctx context.Context, client *containerd.Client, args []string, netMa

internalLabels.rm = containerutil.EncodeContainerRmOptLabel(options.Rm)

internalLabels.blkioWeight = options.BlkioWeight

// TODO: abolish internal labels and only use annotations
ilOpt, err := withInternalLabels(internalLabels)
if err != nil {
Expand Down Expand Up @@ -616,21 +624,25 @@ func withStop(stopSignal string, stopTimeout int, ensuredImage *imgutil.EnsuredI

type internalLabels struct {
// labels from cmd options
namespace string
platform string
extraHosts []string
pidFile string
namespace string
platform string
extraHosts []string
pidFile string
blkioWeight uint16
// labels from cmd options or automatically set
name string
hostname string
// automatically generated
stateDir string
// network
networks []string
ipAddress string
ip6Address string
ports []cni.PortMapping
macAddress string
networks []string
ipAddress string
ip6Address string
ports []cni.PortMapping
macAddress string
dnsServers []string
dnsSearchDomains []string
dnsResolvConfOptions []string
// volume
mountPoints []*mountutil.Processed
anonVolumes []string
Expand All @@ -641,12 +653,24 @@ type internalLabels struct {
// log
logURI string
// a label to check whether the --rm option is specified.
rm string
rm string
logConfig logging.LogConfig

// a label to chek if --cidfile is set
cidFile string

// label to check if --group-add is set
groupAdd []string

// label for device mapping set by the --device flag
deviceMapping []dockercompat.DeviceMapping
}

// WithInternalLabels sets the internal labels for a container.
func withInternalLabels(internalLabels internalLabels) (containerd.NewContainerOpts, error) {
m := make(map[string]string)
var hostConfigLabel dockercompat.HostConfigLabel
var dnsSettings dockercompat.DNSSettings
m[labels.Namespace] = internalLabels.namespace
if internalLabels.name != "" {
m[labels.Name] = internalLabels.name
Expand All @@ -672,6 +696,11 @@ func withInternalLabels(internalLabels internalLabels) (containerd.NewContainerO
}
if internalLabels.logURI != "" {
m[labels.LogURI] = internalLabels.logURI
logConfigJSON, err := json.Marshal(internalLabels.logConfig)
if err != nil {
return nil, err
}
m[labels.LogConfig] = string(logConfigJSON)
}
if len(internalLabels.anonVolumes) > 0 {
anonVolumeJSON, err := json.Marshal(internalLabels.anonVolumes)
Expand Down Expand Up @@ -723,6 +752,42 @@ func withInternalLabels(internalLabels internalLabels) (containerd.NewContainerO
m[labels.ContainerAutoRemove] = internalLabels.rm
}

if internalLabels.blkioWeight > 0 {
hostConfigLabel.BlkioWeight = internalLabels.blkioWeight
}

if internalLabels.cidFile != "" {
hostConfigLabel.CidFile = internalLabels.cidFile
}

if len(internalLabels.dnsServers) > 0 {
dnsSettings.DNSServers = internalLabels.dnsServers
}

if len(internalLabels.dnsSearchDomains) > 0 {
dnsSettings.DNSSearchDomains = internalLabels.dnsSearchDomains
}

if len(internalLabels.dnsResolvConfOptions) > 0 {
dnsSettings.DNSResolvConfOptions = internalLabels.dnsResolvConfOptions
}

if len(internalLabels.deviceMapping) > 0 {
hostConfigLabel.Devices = append(hostConfigLabel.Devices, internalLabels.deviceMapping...)
}

hostConfigJSON, err := json.Marshal(hostConfigLabel)
if err != nil {
return nil, err
}
m[labels.HostConfigLabel] = string(hostConfigJSON)

dnsSettingsJSON, err := json.Marshal(dnsSettings)
if err != nil {
return nil, err
}
m[labels.DNSSetting] = string(dnsSettingsJSON)

return containerd.WithAdditionalContainerLabels(m), nil
}

Expand All @@ -734,6 +799,9 @@ func (il *internalLabels) loadNetOpts(opts types.NetworkOptions) {
il.ip6Address = opts.IP6Address
il.networks = opts.NetworkSlice
il.macAddress = opts.MACAddress
il.dnsServers = opts.DNSServers
il.dnsSearchDomains = opts.DNSSearchDomains
il.dnsResolvConfOptions = opts.DNSResolvConfOptions
}

func dockercompatMounts(mountPoints []*mountutil.Processed) []dockercompat.MountPoint {
Expand Down
Loading
Loading