2021-08-23 13:14:53 +00:00
|
|
|
//go:build !windows
|
2015-06-03 19:01:53 +00:00
|
|
|
|
2018-02-05 21:05:59 +00:00
|
|
|
package daemon // import "github.com/docker/docker/daemon"
|
2015-06-03 19:01:53 +00:00
|
|
|
|
|
|
|
import (
|
2017-08-01 19:04:37 +00:00
|
|
|
"errors"
|
2015-08-06 00:15:14 +00:00
|
|
|
"os"
|
2019-05-14 07:21:55 +00:00
|
|
|
"path/filepath"
|
2015-06-03 19:01:53 +00:00
|
|
|
"testing"
|
|
|
|
|
2019-05-14 07:21:55 +00:00
|
|
|
"github.com/docker/docker/api/types/blkiodev"
|
2016-09-06 18:18:12 +00:00
|
|
|
containertypes "github.com/docker/docker/api/types/container"
|
2016-02-02 02:26:47 +00:00
|
|
|
"github.com/docker/docker/container"
|
2017-01-23 11:23:07 +00:00
|
|
|
"github.com/docker/docker/daemon/config"
|
2018-12-17 10:23:41 +00:00
|
|
|
"github.com/docker/docker/pkg/sysinfo"
|
2023-04-14 07:27:20 +00:00
|
|
|
"github.com/opencontainers/selinux/go-selinux"
|
2019-05-14 07:21:55 +00:00
|
|
|
"golang.org/x/sys/unix"
|
2020-02-07 13:39:24 +00:00
|
|
|
"gotest.tools/v3/assert"
|
|
|
|
is "gotest.tools/v3/assert/cmp"
|
2015-06-03 19:01:53 +00:00
|
|
|
)
|
|
|
|
|
2017-08-01 19:04:37 +00:00
|
|
|
type fakeContainerGetter struct {
|
|
|
|
containers map[string]*container.Container
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeContainerGetter) GetContainer(cid string) (*container.Container, error) {
|
2019-08-09 12:10:07 +00:00
|
|
|
ctr, ok := f.containers[cid]
|
2017-08-01 19:04:37 +00:00
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("container not found")
|
|
|
|
}
|
2019-08-09 12:10:07 +00:00
|
|
|
return ctr, nil
|
2017-08-01 19:04:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Unix test as uses settings which are not available on Windows
|
|
|
|
func TestAdjustSharedNamespaceContainerName(t *testing.T) {
|
|
|
|
fakeID := "abcdef1234567890"
|
|
|
|
hostConfig := &containertypes.HostConfig{
|
|
|
|
IpcMode: containertypes.IpcMode("container:base"),
|
|
|
|
PidMode: containertypes.PidMode("container:base"),
|
|
|
|
NetworkMode: containertypes.NetworkMode("container:base"),
|
|
|
|
}
|
|
|
|
containerStore := &fakeContainerGetter{}
|
|
|
|
containerStore.containers = make(map[string]*container.Container)
|
|
|
|
containerStore.containers["base"] = &container.Container{
|
|
|
|
ID: fakeID,
|
|
|
|
}
|
|
|
|
|
|
|
|
adaptSharedNamespaceContainer(containerStore, hostConfig)
|
|
|
|
if hostConfig.IpcMode != containertypes.IpcMode("container:"+fakeID) {
|
|
|
|
t.Errorf("Expected IpcMode to be container:%s", fakeID)
|
|
|
|
}
|
|
|
|
if hostConfig.PidMode != containertypes.PidMode("container:"+fakeID) {
|
|
|
|
t.Errorf("Expected PidMode to be container:%s", fakeID)
|
|
|
|
}
|
|
|
|
if hostConfig.NetworkMode != containertypes.NetworkMode("container:"+fakeID) {
|
|
|
|
t.Errorf("Expected NetworkMode to be container:%s", fakeID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-02 02:26:47 +00:00
|
|
|
// Unix test as uses settings which are not available on Windows
|
2015-08-06 00:15:14 +00:00
|
|
|
func TestAdjustCPUShares(t *testing.T) {
|
2021-08-24 10:10:50 +00:00
|
|
|
tmp, err := os.MkdirTemp("", "docker-daemon-unix-test-")
|
2015-08-06 00:15:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmp)
|
|
|
|
daemon := &Daemon{
|
|
|
|
repository: tmp,
|
|
|
|
root: tmp,
|
|
|
|
}
|
2022-08-17 21:13:49 +00:00
|
|
|
cfg := &config.Config{}
|
2019-10-17 00:47:37 +00:00
|
|
|
muteLogs()
|
2015-08-06 00:15:14 +00:00
|
|
|
|
2016-02-02 02:26:47 +00:00
|
|
|
hostConfig := &containertypes.HostConfig{
|
|
|
|
Resources: containertypes.Resources{CPUShares: linuxMinCPUShares - 1},
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
2022-08-17 21:13:49 +00:00
|
|
|
daemon.adaptContainerSettings(cfg, hostConfig, true)
|
2015-07-21 05:15:44 +00:00
|
|
|
if hostConfig.CPUShares != linuxMinCPUShares {
|
|
|
|
t.Errorf("Expected CPUShares to be %d", linuxMinCPUShares)
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
|
|
|
|
2015-07-21 05:15:44 +00:00
|
|
|
hostConfig.CPUShares = linuxMaxCPUShares + 1
|
2022-08-17 21:13:49 +00:00
|
|
|
daemon.adaptContainerSettings(cfg, hostConfig, true)
|
2015-07-21 05:15:44 +00:00
|
|
|
if hostConfig.CPUShares != linuxMaxCPUShares {
|
|
|
|
t.Errorf("Expected CPUShares to be %d", linuxMaxCPUShares)
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
|
|
|
|
2015-07-25 09:11:45 +00:00
|
|
|
hostConfig.CPUShares = 0
|
2022-08-17 21:13:49 +00:00
|
|
|
daemon.adaptContainerSettings(cfg, hostConfig, true)
|
2015-07-25 09:11:45 +00:00
|
|
|
if hostConfig.CPUShares != 0 {
|
2015-07-21 05:15:44 +00:00
|
|
|
t.Error("Expected CPUShares to be unchanged")
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
|
|
|
|
2015-07-25 09:11:45 +00:00
|
|
|
hostConfig.CPUShares = 1024
|
2022-08-17 21:13:49 +00:00
|
|
|
daemon.adaptContainerSettings(cfg, hostConfig, true)
|
2015-07-25 09:11:45 +00:00
|
|
|
if hostConfig.CPUShares != 1024 {
|
2015-07-21 05:15:44 +00:00
|
|
|
t.Error("Expected CPUShares to be unchanged")
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-02 02:26:47 +00:00
|
|
|
// Unix test as uses settings which are not available on Windows
|
2015-07-21 05:15:44 +00:00
|
|
|
func TestAdjustCPUSharesNoAdjustment(t *testing.T) {
|
2021-08-24 10:10:50 +00:00
|
|
|
tmp, err := os.MkdirTemp("", "docker-daemon-unix-test-")
|
2015-08-06 00:15:14 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmp)
|
|
|
|
daemon := &Daemon{
|
|
|
|
repository: tmp,
|
|
|
|
root: tmp,
|
|
|
|
}
|
2022-08-17 21:13:49 +00:00
|
|
|
cfg := &config.Config{}
|
2015-08-06 00:15:14 +00:00
|
|
|
|
2016-02-02 02:26:47 +00:00
|
|
|
hostConfig := &containertypes.HostConfig{
|
|
|
|
Resources: containertypes.Resources{CPUShares: linuxMinCPUShares - 1},
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
2022-08-17 21:13:49 +00:00
|
|
|
daemon.adaptContainerSettings(cfg, hostConfig, false)
|
2015-07-21 05:15:44 +00:00
|
|
|
if hostConfig.CPUShares != linuxMinCPUShares-1 {
|
|
|
|
t.Errorf("Expected CPUShares to be %d", linuxMinCPUShares-1)
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
|
|
|
|
2015-07-21 05:15:44 +00:00
|
|
|
hostConfig.CPUShares = linuxMaxCPUShares + 1
|
2022-08-17 21:13:49 +00:00
|
|
|
daemon.adaptContainerSettings(cfg, hostConfig, false)
|
2015-07-21 05:15:44 +00:00
|
|
|
if hostConfig.CPUShares != linuxMaxCPUShares+1 {
|
|
|
|
t.Errorf("Expected CPUShares to be %d", linuxMaxCPUShares+1)
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
|
|
|
|
2015-07-25 09:11:45 +00:00
|
|
|
hostConfig.CPUShares = 0
|
2022-08-17 21:13:49 +00:00
|
|
|
daemon.adaptContainerSettings(cfg, hostConfig, false)
|
2015-07-25 09:11:45 +00:00
|
|
|
if hostConfig.CPUShares != 0 {
|
2015-07-21 05:15:44 +00:00
|
|
|
t.Error("Expected CPUShares to be unchanged")
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
|
|
|
|
2015-07-25 09:11:45 +00:00
|
|
|
hostConfig.CPUShares = 1024
|
2022-08-17 21:13:49 +00:00
|
|
|
daemon.adaptContainerSettings(cfg, hostConfig, false)
|
2015-07-25 09:11:45 +00:00
|
|
|
if hostConfig.CPUShares != 1024 {
|
2015-07-21 05:15:44 +00:00
|
|
|
t.Error("Expected CPUShares to be unchanged")
|
2015-06-03 19:01:53 +00:00
|
|
|
}
|
|
|
|
}
|
2016-02-02 02:26:47 +00:00
|
|
|
|
|
|
|
// Unix test as uses settings which are not available on Windows
|
2016-03-15 22:34:29 +00:00
|
|
|
func TestParseSecurityOptWithDeprecatedColon(t *testing.T) {
|
2023-04-14 07:27:20 +00:00
|
|
|
opts := &container.SecurityOptions{}
|
2019-08-09 12:10:07 +00:00
|
|
|
cfg := &containertypes.HostConfig{}
|
2016-02-02 02:26:47 +00:00
|
|
|
|
|
|
|
// test apparmor
|
2019-08-09 12:10:07 +00:00
|
|
|
cfg.SecurityOpt = []string{"apparmor=test_profile"}
|
2023-04-14 07:27:20 +00:00
|
|
|
if err := parseSecurityOpt(opts, cfg); err != nil {
|
2016-02-02 02:26:47 +00:00
|
|
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
|
|
}
|
2023-04-14 07:27:20 +00:00
|
|
|
if opts.AppArmorProfile != "test_profile" {
|
2023-07-05 10:13:09 +00:00
|
|
|
t.Fatalf(`Unexpected AppArmorProfile, expected: "test_profile", got %q`, opts.AppArmorProfile)
|
2016-02-02 02:26:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// test seccomp
|
|
|
|
sp := "/path/to/seccomp_test.json"
|
2019-08-09 12:10:07 +00:00
|
|
|
cfg.SecurityOpt = []string{"seccomp=" + sp}
|
2023-04-14 07:27:20 +00:00
|
|
|
if err := parseSecurityOpt(opts, cfg); err != nil {
|
2016-02-02 02:26:47 +00:00
|
|
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
|
|
}
|
2023-04-14 07:27:20 +00:00
|
|
|
if opts.SeccompProfile != sp {
|
|
|
|
t.Fatalf("Unexpected AppArmorProfile, expected: %q, got %q", sp, opts.SeccompProfile)
|
2016-02-02 02:26:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// test valid label
|
2019-08-09 12:10:07 +00:00
|
|
|
cfg.SecurityOpt = []string{"label=user:USER"}
|
2023-04-14 07:27:20 +00:00
|
|
|
if err := parseSecurityOpt(opts, cfg); err != nil {
|
2016-03-15 22:34:29 +00:00
|
|
|
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// test invalid label
|
2019-08-09 12:10:07 +00:00
|
|
|
cfg.SecurityOpt = []string{"label"}
|
2023-04-14 07:27:20 +00:00
|
|
|
if err := parseSecurityOpt(opts, cfg); err == nil {
|
2016-03-15 22:34:29 +00:00
|
|
|
t.Fatal("Expected parseSecurityOpt error, got nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
// test invalid opt
|
2019-08-09 12:10:07 +00:00
|
|
|
cfg.SecurityOpt = []string{"test"}
|
2023-04-14 07:27:20 +00:00
|
|
|
if err := parseSecurityOpt(opts, cfg); err == nil {
|
2016-03-15 22:34:29 +00:00
|
|
|
t.Fatal("Expected parseSecurityOpt error, got nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestParseSecurityOpt(t *testing.T) {
|
2023-04-14 07:27:20 +00:00
|
|
|
t.Run("apparmor", func(t *testing.T) {
|
|
|
|
secOpts := &container.SecurityOptions{}
|
|
|
|
err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
SecurityOpt: []string{"apparmor=test_profile"},
|
|
|
|
})
|
|
|
|
assert.Check(t, err)
|
|
|
|
assert.Equal(t, secOpts.AppArmorProfile, "test_profile")
|
|
|
|
})
|
|
|
|
t.Run("apparmor using legacy separator", func(t *testing.T) {
|
|
|
|
secOpts := &container.SecurityOptions{}
|
|
|
|
err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
SecurityOpt: []string{"apparmor:test_profile"},
|
|
|
|
})
|
|
|
|
assert.Check(t, err)
|
|
|
|
assert.Equal(t, secOpts.AppArmorProfile, "test_profile")
|
|
|
|
})
|
|
|
|
t.Run("seccomp", func(t *testing.T) {
|
|
|
|
secOpts := &container.SecurityOptions{}
|
|
|
|
err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
SecurityOpt: []string{"seccomp=/path/to/seccomp_test.json"},
|
|
|
|
})
|
|
|
|
assert.Check(t, err)
|
|
|
|
assert.Equal(t, secOpts.SeccompProfile, "/path/to/seccomp_test.json")
|
|
|
|
})
|
|
|
|
t.Run("valid label", func(t *testing.T) {
|
|
|
|
secOpts := &container.SecurityOptions{}
|
|
|
|
err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
SecurityOpt: []string{"label=user:USER"},
|
|
|
|
})
|
|
|
|
assert.Check(t, err)
|
|
|
|
if selinux.GetEnabled() {
|
|
|
|
// TODO(thaJeztah): set expected labels here (or "partial" if depends on host)
|
|
|
|
// assert.Check(t, is.Equal(secOpts.MountLabel, ""))
|
|
|
|
// assert.Check(t, is.Equal(secOpts.ProcessLabel, ""))
|
|
|
|
} else {
|
|
|
|
assert.Check(t, is.Equal(secOpts.MountLabel, ""))
|
|
|
|
assert.Check(t, is.Equal(secOpts.ProcessLabel, ""))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("invalid label", func(t *testing.T) {
|
|
|
|
secOpts := &container.SecurityOptions{}
|
|
|
|
err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
SecurityOpt: []string{"label"},
|
|
|
|
})
|
|
|
|
assert.Error(t, err, `invalid --security-opt 1: "label"`)
|
|
|
|
})
|
|
|
|
t.Run("invalid option (no value)", func(t *testing.T) {
|
|
|
|
secOpts := &container.SecurityOptions{}
|
|
|
|
err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
SecurityOpt: []string{"unknown"},
|
|
|
|
})
|
|
|
|
assert.Error(t, err, `invalid --security-opt 1: "unknown"`)
|
|
|
|
})
|
|
|
|
t.Run("unknown option", func(t *testing.T) {
|
|
|
|
secOpts := &container.SecurityOptions{}
|
|
|
|
err := parseSecurityOpt(secOpts, &containertypes.HostConfig{
|
|
|
|
SecurityOpt: []string{"unknown=something"},
|
|
|
|
})
|
|
|
|
assert.Error(t, err, `invalid --security-opt 2: "unknown=something"`)
|
|
|
|
})
|
2016-02-02 02:26:47 +00:00
|
|
|
}
|
|
|
|
|
2017-01-09 01:22:05 +00:00
|
|
|
func TestParseNNPSecurityOptions(t *testing.T) {
|
2022-08-31 20:12:30 +00:00
|
|
|
daemonCfg := &configStore{Config: config.Config{NoNewPrivileges: true}}
|
2022-08-17 21:13:49 +00:00
|
|
|
daemon := &Daemon{}
|
|
|
|
daemon.configStore.Store(daemonCfg)
|
2023-04-14 07:27:20 +00:00
|
|
|
opts := &container.SecurityOptions{}
|
2019-08-09 12:10:07 +00:00
|
|
|
cfg := &containertypes.HostConfig{}
|
2017-01-09 01:22:05 +00:00
|
|
|
|
|
|
|
// test NNP when "daemon:true" and "no-new-privileges=false""
|
2019-08-09 12:10:07 +00:00
|
|
|
cfg.SecurityOpt = []string{"no-new-privileges=false"}
|
2017-01-09 01:22:05 +00:00
|
|
|
|
2022-08-31 20:12:30 +00:00
|
|
|
if err := daemon.parseSecurityOpt(&daemonCfg.Config, opts, cfg); err != nil {
|
2017-01-09 01:22:05 +00:00
|
|
|
t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err)
|
|
|
|
}
|
2023-04-14 07:27:20 +00:00
|
|
|
if opts.NoNewPrivileges {
|
|
|
|
t.Fatalf("container.NoNewPrivileges should be FALSE: %v", opts.NoNewPrivileges)
|
2017-01-09 01:22:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// test NNP when "daemon:false" and "no-new-privileges=true""
|
2022-08-17 21:13:49 +00:00
|
|
|
daemonCfg.NoNewPrivileges = false
|
2019-08-09 12:10:07 +00:00
|
|
|
cfg.SecurityOpt = []string{"no-new-privileges=true"}
|
2017-01-09 01:22:05 +00:00
|
|
|
|
2022-08-31 20:12:30 +00:00
|
|
|
if err := daemon.parseSecurityOpt(&daemonCfg.Config, opts, cfg); err != nil {
|
2017-01-09 01:22:05 +00:00
|
|
|
t.Fatalf("Unexpected daemon.parseSecurityOpt error: %v", err)
|
|
|
|
}
|
2023-04-14 07:27:20 +00:00
|
|
|
if !opts.NoNewPrivileges {
|
|
|
|
t.Fatalf("container.NoNewPrivileges should be TRUE: %v", opts.NoNewPrivileges)
|
2017-01-09 01:22:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-18 22:41:52 +00:00
|
|
|
func TestVerifyPlatformContainerResources(t *testing.T) {
|
2018-12-17 10:23:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
var (
|
|
|
|
no = false
|
|
|
|
yes = true
|
|
|
|
)
|
|
|
|
|
|
|
|
withMemoryLimit := func(si *sysinfo.SysInfo) {
|
|
|
|
si.MemoryLimit = true
|
|
|
|
}
|
|
|
|
withSwapLimit := func(si *sysinfo.SysInfo) {
|
|
|
|
si.SwapLimit = true
|
|
|
|
}
|
|
|
|
withOomKillDisable := func(si *sysinfo.SysInfo) {
|
|
|
|
si.OomKillDisable = true
|
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
resources containertypes.Resources
|
|
|
|
sysInfo sysinfo.SysInfo
|
|
|
|
update bool
|
|
|
|
expectedWarnings []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "no-oom-kill-disable",
|
|
|
|
resources: containertypes.Resources{},
|
|
|
|
sysInfo: sysInfo(t, withMemoryLimit),
|
|
|
|
expectedWarnings: []string{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "oom-kill-disable-disabled",
|
|
|
|
resources: containertypes.Resources{
|
|
|
|
OomKillDisable: &no,
|
|
|
|
},
|
|
|
|
sysInfo: sysInfo(t, withMemoryLimit),
|
|
|
|
expectedWarnings: []string{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "oom-kill-disable-not-supported",
|
|
|
|
resources: containertypes.Resources{
|
|
|
|
OomKillDisable: &yes,
|
|
|
|
},
|
|
|
|
sysInfo: sysInfo(t, withMemoryLimit),
|
|
|
|
expectedWarnings: []string{
|
|
|
|
"Your kernel does not support OomKillDisable. OomKillDisable discarded.",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "oom-kill-disable-without-memory-constraints",
|
|
|
|
resources: containertypes.Resources{
|
|
|
|
OomKillDisable: &yes,
|
|
|
|
Memory: 0,
|
|
|
|
},
|
|
|
|
sysInfo: sysInfo(t, withMemoryLimit, withOomKillDisable, withSwapLimit),
|
|
|
|
expectedWarnings: []string{
|
|
|
|
"OOM killer is disabled for the container, but no memory limit is set, this can result in the system running out of resources.",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "oom-kill-disable-with-memory-constraints-but-no-memory-limit-support",
|
|
|
|
resources: containertypes.Resources{
|
|
|
|
OomKillDisable: &yes,
|
|
|
|
Memory: linuxMinMemory,
|
|
|
|
},
|
|
|
|
sysInfo: sysInfo(t, withOomKillDisable),
|
|
|
|
expectedWarnings: []string{
|
|
|
|
"Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.",
|
|
|
|
"OOM killer is disabled for the container, but no memory limit is set, this can result in the system running out of resources.",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "oom-kill-disable-with-memory-constraints",
|
|
|
|
resources: containertypes.Resources{
|
|
|
|
OomKillDisable: &yes,
|
|
|
|
Memory: linuxMinMemory,
|
|
|
|
},
|
|
|
|
sysInfo: sysInfo(t, withMemoryLimit, withOomKillDisable, withSwapLimit),
|
|
|
|
expectedWarnings: []string{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range tests {
|
2021-09-22 15:12:45 +00:00
|
|
|
tc := tc
|
2018-12-17 10:23:41 +00:00
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2018-12-18 22:41:52 +00:00
|
|
|
warnings, err := verifyPlatformContainerResources(&tc.resources, &tc.sysInfo, tc.update)
|
2018-12-17 10:23:41 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
for _, w := range tc.expectedWarnings {
|
|
|
|
assert.Assert(t, is.Contains(warnings, w))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func sysInfo(t *testing.T, opts ...func(*sysinfo.SysInfo)) sysinfo.SysInfo {
|
|
|
|
t.Helper()
|
|
|
|
si := sysinfo.SysInfo{}
|
|
|
|
|
|
|
|
for _, opt := range opts {
|
|
|
|
opt(&si)
|
|
|
|
}
|
|
|
|
|
|
|
|
if si.OomKillDisable {
|
|
|
|
t.Log(t.Name(), "OOM disable supported")
|
|
|
|
}
|
|
|
|
return si
|
|
|
|
}
|
2019-05-14 07:21:55 +00:00
|
|
|
|
|
|
|
const (
|
|
|
|
// prepare major 0x1FD(509 in decimal) and minor 0x130(304)
|
|
|
|
DEVNO = 0x11FD30
|
|
|
|
MAJOR = 509
|
|
|
|
MINOR = 304
|
|
|
|
WEIGHT = 1024
|
|
|
|
)
|
|
|
|
|
|
|
|
func deviceTypeMock(t *testing.T, testAndCheck func(string)) {
|
|
|
|
if os.Getuid() != 0 {
|
|
|
|
t.Skip("root required") // for mknod
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
2021-08-24 10:10:50 +00:00
|
|
|
tempDir, err := os.MkdirTemp("", "tempDevDir"+t.Name())
|
2019-05-14 07:21:55 +00:00
|
|
|
assert.NilError(t, err, "create temp file")
|
|
|
|
tempFile := filepath.Join(tempDir, "dev")
|
|
|
|
|
|
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
|
|
|
|
if err = unix.Mknod(tempFile, unix.S_IFCHR, DEVNO); err != nil {
|
|
|
|
t.Fatalf("mknod error %s(%x): %v", tempFile, DEVNO, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
testAndCheck(tempFile)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetBlkioWeightDevices(t *testing.T) {
|
|
|
|
deviceTypeMock(t, func(tempFile string) {
|
|
|
|
mockResource := containertypes.Resources{
|
|
|
|
BlkioWeightDevice: []*blkiodev.WeightDevice{{Path: tempFile, Weight: WEIGHT}},
|
|
|
|
}
|
|
|
|
|
|
|
|
weightDevs, err := getBlkioWeightDevices(mockResource)
|
|
|
|
|
|
|
|
assert.NilError(t, err, "getBlkioWeightDevices")
|
|
|
|
assert.Check(t, is.Len(weightDevs, 1), "getBlkioWeightDevices")
|
|
|
|
assert.Check(t, weightDevs[0].Major == MAJOR, "get major device type")
|
|
|
|
assert.Check(t, weightDevs[0].Minor == MINOR, "get minor device type")
|
|
|
|
assert.Check(t, *weightDevs[0].Weight == WEIGHT, "get device weight")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetBlkioThrottleDevices(t *testing.T) {
|
|
|
|
deviceTypeMock(t, func(tempFile string) {
|
|
|
|
mockDevs := []*blkiodev.ThrottleDevice{{Path: tempFile, Rate: WEIGHT}}
|
|
|
|
|
|
|
|
retDevs, err := getBlkioThrottleDevices(mockDevs)
|
|
|
|
|
|
|
|
assert.NilError(t, err, "getBlkioThrottleDevices")
|
|
|
|
assert.Check(t, is.Len(retDevs, 1), "getBlkioThrottleDevices")
|
|
|
|
assert.Check(t, retDevs[0].Major == MAJOR, "get major device type")
|
|
|
|
assert.Check(t, retDevs[0].Minor == MINOR, "get minor device type")
|
|
|
|
assert.Check(t, retDevs[0].Rate == WEIGHT, "get device rate")
|
|
|
|
})
|
|
|
|
}
|