package config import ( "bytes" "io/ioutil" "os" "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() { BeforeEach(beforeEach) Describe("ValidateConfig", func() { It("should succeed with default config", func() { // Given // When defaultConfig, err := NewConfig("") // Then gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(defaultConfig.Containers.ApparmorProfile).To(gomega.Equal(apparmor.Profile)) gomega.Expect(defaultConfig.Containers.BaseHostsFile).To(gomega.Equal("")) gomega.Expect(defaultConfig.Containers.PidsLimit).To(gomega.BeEquivalentTo(2048)) gomega.Expect(defaultConfig.Engine.ServiceTimeout).To(gomega.BeEquivalentTo(5)) gomega.Expect(defaultConfig.NetNS()).To(gomega.BeEquivalentTo("private")) gomega.Expect(defaultConfig.IPCNS()).To(gomega.BeEquivalentTo("shareable")) gomega.Expect(defaultConfig.Engine.InfraImage).To(gomega.BeEquivalentTo("")) path, err := defaultConfig.ImageCopyTmpDir() gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(path).To(gomega.BeEquivalentTo("/var/tmp")) }) It("should succeed with devices", func() { // Given sut.Containers.Devices = []string{ "/dev/null:/dev/null:rw", "/dev/sdc/", "/dev/sdc:/dev/xvdc", "/dev/sdc:rm", } // When err := sut.Containers.Validate() // Then gomega.Expect(err).To(gomega.BeNil()) }) It("should fail wrong max log size", func() { // Given sut.Containers.LogSizeMax = 1 // When err := sut.Validate() // Then gomega.Expect(err).NotTo(gomega.BeNil()) }) It("should succeed with valid shm size", func() { // Given sut.Containers.ShmSize = "1024" // When err := sut.Validate() // Then gomega.Expect(err).To(gomega.BeNil()) // Given sut.Containers.ShmSize = "64m" // When err = sut.Validate() // Then gomega.Expect(err).To(gomega.BeNil()) }) It("should fail wrong shm size", func() { // Given sut.Containers.ShmSize = "-2" // When err := sut.Validate() // Then gomega.Expect(err).NotTo(gomega.BeNil()) }) 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())) }) }) Describe("ValidateNetworkConfig", func() { It("should succeed with default config", func() { // Given // When err := sut.Network.Validate() // Then gomega.Expect(err).To(gomega.BeNil()) }) }) Describe("readStorageTmp", func() { It("test image_copy_tmp_dir='storage'", func() { // Reload from new configuration file testFile := "testdata/temp.conf" content := `[engine] image_copy_tmp_dir="storage"` err := ioutil.WriteFile(testFile, []byte(content), os.ModePerm) // Then gomega.Expect(err).To(gomega.BeNil()) defer os.Remove(testFile) config, _ := NewConfig(testFile) path, err := config.ImageCopyTmpDir() gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(path).To(gomega.ContainSubstring("containers/storage/tmp")) // Given we do oldTMPDIR, set := os.LookupEnv("TMPDIR") os.Setenv("TMPDIR", "/var/tmp/foobar") path, err = config.ImageCopyTmpDir() gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(path).To(gomega.BeEquivalentTo("/var/tmp/foobar")) if set { os.Setenv("TMPDIR", oldTMPDIR) } else { os.Unsetenv("TMPDIR") } }) }) 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.Equal(true)) err := readConfigFromFile("testdata/containers_default.conf", defaultConfig) 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", }, "crun": { "/usr/bin/crun", "/usr/local/bin/crun", }, "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", }, "krun": { "/usr/bin/krun", "/usr/local/bin/krun", }, } pluginDirs := []string{ "/usr/libexec/cni", "/usr/libexec/foo", } envs := []string{ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm", } volumes := []string{ "$HOME:$HOME", } newVolumes := []string{ os.ExpandEnv("$HOME:$HOME"), } helperDirs := []string{ "/somepath", } // Then gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(defaultConfig.Engine.CgroupManager).To(gomega.Equal("systemd")) gomega.Expect(defaultConfig.Containers.Env).To(gomega.BeEquivalentTo(envs)) gomega.Expect(defaultConfig.Containers.PidsLimit).To(gomega.BeEquivalentTo(2048)) gomega.Expect(defaultConfig.Network.CNIPluginDirs).To(gomega.Equal(pluginDirs)) gomega.Expect(defaultConfig.Engine.NumLocks).To(gomega.BeEquivalentTo(2048)) gomega.Expect(defaultConfig.Engine.OCIRuntimes).To(gomega.Equal(OCIRuntimeMap)) gomega.Expect(defaultConfig.Containers.HTTPProxy).To(gomega.Equal(false)) gomega.Expect(defaultConfig.Engine.NetworkCmdOptions).To(gomega.BeNil()) gomega.Expect(defaultConfig.Engine.HelperBinariesDir).To(gomega.Equal(helperDirs)) gomega.Expect(defaultConfig.Engine.ServiceTimeout).To(gomega.BeEquivalentTo(300)) gomega.Expect(defaultConfig.Engine.InfraImage).To(gomega.BeEquivalentTo("k8s.gcr.io/pause:3.4.1")) gomega.Expect(defaultConfig.Machine.Volumes).To(gomega.BeEquivalentTo(volumes)) newV, err := defaultConfig.MachineVolumes() if newVolumes[0] == ":" { // $HOME is not set gomega.Expect(err).To(gomega.HaveOccurred()) } else { gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(newV).To(gomega.BeEquivalentTo(newVolumes)) } }) It("test GetDefaultEnvEx", func() { envs := []string{ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm", } httpEnvs := append([]string{"HTTP_PROXY=1.2.3.4"}, envs...) oldProxy, proxyEnvSet := os.LookupEnv("HTTP_PROXY") os.Setenv("HTTP_PROXY", "1.2.3.4") oldFoo, fooEnvSet := os.LookupEnv("foo") os.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")) // Undo that if proxyEnvSet { os.Setenv("HTTP_PROXY", oldProxy) } else { os.Unsetenv("HTTP_PROXY") } if fooEnvSet { os.Setenv("foo", oldFoo) } else { os.Unsetenv("foo") } }) It("should succeed with commented out configuration", func() { // Given // When conf := Config{} err := readConfigFromFile("testdata/containers_comment.conf", &conf) // Then gomega.Expect(err).To(gomega.BeNil()) }) It("should fail when file does not exist", func() { // Given // When conf := Config{} err := readConfigFromFile("/invalid/file", &conf) // Then gomega.Expect(err).NotTo(gomega.BeNil()) }) It("should fail when toml decode fails", func() { // Given // When conf := Config{} err := readConfigFromFile("config.go", &conf) // Then gomega.Expect(err).NotTo(gomega.BeNil()) }) }) 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", }, } envs := []string{ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm", } // Given we do oldContainersConf, envSet := os.LookupEnv("CONTAINERS_CONF") os.Setenv("CONTAINERS_CONF", "/dev/null") // When config, err := NewConfig("") // Undo that if envSet { os.Setenv("CONTAINERS_CONF", oldContainersConf) } else { os.Unsetenv("CONTAINERS_CONF") } // Then gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(config.Containers.ApparmorProfile).To(gomega.Equal(apparmor.Profile)) gomega.Expect(config.Containers.PidsLimit).To(gomega.BeEquivalentTo(2048)) gomega.Expect(config.Containers.Env).To(gomega.BeEquivalentTo(envs)) gomega.Expect(config.Containers.UserNS).To(gomega.BeEquivalentTo("")) gomega.Expect(config.Network.CNIPluginDirs).To(gomega.Equal(DefaultCNIPluginDirs)) gomega.Expect(config.Engine.NumLocks).To(gomega.BeEquivalentTo(2048)) gomega.Expect(config.Engine.OCIRuntimes["runc"]).To(gomega.Equal(OCIRuntimeMap["runc"])) 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(config.Engine.TmpDir + "/events/events.log")) gomega.Expect(uint64(config.Engine.EventsLogFileMaxSize)).To(gomega.Equal(DefaultEventsLogSizeMax)) gomega.Expect(config.Engine.PodExitPolicy).To(gomega.Equal(PodExitPolicyContinue)) }) It("should success with valid user file path", func() { // Given // When config, err := NewConfig("testdata/containers_default.conf") // Then gomega.Expect(err).To(gomega.BeNil()) 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")) }) It("contents of passed-in file should override others", func() { // Given we do oldContainersConf, envSet := os.LookupEnv("CONTAINERS_CONF") os.Setenv("CONTAINERS_CONF", "containers.conf") // When config, err := NewConfig("testdata/containers_override.conf") // Undo that if envSet { os.Setenv("CONTAINERS_CONF", oldContainersConf) } else { os.Unsetenv("CONTAINERS_CONF") } // Then gomega.Expect(err).To(gomega.BeNil()) 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.Engine.ImageParallelCopies).To(gomega.Equal(uint(10))) gomega.Expect(config.Engine.ImageDefaultFormat).To(gomega.Equal("v2s2")) gomega.Expect(config.Engine.EventsLogFilePath).To(gomega.BeEquivalentTo("/tmp/events.log")) path, err := config.ImageCopyTmpDir() gomega.Expect(err).To(gomega.BeNil()) 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).ToNot(gomega.BeNil()) gomega.Expect(config).To(gomega.BeNil()) }) It("Test Capabilities call", func() { // Given // When config, err := NewConfig("") // Then gomega.Expect(err).To(gomega.BeNil()) var addcaps, dropcaps []string caps, err := config.Capabilities("0", addcaps, dropcaps) gomega.Expect(err).To(gomega.BeNil()) sort.Strings(caps) defaultCaps := config.Containers.DefaultCapabilities 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).To(gomega.BeNil()) sort.Strings(caps) boundingSet, err := capabilities.BoundingSet() gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(caps).To(gomega.BeEquivalentTo(boundingSet)) // Drop all caps dropcaps = []string{"all"} caps, err = config.Capabilities("", boundingSet, dropcaps) gomega.Expect(err).To(gomega.BeNil()) sort.Strings(caps) gomega.Expect(caps).ToNot(gomega.BeEquivalentTo([]string{})) config.Containers.DefaultCapabilities = []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).To(gomega.BeNil()) 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).To(gomega.BeNil()) 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).To(gomega.BeNil()) sort.Strings(caps) gomega.Expect(caps).To(gomega.BeEquivalentTo(expectedCaps)) }) It("should succeed with default pull_policy", func() { err := sut.Engine.Validate() gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(sut.Engine.PullPolicy).To(gomega.Equal("missing")) sut.Engine.PullPolicy = DefaultPullPolicy err = sut.Engine.Validate() gomega.Expect(err).To(gomega.BeNil()) }) It("should succeed case-insensitive", func() { sut.Engine.PullPolicy = "NeVer" err := sut.Engine.Validate() gomega.Expect(err).To(gomega.BeNil()) }) It("should fail with invalid pull_policy", func() { sut.Engine.PullPolicy = "invalidPullPolicy" err := sut.Engine.Validate() gomega.Expect(err).ToNot(gomega.BeNil()) }) }) Describe("Service Destinations", func() { ConfPath := struct { Value string IsSet bool }{} BeforeEach(func() { ConfPath.Value, ConfPath.IsSet = os.LookupEnv("CONTAINERS_CONF") conf, _ := ioutil.TempFile("", "containersconf") os.Setenv("CONTAINERS_CONF", conf.Name()) }) AfterEach(func() { os.Remove(os.Getenv("CONTAINERS_CONF")) if ConfPath.IsSet { os.Setenv("CONTAINERS_CONF", ConfPath.Value) } else { os.Unsetenv("CONTAINERS_CONF") } }) It("succeed to set and read", func() { cfg, err := ReadCustomConfig() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) cfg.Engine.ActiveService = "QA" cfg.Engine.ServiceDestinations = map[string]Destination{ "QA": { URI: "https://qa/run/podman/podman.sock", Identity: "/.ssh/id_rsa", }, } err = cfg.Write() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) // test that we do not write zero values to the file path, err := customConfigFile() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) f, err := os.Open(path) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) data, err := ioutil.ReadAll(f) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) gomega.Expect(string(data)).ShouldNot(gomega.ContainSubstring("cpus")) gomega.Expect(string(data)).ShouldNot(gomega.ContainSubstring("disk_size")) gomega.Expect(string(data)).ShouldNot(gomega.ContainSubstring("memory")) cfg, err = ReadCustomConfig() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) gomega.Expect(cfg.Engine.ActiveService, "QA") gomega.Expect(cfg.Engine.ServiceDestinations["QA"].URI, "https://qa/run/podman/podman.sock") gomega.Expect(cfg.Engine.ServiceDestinations["QA"].Identity, "/.ssh/id_rsa") }) It("succeed ActiveDestinations()", func() { cfg, err := ReadCustomConfig() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) cfg.Engine.ActiveService = "QA" cfg.Engine.ServiceDestinations = map[string]Destination{ "QB": { URI: "https://qb/run/podman/podman.sock", Identity: "/.ssh/qb_id_rsa", }, "QA": { URI: "https://qa/run/podman/podman.sock", Identity: "/.ssh/id_rsa", }, } err = cfg.Write() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) cfg, err = ReadCustomConfig() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) u, i, err := cfg.ActiveDestination() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) gomega.Expect(u).To(gomega.Equal("https://qa/run/podman/podman.sock")) gomega.Expect(i).To(gomega.Equal("/.ssh/id_rsa")) }) It("succeed ActiveDestinations() CONTAINER_CONNECTION environment", func() { cfg, err := ReadCustomConfig() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) cfg.Engine.ActiveService = "QA" cfg.Engine.ServiceDestinations = map[string]Destination{ "QA": { URI: "https://qa/run/podman/podman.sock", Identity: "/.ssh/id_rsa", }, "QB": { URI: "https://qb/run/podman/podman.sock", Identity: "/.ssh/qb_id_rsa", }, } err = cfg.Write() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) cfg, err = ReadCustomConfig() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) // Given we do oldContainerConnection, hostEnvSet := os.LookupEnv("CONTAINER_CONNECTION") os.Setenv("CONTAINER_CONNECTION", "QB") u, i, err := cfg.ActiveDestination() // Undo that if hostEnvSet { os.Setenv("CONTAINER_CONNECTION", oldContainerConnection) } else { os.Unsetenv("CONTAINER_CONNECTION") } gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) gomega.Expect(u).To(gomega.Equal("https://qb/run/podman/podman.sock")) gomega.Expect(i).To(gomega.Equal("/.ssh/qb_id_rsa")) }) It("succeed ActiveDestinations CONTAINER_HOST ()", func() { cfg, err := ReadCustomConfig() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) cfg.Engine.ActiveService = "QA" cfg.Engine.ServiceDestinations = map[string]Destination{ "QB": { URI: "https://qb/run/podman/podman.sock", Identity: "/.ssh/qb_id_rsa", }, "QA": { URI: "https://qa/run/podman/podman.sock", Identity: "/.ssh/id_rsa", }, } err = cfg.Write() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) cfg, err = ReadCustomConfig() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) // Given we do oldContainerHost, hostEnvSet := os.LookupEnv("CONTAINER_HOST") oldContainerSSH, sshEnvSet := os.LookupEnv("CONTAINER_SSHKEY") os.Setenv("CONTAINER_HOST", "foo.bar") os.Setenv("CONTAINER_SSHKEY", "/.ssh/newid_rsa") u, i, err := cfg.ActiveDestination() // Undo that if hostEnvSet { os.Setenv("CONTAINER_HOST", oldContainerHost) } else { os.Unsetenv("CONTAINER_HOST") } // Undo that if sshEnvSet { os.Setenv("CONTAINER_SSHKEY", oldContainerSSH) } else { os.Unsetenv("CONTAINER_SSHKEY") } gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) gomega.Expect(u).To(gomega.Equal("foo.bar")) gomega.Expect(i).To(gomega.Equal("/.ssh/newid_rsa")) }) It("fail ActiveDestination() no configuration", func() { cfg, err := ReadCustomConfig() gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) _, _, err = cfg.ActiveDestination() gomega.Expect(err).Should(gomega.HaveOccurred()) }) It("test addConfigs", func() { tmpFilePath := func(dir, prefix string) string { file, err := ioutil.TempFile(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)) dir, err := ioutil.TempDir("", "configTest") gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) defer os.RemoveAll(dir) 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 _, err = ioutil.TempFile(dir, "notconf") gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) subdir, err := ioutil.TempDir(dir, "") gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) // create a file in subdir, to make sure it does not // show up in configs _, err = ioutil.TempFile(subdir, "") gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) 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) gomega.Expect(err).To(gomega.BeNil()) 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) gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(content.String()).To(gomega.Equal("")) logrus.SetOutput(os.Stderr) }) }) Describe("Reload", func() { It("test new config from reload", func() { // Default configuration defaultTestFile := "testdata/containers_default.conf" oldEnv, set := os.LookupEnv("CONTAINERS_CONF") os.Setenv("CONTAINERS_CONF", defaultTestFile) cfg, err := Default() gomega.Expect(err).To(gomega.BeNil()) if set { os.Setenv("CONTAINERS_CONF", oldEnv) } else { os.Unsetenv("CONTAINERS_CONF") } // Reload from new configuration file testFile := "testdata/temp.conf" content := `[containers] env=["foo=bar"]` err = ioutil.WriteFile(testFile, []byte(content), os.ModePerm) defer os.Remove(testFile) gomega.Expect(err).To(gomega.BeNil()) oldEnv, set = os.LookupEnv("CONTAINERS_CONF") os.Setenv("CONTAINERS_CONF", testFile) _, err = Reload() gomega.Expect(err).To(gomega.BeNil()) newCfg, err := Default() gomega.Expect(err).To(gomega.BeNil()) if set { os.Setenv("CONTAINERS_CONF", oldEnv) } else { os.Unsetenv("CONTAINERS_CONF") } expectOldEnv := []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm"} expectNewEnv := []string{"foo=bar"} gomega.Expect(cfg.Containers.Env).To(gomega.Equal(expectOldEnv)) gomega.Expect(newCfg.Containers.Env).To(gomega.Equal(expectNewEnv)) // Reload change back to default global configuration _, err = Reload() gomega.Expect(err).To(gomega.BeNil()) }) }) It("write default config should be empty", func() { defer os.Unsetenv("CONTAINERS_CONF") os.Setenv("CONTAINERS_CONF", "/dev/null") conf, err := ReadCustomConfig() gomega.Expect(err).ToNot(gomega.HaveOccurred()) f, err := ioutil.TempFile("", "container-common-test") gomega.Expect(err).ToNot(gomega.HaveOccurred()) defer f.Close() defer os.Remove(f.Name()) os.Setenv("CONTAINERS_CONF", f.Name()) err = conf.Write() gomega.Expect(err).ToNot(gomega.HaveOccurred()) b, err := ioutil.ReadFile(f.Name()) gomega.Expect(err).ToNot(gomega.HaveOccurred()) // config should only contain empty stanzas gomega.Expect(string(b)).To(gomega. Equal("[containers]\n\n[engine]\n\n[machine]\n\n[network]\n\n[secrets]\n\n[configmaps]\n")) }) })