880 lines
29 KiB
Go
880 lines
29 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/containers/common/pkg/apparmor"
|
|
"github.com/containers/common/pkg/capabilities"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
"github.com/onsi/gomega"
|
|
selinux "github.com/opencontainers/selinux/go-selinux"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var _ = Describe("Config", func() {
|
|
Describe("ValidateConfig", func() {
|
|
It("should succeed with default config", func() {
|
|
// Given
|
|
// When
|
|
defaultConfig, err := NewConfig("")
|
|
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defaultConfig.Containers.ApparmorProfile).To(gomega.Equal(apparmor.Profile))
|
|
gomega.Expect(defaultConfig.Containers.BaseHostsFile).To(gomega.Equal(""))
|
|
gomega.Expect(defaultConfig.Containers.InterfaceName).To(gomega.Equal(""))
|
|
gomega.Expect(defaultConfig.Containers.PidsLimit).To(gomega.BeEquivalentTo(2048))
|
|
gomega.Expect(defaultConfig.Containers.Privileged).To(gomega.BeFalse())
|
|
gomega.Expect(defaultConfig.Containers.ReadOnly).To(gomega.BeFalse())
|
|
gomega.Expect(defaultConfig.Engine.ServiceTimeout).To(gomega.BeEquivalentTo(5))
|
|
gomega.Expect(defaultConfig.Engine.CompressionFormat).To(gomega.BeEquivalentTo("gzip"))
|
|
gomega.Expect(defaultConfig.Engine.CompressionLevel).To(gomega.BeNil())
|
|
gomega.Expect(defaultConfig.NetNS()).To(gomega.BeEquivalentTo("private"))
|
|
gomega.Expect(defaultConfig.IPCNS()).To(gomega.BeEquivalentTo("shareable"))
|
|
gomega.Expect(defaultConfig.Engine.InfraImage).To(gomega.BeEquivalentTo(""))
|
|
gomega.Expect(defaultConfig.Engine.ImageVolumeMode).To(gomega.BeEquivalentTo("anonymous"))
|
|
gomega.Expect(defaultConfig.Engine.SSHConfig).To(gomega.ContainSubstring("/.ssh/config"))
|
|
gomega.Expect(defaultConfig.Engine.EventsContainerCreateInspectData).To(gomega.BeFalse())
|
|
gomega.Expect(defaultConfig.Engine.DBBackend).To(gomega.Equal(""))
|
|
gomega.Expect(defaultConfig.Engine.PodmanshTimeout).To(gomega.BeEquivalentTo(30))
|
|
gomega.Expect(defaultConfig.Engine.AddCompression.Get()).To(gomega.BeEmpty())
|
|
gomega.Expect(defaultConfig.Podmansh.Container).To(gomega.Equal("podmansh"))
|
|
gomega.Expect(defaultConfig.Podmansh.Shell).To(gomega.Equal("/bin/sh"))
|
|
gomega.Expect(defaultConfig.Podmansh.Timeout).To(gomega.BeEquivalentTo(0))
|
|
|
|
path, err := defaultConfig.ImageCopyTmpDir()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(path).To(gomega.BeEquivalentTo("/var/tmp"))
|
|
gomega.Expect(defaultConfig.Engine.Retry).To(gomega.BeEquivalentTo(3))
|
|
gomega.Expect(defaultConfig.Engine.RetryDelay).To(gomega.Equal(""))
|
|
})
|
|
|
|
It("should succeed with devices", func() {
|
|
defConf, err := defaultConfig()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf).NotTo(gomega.BeNil())
|
|
|
|
// Given
|
|
defConf.Containers.Devices.Set([]string{
|
|
"/dev/null:/dev/null:rw",
|
|
"/dev/sdc/",
|
|
"/dev/sdc:/dev/xvdc",
|
|
"/dev/sdc:rm",
|
|
})
|
|
|
|
// When
|
|
err = defConf.Containers.Validate()
|
|
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("should fail wrong max log size", func() {
|
|
defConf, err := defaultConfig()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf).NotTo(gomega.BeNil())
|
|
|
|
// Given
|
|
defConf.Containers.LogSizeMax = 1
|
|
|
|
// When
|
|
err = defConf.Validate()
|
|
|
|
// Then
|
|
gomega.Expect(err).To(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("should succeed with valid shm size", func() {
|
|
defConf, err := defaultConfig()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf).NotTo(gomega.BeNil())
|
|
|
|
// Given
|
|
defConf.Containers.ShmSize = "1024"
|
|
|
|
// When
|
|
err = defConf.Validate()
|
|
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
|
|
// Given
|
|
defConf.Containers.ShmSize = "64m"
|
|
|
|
// When
|
|
err = defConf.Validate()
|
|
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("should fail wrong shm size", func() {
|
|
defConf, err := defaultConfig()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf).NotTo(gomega.BeNil())
|
|
|
|
// Given
|
|
defConf.Containers.ShmSize = "-2"
|
|
|
|
// When
|
|
err = defConf.Validate()
|
|
|
|
// Then
|
|
gomega.Expect(err).To(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("Check SELinux settings", func() {
|
|
defaultConfig, _ := NewConfig("")
|
|
// EnableLabeling should match whether or not SELinux is enabled on the host
|
|
gomega.Expect(defaultConfig.Containers.EnableLabeling).To(gomega.Equal(selinux.GetEnabled()))
|
|
gomega.Expect(defaultConfig.Containers.EnableLabeledUsers).To(gomega.BeFalse())
|
|
})
|
|
|
|
It("Check podmansh timeout settings", func() {
|
|
// Note: Podmansh.Timeout must be preferred over Engine.PodmanshTimeout
|
|
|
|
// Given
|
|
defaultConfig, _ := NewConfig("")
|
|
// When
|
|
defaultConfig.Engine.PodmanshTimeout = 30
|
|
defaultConfig.Podmansh.Timeout = 0
|
|
|
|
// Then
|
|
gomega.Expect(defaultConfig.PodmanshTimeout()).To(gomega.Equal(uint(30)))
|
|
|
|
// When
|
|
defaultConfig.Engine.PodmanshTimeout = 0
|
|
defaultConfig.Podmansh.Timeout = 42
|
|
|
|
// Then
|
|
gomega.Expect(defaultConfig.PodmanshTimeout()).To(gomega.Equal(uint(42)))
|
|
|
|
// When
|
|
defaultConfig.Engine.PodmanshTimeout = 300
|
|
defaultConfig.Podmansh.Timeout = 42
|
|
|
|
// Then
|
|
gomega.Expect(defaultConfig.PodmanshTimeout()).To(gomega.Equal(uint(42)))
|
|
})
|
|
})
|
|
|
|
Describe("ValidateNetworkConfig", func() {
|
|
It("should succeed with default config", func() {
|
|
defConf, err := defaultConfig()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf).NotTo(gomega.BeNil())
|
|
|
|
// Given
|
|
// When
|
|
err = defConf.Network.Validate()
|
|
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Describe("readStorageTmp", func() {
|
|
It("test image_copy_tmp_dir='storage'", func() {
|
|
t := GinkgoT()
|
|
// Reload from new configuration file
|
|
testFile := t.TempDir() + "/temp.conf"
|
|
content := `[engine]
|
|
image_copy_tmp_dir="storage"`
|
|
err := os.WriteFile(testFile, []byte(content), os.ModePerm)
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
|
|
config, _ := NewConfig(testFile)
|
|
path, err := config.ImageCopyTmpDir()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(path).To(gomega.ContainSubstring("containers/storage/tmp"))
|
|
// Given we do
|
|
t.Setenv("TMPDIR", "/var/tmp/foobar")
|
|
path, err = config.ImageCopyTmpDir()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(path).To(gomega.BeEquivalentTo("/var/tmp/foobar"))
|
|
})
|
|
})
|
|
|
|
Describe("readConfigFromFile", func() {
|
|
It("should succeed with default config", func() {
|
|
// Given
|
|
// When
|
|
defaultConfig, _ := defaultConfig()
|
|
// prior to reading local config, shows hard coded defaults
|
|
gomega.Expect(defaultConfig.Containers.HTTPProxy).To(gomega.BeTrue())
|
|
gomega.Expect(defaultConfig.Engine.HealthcheckEvents).To(gomega.BeTrue())
|
|
gomega.Expect(defaultConfig.Containers.ContainerNameAsHostName).To(gomega.BeFalse())
|
|
|
|
err := readConfigFromFile("testdata/containers_default.conf", defaultConfig, false)
|
|
|
|
crunWasm := "crun-wasm"
|
|
PlatformToOCIRuntimeMap := map[string]string{
|
|
"wasi/wasm": crunWasm,
|
|
"wasi/wasm32": crunWasm,
|
|
"wasi/wasm64": crunWasm,
|
|
}
|
|
|
|
OCIRuntimeMap := map[string][]string{
|
|
"kata": {
|
|
"/usr/bin/kata-runtime",
|
|
"/usr/sbin/kata-runtime",
|
|
"/usr/local/bin/kata-runtime",
|
|
"/usr/local/sbin/kata-runtime",
|
|
"/sbin/kata-runtime",
|
|
"/bin/kata-runtime",
|
|
"/usr/bin/kata-qemu",
|
|
"/usr/bin/kata-fc",
|
|
},
|
|
"runc": {
|
|
"/usr/bin/runc",
|
|
"/usr/sbin/runc",
|
|
"/usr/local/bin/runc",
|
|
"/usr/local/sbin/runc",
|
|
"/sbin/runc",
|
|
"/bin/runc",
|
|
"/usr/lib/cri-o-runc/sbin/runc",
|
|
},
|
|
"runj": {
|
|
"/usr/local/bin/runj",
|
|
},
|
|
"crun": {
|
|
"/usr/bin/crun",
|
|
"/usr/local/bin/crun",
|
|
},
|
|
"crun-vm": {
|
|
"/usr/bin/crun-vm",
|
|
"/usr/local/bin/crun-vm",
|
|
"/usr/local/sbin/crun-vm",
|
|
"/sbin/crun-vm",
|
|
"/bin/crun-vm",
|
|
"/run/current-system/sw/bin/crun-vm",
|
|
},
|
|
"crun-wasm": {
|
|
"/usr/bin/crun-wasm",
|
|
"/usr/sbin/crun-wasm",
|
|
"/usr/local/bin/crun-wasm",
|
|
"/usr/local/sbin/crun-wasm",
|
|
"/sbin/crun-wasm",
|
|
"/bin/crun-wasm",
|
|
"/run/current-system/sw/bin/crun-wasm",
|
|
},
|
|
"runsc": {
|
|
"/usr/bin/runsc",
|
|
"/usr/sbin/runsc",
|
|
"/usr/local/bin/runsc",
|
|
"/usr/local/sbin/runsc",
|
|
"/bin/runsc",
|
|
"/sbin/runsc",
|
|
"/run/current-system/sw/bin/runsc",
|
|
},
|
|
"youki": {
|
|
"/usr/local/bin/youki",
|
|
"/usr/bin/youki",
|
|
"/bin/youki",
|
|
"/run/current-system/sw/bin/youki",
|
|
},
|
|
"krun": {
|
|
"/usr/bin/krun",
|
|
"/usr/local/bin/krun",
|
|
},
|
|
"ocijail": {
|
|
"/usr/local/bin/ocijail",
|
|
},
|
|
}
|
|
|
|
pluginDirs := []string{
|
|
"/usr/libexec/cni",
|
|
"/tmp",
|
|
}
|
|
|
|
envs := []string{
|
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
}
|
|
|
|
mounts := []string{
|
|
"type=glob,source=/tmp/test2*,ro=true",
|
|
"type=bind,source=/etc/services,destination=/etc/services,ro",
|
|
}
|
|
|
|
volumes := []string{
|
|
"$HOME:$HOME",
|
|
}
|
|
|
|
newVolumes := []string{
|
|
os.ExpandEnv("$HOME:$HOME"),
|
|
}
|
|
|
|
helperDirs := []string{
|
|
"/somepath",
|
|
}
|
|
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defaultConfig.Engine.CgroupManager).To(gomega.Equal("systemd"))
|
|
gomega.Expect(defaultConfig.Containers.ContainerNameAsHostName).To(gomega.BeTrue())
|
|
gomega.Expect(defaultConfig.Containers.Env.Get()).To(gomega.BeEquivalentTo(envs))
|
|
gomega.Expect(defaultConfig.Containers.Mounts.Get()).To(gomega.BeEquivalentTo(mounts))
|
|
gomega.Expect(defaultConfig.Containers.PidsLimit).To(gomega.BeEquivalentTo(2048))
|
|
gomega.Expect(defaultConfig.Network.CNIPluginDirs.Get()).To(gomega.Equal(pluginDirs))
|
|
gomega.Expect(defaultConfig.Network.NetavarkPluginDirs.Get()).To(gomega.Equal([]string{"/usr/netavark"}))
|
|
gomega.Expect(defaultConfig.Engine.NumLocks).To(gomega.BeEquivalentTo(2048))
|
|
gomega.Expect(defaultConfig.Engine.OCIRuntimes).To(gomega.Equal(OCIRuntimeMap))
|
|
gomega.Expect(defaultConfig.Engine.PlatformToOCIRuntime).To(gomega.Equal(PlatformToOCIRuntimeMap))
|
|
gomega.Expect(defaultConfig.Containers.HTTPProxy).To(gomega.BeFalse())
|
|
gomega.Expect(defaultConfig.Engine.NetworkCmdOptions.Get()).To(gomega.BeEmpty())
|
|
gomega.Expect(defaultConfig.Engine.HelperBinariesDir.Get()).To(gomega.Equal(helperDirs))
|
|
gomega.Expect(defaultConfig.Engine.ServiceTimeout).To(gomega.BeEquivalentTo(300))
|
|
gomega.Expect(defaultConfig.Engine.InfraImage).To(gomega.BeEquivalentTo("registry.k8s.io/pause:3.4.1"))
|
|
gomega.Expect(defaultConfig.Engine.PodmanshTimeout).To(gomega.BeEquivalentTo(300))
|
|
gomega.Expect(defaultConfig.Machine.Volumes.Get()).To(gomega.BeEquivalentTo(volumes))
|
|
gomega.Expect(defaultConfig.Podmansh.Timeout).To(gomega.BeEquivalentTo(42))
|
|
gomega.Expect(defaultConfig.Podmansh.Shell).To(gomega.Equal("/bin/zsh"))
|
|
gomega.Expect(defaultConfig.Podmansh.Container).To(gomega.BeEquivalentTo("podmansh-1"))
|
|
gomega.Expect(defaultConfig.Engine.HealthcheckEvents).To(gomega.BeFalse())
|
|
newV, err := defaultConfig.MachineVolumes()
|
|
if newVolumes[0] == ":" {
|
|
// $HOME is not set
|
|
gomega.Expect(err).To(gomega.HaveOccurred())
|
|
} else {
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(newV).To(gomega.BeEquivalentTo(newVolumes))
|
|
}
|
|
gomega.Expect(defaultConfig.Engine.Retry).To(gomega.BeEquivalentTo(5))
|
|
gomega.Expect(defaultConfig.Engine.RetryDelay).To(gomega.Equal("10s"))
|
|
})
|
|
|
|
It("test GetDefaultEnvEx", func() {
|
|
envs := []string{
|
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
}
|
|
httpEnvs := append([]string{"HTTP_PROXY=1.2.3.4"}, envs...)
|
|
t := GinkgoT()
|
|
t.Setenv("HTTP_PROXY", "1.2.3.4")
|
|
t.Setenv("foo", "bar")
|
|
|
|
defaultConfig, _ := defaultConfig()
|
|
gomega.Expect(defaultConfig.GetDefaultEnvEx(false, false)).To(gomega.BeEquivalentTo(envs))
|
|
gomega.Expect(defaultConfig.GetDefaultEnvEx(false, true)).To(gomega.BeEquivalentTo(httpEnvs))
|
|
gomega.Expect(strings.Join(defaultConfig.GetDefaultEnvEx(true, true), ",")).To(gomega.ContainSubstring("HTTP_PROXY"))
|
|
gomega.Expect(strings.Join(defaultConfig.GetDefaultEnvEx(true, true), ",")).To(gomega.ContainSubstring("foo"))
|
|
})
|
|
|
|
It("should succeed with commented out configuration", func() {
|
|
// Given
|
|
// When
|
|
conf := Config{}
|
|
err := readConfigFromFile("testdata/containers_comment.conf", &conf, false)
|
|
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("should fail when file does not exist", func() {
|
|
// Given
|
|
// When
|
|
conf := Config{}
|
|
err := readConfigFromFile("/invalid/file", &conf, false)
|
|
|
|
// Then
|
|
gomega.Expect(err).To(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("should fail when toml decode fails", func() {
|
|
// Given
|
|
// When
|
|
conf := Config{}
|
|
err := readConfigFromFile("config.go", &conf, false)
|
|
|
|
// Then
|
|
gomega.Expect(err).To(gomega.HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Describe("NewConfig", func() {
|
|
It("should success with default config", func() {
|
|
// Given
|
|
OCIRuntimeMap := map[string][]string{
|
|
"runc": {
|
|
"/usr/bin/runc",
|
|
"/usr/sbin/runc",
|
|
"/usr/local/bin/runc",
|
|
"/usr/local/sbin/runc",
|
|
"/sbin/runc",
|
|
"/bin/runc",
|
|
"/usr/lib/cri-o-runc/sbin/runc",
|
|
"/run/current-system/sw/bin/runc",
|
|
},
|
|
"crun": {
|
|
"/usr/bin/crun",
|
|
"/usr/sbin/crun",
|
|
"/usr/local/bin/crun",
|
|
"/usr/local/sbin/crun",
|
|
"/sbin/crun",
|
|
"/bin/crun",
|
|
"/run/current-system/sw/bin/crun",
|
|
},
|
|
}
|
|
|
|
var defCaps []string
|
|
if runtime.GOOS == "linux" {
|
|
defCaps = []string{
|
|
"CAP_CHOWN",
|
|
"CAP_DAC_OVERRIDE",
|
|
"CAP_FOWNER",
|
|
"CAP_FSETID",
|
|
"CAP_KILL",
|
|
"CAP_NET_BIND_SERVICE",
|
|
"CAP_SETFCAP",
|
|
"CAP_SETGID",
|
|
"CAP_SETPCAP",
|
|
"CAP_SETUID",
|
|
"CAP_SYS_CHROOT",
|
|
}
|
|
}
|
|
|
|
envs := []string{
|
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
}
|
|
|
|
// Given we do
|
|
GinkgoT().Setenv(containersConfEnv, "/dev/null")
|
|
// When
|
|
config, err := NewConfig("")
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(config.Containers.ApparmorProfile).To(gomega.Equal(apparmor.Profile))
|
|
gomega.Expect(config.Containers.PidsLimit).To(gomega.BeEquivalentTo(2048))
|
|
gomega.Expect(config.Containers.Env.Get()).To(gomega.BeEquivalentTo(envs))
|
|
gomega.Expect(config.Containers.UserNS).To(gomega.BeEquivalentTo(""))
|
|
gomega.Expect(config.Network.CNIPluginDirs.Get()).To(gomega.Equal(DefaultCNIPluginDirs))
|
|
gomega.Expect(config.Network.NetavarkPluginDirs.Get()).To(gomega.Equal(DefaultNetavarkPluginDirs))
|
|
gomega.Expect(config.Engine.NumLocks).To(gomega.BeEquivalentTo(2048))
|
|
gomega.Expect(config.Engine.OCIRuntimes["runc"]).To(gomega.Equal(OCIRuntimeMap["runc"]))
|
|
gomega.Expect(config.Containers.CgroupConf.Get()).To(gomega.BeEmpty())
|
|
|
|
caps, err := config.Capabilities("", nil, nil)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(caps).Should(gomega.Equal(defCaps))
|
|
|
|
if useSystemd() {
|
|
gomega.Expect(config.Engine.CgroupManager).To(gomega.BeEquivalentTo("systemd"))
|
|
} else {
|
|
gomega.Expect(config.Engine.CgroupManager).To(gomega.BeEquivalentTo("cgroupfs"))
|
|
}
|
|
if useJournald() {
|
|
gomega.Expect(config.Engine.EventsLogger).To(gomega.BeEquivalentTo("journald"))
|
|
gomega.Expect(config.Containers.LogDriver).To(gomega.BeEquivalentTo("journald"))
|
|
} else {
|
|
gomega.Expect(config.Engine.EventsLogger).To(gomega.BeEquivalentTo("file"))
|
|
gomega.Expect(config.Containers.LogDriver).To(gomega.BeEquivalentTo("k8s-file"))
|
|
}
|
|
gomega.Expect(config.Engine.EventsLogFilePath).To(gomega.BeEquivalentTo(""))
|
|
gomega.Expect(uint64(config.Engine.EventsLogFileMaxSize)).To(gomega.Equal(DefaultEventsLogSizeMax))
|
|
gomega.Expect(config.Engine.PodExitPolicy).To(gomega.Equal(PodExitPolicyContinue))
|
|
gomega.Expect(config.Engine.KubeGenerateType).To(gomega.Equal("pod"))
|
|
})
|
|
|
|
It("should success with valid user file path", func() {
|
|
// Given
|
|
// When
|
|
config, err := NewConfig("testdata/containers_default.conf")
|
|
// Then
|
|
cgroupConf := []string{
|
|
"memory.high=1073741824",
|
|
}
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(config.Containers.ApparmorProfile).To(gomega.Equal("container-default"))
|
|
gomega.Expect(config.Containers.PidsLimit).To(gomega.BeEquivalentTo(2048))
|
|
gomega.Expect(config.Containers.BaseHostsFile).To(gomega.BeEquivalentTo("/etc/hosts2"))
|
|
gomega.Expect(config.Containers.HostContainersInternalIP).To(gomega.BeEquivalentTo("1.2.3.4"))
|
|
gomega.Expect(config.Engine.ImageVolumeMode).To(gomega.BeEquivalentTo("tmpfs"))
|
|
gomega.Expect(config.Engine.SSHConfig).To(gomega.Equal("/foo/bar/.ssh/config"))
|
|
|
|
gomega.Expect(config.Engine.DBBackend).To(gomega.Equal(stringSQLite))
|
|
gomega.Expect(config.Containers.CgroupConf.Get()).To(gomega.Equal(cgroupConf))
|
|
gomega.Expect(*config.Containers.OOMScoreAdj).To(gomega.Equal(int(750)))
|
|
gomega.Expect(config.Engine.KubeGenerateType).To(gomega.Equal("pod"))
|
|
})
|
|
|
|
It("contents of passed-in file should override others", func() {
|
|
// Given we do
|
|
GinkgoT().Setenv(containersConfEnv, "containers.conf")
|
|
// When
|
|
config, err := NewConfig("testdata/containers_override.conf")
|
|
|
|
crunWasm := "crun-wasm"
|
|
PlatformToOCIRuntimeMap := map[string]string{
|
|
"hello": "world",
|
|
"wasi/wasm": crunWasm,
|
|
"wasi/wasm32": crunWasm,
|
|
"wasi/wasm64": crunWasm,
|
|
}
|
|
|
|
// Also test `ImagePlatformToRuntimes
|
|
runtimes := config.Engine.ImagePlatformToRuntime("wasi", "wasm")
|
|
gomega.Expect(runtimes).To(gomega.Equal(crunWasm))
|
|
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(config).ToNot(gomega.BeNil())
|
|
gomega.Expect(config.Containers.ApparmorProfile).To(gomega.Equal("overridden-default"))
|
|
gomega.Expect(config.Containers.LogDriver).To(gomega.Equal("journald"))
|
|
gomega.Expect(config.Containers.LogTag).To(gomega.Equal("{{.Name}}|{{.ID}}"))
|
|
gomega.Expect(config.Containers.LogSizeMax).To(gomega.Equal(int64(100000)))
|
|
gomega.Expect(config.Containers.Privileged).To(gomega.BeTrue())
|
|
gomega.Expect(config.Containers.ReadOnly).To(gomega.BeTrue())
|
|
gomega.Expect(config.Engine.ImageParallelCopies).To(gomega.Equal(uint(10)))
|
|
gomega.Expect(config.Engine.PlatformToOCIRuntime).To(gomega.Equal(PlatformToOCIRuntimeMap))
|
|
gomega.Expect(config.Engine.ImageDefaultFormat).To(gomega.Equal("v2s2"))
|
|
gomega.Expect(config.Engine.CompressionFormat).To(gomega.BeEquivalentTo("zstd:chunked"))
|
|
gomega.Expect(config.Engine.EventsLogFilePath).To(gomega.BeEquivalentTo("/tmp/events.log"))
|
|
gomega.Expect(config.Engine.EventsContainerCreateInspectData).To(gomega.BeTrue())
|
|
path, err := config.ImageCopyTmpDir()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(path).To(gomega.BeEquivalentTo("/tmp/foobar"))
|
|
gomega.Expect(uint64(config.Engine.EventsLogFileMaxSize)).To(gomega.Equal(uint64(500)))
|
|
gomega.Expect(config.Engine.PodExitPolicy).To(gomega.BeEquivalentTo(PodExitPolicyStop))
|
|
})
|
|
|
|
It("should fail with invalid value", func() {
|
|
// Given
|
|
// When
|
|
config, err := NewConfig("testdata/containers_invalid.conf")
|
|
// Then
|
|
gomega.Expect(err).To(gomega.HaveOccurred())
|
|
gomega.Expect(config).To(gomega.BeNil())
|
|
})
|
|
|
|
It("Test Capabilities call", func() {
|
|
// Given
|
|
if runtime.GOOS != "linux" {
|
|
Skip(fmt.Sprintf("capabilities not supported on %s", runtime.GOOS))
|
|
}
|
|
// When
|
|
config, err := NewConfig("")
|
|
// Then
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
var addcaps, dropcaps []string
|
|
caps, err := config.Capabilities("0", addcaps, dropcaps)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
sort.Strings(caps)
|
|
defaultCaps := config.Containers.DefaultCapabilities.Get()
|
|
sort.Strings(defaultCaps)
|
|
gomega.Expect(caps).To(gomega.BeEquivalentTo(defaultCaps))
|
|
|
|
// Add all caps
|
|
addcaps = []string{"all"}
|
|
caps, err = config.Capabilities("root", addcaps, dropcaps)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
sort.Strings(caps)
|
|
boundingSet, err := capabilities.BoundingSet()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(caps).To(gomega.BeEquivalentTo(boundingSet))
|
|
|
|
// Drop all caps
|
|
dropcaps = []string{"all"}
|
|
caps, err = config.Capabilities("", boundingSet, dropcaps)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
sort.Strings(caps)
|
|
gomega.Expect(caps).ToNot(gomega.BeEquivalentTo([]string{}))
|
|
|
|
config.Containers.DefaultCapabilities.Set([]string{
|
|
"CAP_AUDIT_WRITE",
|
|
"CAP_CHOWN",
|
|
"CAP_DAC_OVERRIDE",
|
|
"CAP_FOWNER",
|
|
})
|
|
|
|
expectedCaps := []string{
|
|
"CAP_AUDIT_WRITE",
|
|
"CAP_DAC_OVERRIDE",
|
|
"CAP_NET_ADMIN",
|
|
"CAP_SYS_ADMIN",
|
|
}
|
|
|
|
// Add all caps
|
|
addcaps = []string{"CAP_NET_ADMIN", "CAP_SYS_ADMIN"}
|
|
dropcaps = []string{"CAP_FOWNER", "CAP_CHOWN"}
|
|
caps, err = config.Capabilities("", addcaps, dropcaps)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
sort.Strings(caps)
|
|
gomega.Expect(caps).To(gomega.BeEquivalentTo(expectedCaps))
|
|
|
|
addcaps = []string{"NET_ADMIN", "cap_sys_admin"}
|
|
dropcaps = []string{"FOWNER", "chown"}
|
|
caps, err = config.Capabilities("", addcaps, dropcaps)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
sort.Strings(caps)
|
|
gomega.Expect(caps).To(gomega.BeEquivalentTo(expectedCaps))
|
|
|
|
expectedCaps = []string{"CAP_NET_ADMIN", "CAP_SYS_ADMIN"}
|
|
caps, err = config.Capabilities("notroot", addcaps, dropcaps)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
sort.Strings(caps)
|
|
gomega.Expect(caps).To(gomega.BeEquivalentTo(expectedCaps))
|
|
})
|
|
|
|
It("should succeed with default pull_policy", func() {
|
|
defConf, err := defaultConfig()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf).NotTo(gomega.BeNil())
|
|
|
|
err = defConf.Engine.Validate()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf.Engine.PullPolicy).To(gomega.Equal("missing"))
|
|
|
|
defConf.Engine.PullPolicy = DefaultPullPolicy
|
|
err = defConf.Engine.Validate()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("should succeed case-insensitive", func() {
|
|
defConf, err := defaultConfig()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf).NotTo(gomega.BeNil())
|
|
|
|
defConf.Engine.PullPolicy = "NeVer"
|
|
err = defConf.Engine.Validate()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("should fail with invalid pull_policy", func() {
|
|
defConf, err := defaultConfig()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf).NotTo(gomega.BeNil())
|
|
|
|
defConf.Engine.PullPolicy = "invalidPullPolicy"
|
|
err = defConf.Engine.Validate()
|
|
gomega.Expect(err).To(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("should fail with invalid database_backend", func() {
|
|
defConf, err := defaultConfig()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(defConf).NotTo(gomega.BeNil())
|
|
|
|
defConf.Engine.DBBackend = "blah"
|
|
err = defConf.Engine.Validate()
|
|
gomega.Expect(err).To(gomega.HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Describe("Service Destinations", func() {
|
|
BeforeEach(func() {
|
|
t := GinkgoT()
|
|
name := t.TempDir() + "/containersconf"
|
|
err := os.WriteFile(name, []byte{}, os.ModePerm)
|
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
t.Setenv(containersConfEnv, name)
|
|
})
|
|
|
|
It("test addConfigs", func() {
|
|
tmpFilePath := func(dir, prefix string) string {
|
|
file, err := os.CreateTemp(dir, prefix)
|
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
conf := file.Name() + ".conf"
|
|
|
|
err = os.Rename(file.Name(), conf)
|
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
return conf
|
|
}
|
|
configs := []string{
|
|
"test1",
|
|
"test2",
|
|
}
|
|
newConfigs, err := addConfigs("/bogus/path", configs)
|
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
gomega.Expect(newConfigs).To(gomega.Equal(configs))
|
|
|
|
t := GinkgoT()
|
|
dir := t.TempDir()
|
|
file1 := tmpFilePath(dir, "b")
|
|
file2 := tmpFilePath(dir, "a")
|
|
file3 := tmpFilePath(dir, "2")
|
|
file4 := tmpFilePath(dir, "1")
|
|
// create a file in dir that is not a .conf to make sure
|
|
// it does not show up in configs
|
|
f, err := os.CreateTemp(dir, "notconf")
|
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
f.Close()
|
|
subdir := filepath.Join(dir, "subdir")
|
|
err = os.Mkdir(subdir, 0o700)
|
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
// create a file in subdir, to make sure it does not
|
|
// show up in configs
|
|
f, err = os.CreateTemp(subdir, "")
|
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
f.Close()
|
|
|
|
newConfigs, err = addConfigs(dir, configs)
|
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
|
testConfigs := append(configs, []string{file4, file3, file2, file1}...)
|
|
gomega.Expect(newConfigs).To(gomega.Equal(testConfigs))
|
|
})
|
|
|
|
It("test config errors", func() {
|
|
conf := Config{}
|
|
content := bytes.NewBufferString("")
|
|
logrus.SetOutput(content)
|
|
logrus.SetLevel(logrus.DebugLevel)
|
|
err := readConfigFromFile("testdata/containers_broken.conf", &conf, false)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(conf.Containers.NetNS).To(gomega.Equal("bridge"))
|
|
gomega.Expect(conf.Containers.Umask).To(gomega.Equal("0002"))
|
|
gomega.Expect(content).To(gomega.ContainSubstring("Failed to decode the keys [\\\"foo\\\" \\\"containers.image_default_transport\\\"] from \\\"testdata/containers_broken.conf\\\""))
|
|
logrus.SetOutput(os.Stderr)
|
|
})
|
|
|
|
It("test default config errors", func() {
|
|
conf := Config{}
|
|
content := bytes.NewBufferString("")
|
|
logrus.SetOutput(content)
|
|
err := readConfigFromFile("containers.conf", &conf, false)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(content.String()).To(gomega.Equal(""))
|
|
logrus.SetOutput(os.Stderr)
|
|
})
|
|
})
|
|
|
|
Describe("Reload", func() {
|
|
It("test new config from reload", func() {
|
|
t := GinkgoT()
|
|
// Default configuration
|
|
defaultTestFile := "testdata/containers_default.conf"
|
|
// Note this must be defined before the Setenv as cleanup happens LIFO
|
|
// and Reload() must be called without the custom env to reset the default config
|
|
DeferCleanup(func() {
|
|
// Reload change back to default global configuration
|
|
_, err := Reload()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
})
|
|
t.Setenv(containersConfEnv, defaultTestFile)
|
|
|
|
cfg, err := Default()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
|
|
// Reload from new configuration file
|
|
testFile := t.TempDir() + "/temp.conf"
|
|
content := `[containers]
|
|
env=["foo=bar"]`
|
|
err = os.WriteFile(testFile, []byte(content), os.ModePerm)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
t.Setenv(containersConfEnv, testFile)
|
|
_, err = Reload()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
newCfg, err := Default()
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
|
|
expectOldEnv := []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}
|
|
expectNewEnv := []string{"foo=bar"}
|
|
gomega.Expect(cfg.Containers.Env.Get()).To(gomega.Equal(expectOldEnv))
|
|
gomega.Expect(newCfg.Containers.Env.Get()).To(gomega.Equal(expectNewEnv))
|
|
})
|
|
})
|
|
|
|
It("validate ImageVolumeMode", func() {
|
|
for _, mode := range append(validImageVolumeModes, "") {
|
|
err := ValidateImageVolumeMode(mode)
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
}
|
|
err := ValidateImageVolumeMode("bogus")
|
|
gomega.Expect(err).To(gomega.HaveOccurred())
|
|
})
|
|
|
|
It("CONTAINERS_CONF_OVERRIDE", func() {
|
|
t := GinkgoT()
|
|
t.Setenv("CONTAINERS_CONF_OVERRIDE", "testdata/containers_override.conf")
|
|
config, err := NewConfig("")
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(config.Containers.ApparmorProfile).To(gomega.Equal("overridden-default"))
|
|
|
|
// Make sure that _OVERRIDE is loaded even when CONTAINERS_CONF is set.
|
|
t.Setenv(containersConfEnv, "testdata/containers_default.conf")
|
|
config, err = NewConfig("")
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(config.Containers.ApparmorProfile).To(gomega.Equal("overridden-default"))
|
|
gomega.Expect(config.Containers.BaseHostsFile).To(gomega.Equal("/etc/hosts2"))
|
|
gomega.Expect(config.Containers.EnableLabeledUsers).To(gomega.BeTrue())
|
|
})
|
|
|
|
It("ParsePullPolicy", func() {
|
|
for _, test := range []struct {
|
|
value string
|
|
policy PullPolicy
|
|
fail bool
|
|
}{
|
|
{
|
|
value: "always",
|
|
policy: PullPolicyAlways,
|
|
},
|
|
{
|
|
value: "alWays",
|
|
policy: PullPolicyAlways,
|
|
},
|
|
{
|
|
value: "ALWAYS",
|
|
policy: PullPolicyAlways,
|
|
},
|
|
{
|
|
value: "never",
|
|
policy: PullPolicyNever,
|
|
},
|
|
{
|
|
value: "NEVER",
|
|
policy: PullPolicyNever,
|
|
},
|
|
{
|
|
value: "newer",
|
|
policy: PullPolicyNewer,
|
|
},
|
|
{
|
|
value: "ifnewer",
|
|
policy: PullPolicyNewer,
|
|
},
|
|
{
|
|
value: "NEWER",
|
|
policy: PullPolicyNewer,
|
|
},
|
|
{
|
|
value: "",
|
|
policy: PullPolicyMissing,
|
|
},
|
|
{
|
|
value: "missing",
|
|
policy: PullPolicyMissing,
|
|
},
|
|
{
|
|
value: "MISSING",
|
|
policy: PullPolicyMissing,
|
|
},
|
|
{
|
|
value: "IFMISSING",
|
|
policy: PullPolicyMissing,
|
|
},
|
|
{
|
|
value: "ifnotpresent",
|
|
policy: PullPolicyMissing,
|
|
},
|
|
{
|
|
value: "bogus",
|
|
fail: true,
|
|
},
|
|
} {
|
|
p, err := ParsePullPolicy(test.value)
|
|
if test.fail {
|
|
gomega.Expect(err.Error()).To(gomega.Equal(fmt.Sprintf("unsupported pull policy %q", test.value)))
|
|
} else {
|
|
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
|
gomega.Expect(p).To(gomega.Equal(test.policy))
|
|
}
|
|
}
|
|
})
|
|
})
|