Files
podman/test/e2e/containers_conf_test.go
George Joseph 6fa234a5de Pass container hostname to netavark
Passing the hostname allows netavark to include it in DHCP lease
requests which, in an environment where DDNS is used, can cause
DNS entries to be created automatically.

* The current Hostname() function in container.go was updated to
check the new `container_name_as_hostname` option in the
CONTAINERS table of containers.conf.  If set and no hostname
was configured for the container, it causes the hostname to be
set to a version of the container's name with the characters not
valid for a hostname removed.  If not set (the default), the original
behavior of setting the hostname to the short container ID is
preserved.

* Because the Hostname() function can return the host's hostname
if the container isn't running in a private UTS namespace, and we'd
NEVER want to send _that_ in a DHCP request for a container, a new
function NetworkHostname() was added which functions like Hostname()
except that it will return an empty string instead of the host's
hostname if the container is not running in a private UTS namespace.

* networking_common.getNetworkOptions() now uses NetworkHostname()
to set the ContainerHostname member of the NetworkOptions structure.
That member was added to the structure in a corresponding commit in
common/libnetwork/types/network.go.

* Added test to containers_conf_test.go

Signed-off-by: George Joseph <g.devel@wxy78.net>
2025-01-06 07:09:12 -07:00

872 lines
33 KiB
Go

//go:build linux || freebsd
package integration
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/containers/podman/v5/libpod/define"
. "github.com/containers/podman/v5/test/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gbytes"
. "github.com/onsi/gomega/gexec"
)
var _ = Describe("Verify podman containers.conf usage", func() {
BeforeEach(func() {
confPath, err := filepath.Abs("config/containers.conf")
Expect(err).ToNot(HaveOccurred())
os.Setenv("CONTAINERS_CONF", confPath)
if IsRemote() {
podmanTest.RestartRemoteService()
}
})
It("limits test", func() {
SkipIfRootlessCgroupsV1("Setting limits not supported on cgroupv1 for rootless users")
// containers.conf is set to "nofile=500:500"
session := podmanTest.Podman([]string{"run", "--rm", fedoraMinimal, "ulimit", "-n"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("500"))
session = podmanTest.Podman([]string{"run", "--rm", "--ulimit", "nofile=2048:2048", fedoraMinimal, "ulimit", "-n"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("2048"))
// Reset CONTAINERS_CONF to "/dev/null"
// Local should go back to defaults but remote should be set on server side
os.Setenv("CONTAINERS_CONF", "/dev/null")
session = podmanTest.Podman([]string{"run", "--rm", fedoraMinimal, "ulimit", "-n"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
if IsRemote() {
Expect(session.OutputToString()).To(ContainSubstring("500"))
} else {
Expect(session.OutputToString()).To(Not(Equal("500")))
}
})
It("oom-score-adj", func() {
SkipIfRootlessCgroupsV1("Setting limits not supported on cgroupv1 for rootless users")
// containers.conf is set to "oom_score_adj=999"
session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/proc/self/oom_score_adj"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("999"))
raw, err := os.ReadFile("/proc/self/oom_score_adj")
Expect(err).ToNot(HaveOccurred())
rawS := strings.TrimSuffix(string(raw), "\n")
// Reset CONTAINERS_CONF to "/dev/null"
// Local should go back to defaults but remote should be set on server side
os.Setenv("CONTAINERS_CONF", "/dev/null")
session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/proc/self/oom_score_adj"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
if IsRemote() {
Expect(session.OutputToString()).To(Equal("999"))
} else {
if isRootless() {
Expect(session.OutputToString()).To(ContainSubstring(rawS))
} else {
Expect(session.OutputToString()).To(ContainSubstring("0"))
}
}
})
It("cgroup_conf in containers.conf", func() {
if isCgroupsV1() {
Skip("Setting cgroup_confs not supported on cgroupv1")
}
// FIXME: Needs crun-1.8.2-2 to allow this with --cgroup-manager=cgroupfs, once this is available remove the skip below.
SkipIfRootless("--cgroup-manager=cgoupfs and --cgroup-conf not supported in rootless mode with crun")
conffile := filepath.Join(podmanTest.TempDir, "container.conf")
err := os.WriteFile(conffile, []byte("[containers]\ncgroup_conf = [\"pids.max=1234\",]\n"), 0755)
Expect(err).ToNot(HaveOccurred())
os.Setenv("CONTAINERS_CONF_OVERRIDE", conffile)
if IsRemote() {
podmanTest.RestartRemoteService()
}
// containers.conf is set to "pids.max=1234"
session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/sys/fs/cgroup/pids.max"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("1234"))
session = podmanTest.Podman([]string{"run", "--rm", "--cgroup-conf", "pids.max=400", ALPINE, "cat", "/sys/fs/cgroup/pids.max"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("400"))
})
It("having additional env", func() {
// containers.conf default env includes foo
session := podmanTest.Podman([]string{"run", ALPINE, "printenv"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("foo=bar"))
})
It("additional devices", func() {
// containers.conf devices includes notone
session := podmanTest.Podman([]string{"run", "--device", "/dev/null:/dev/bar", ALPINE, "ls", "/dev"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(
And(
ContainSubstring("bar"),
ContainSubstring("notone"),
))
})
It("shm-size", func() {
// containers.conf default sets shm-size=201k, which ends up as 200k
session := podmanTest.Podman([]string{"run", ALPINE, "grep", "shm", "/proc/self/mounts"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("size=200k"))
session = podmanTest.Podman([]string{"run", "--shm-size", "1g", ALPINE, "grep", "shm", "/proc/self/mounts"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("size=1048576k"))
})
It("add capabilities", func() {
SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
cap := podmanTest.Podman([]string{"run", ALPINE, "grep", "CapEff", "/proc/self/status"})
cap.WaitWithDefaultTimeout()
Expect(cap).Should(ExitCleanly())
os.Setenv("CONTAINERS_CONF", "config/containers-ns.conf")
if IsRemote() {
podmanTest.RestartRemoteService()
}
session := podmanTest.Podman([]string{"run", BB, "grep", "CapEff", "/proc/self/status"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).ToNot(Equal(cap.OutputToString()))
})
It("regular capabilities", func() {
setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout()
result := podmanTest.Podman([]string{"top", "test1", "capeff"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
Expect(result.OutputToString()).To(
And(
ContainSubstring("FOWNER"),
ContainSubstring("SETFCAP"),
))
})
It("drop capabilities", func() {
os.Setenv("CONTAINERS_CONF", "config/containers-caps.conf")
if IsRemote() {
podmanTest.RestartRemoteService()
}
setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout()
result := podmanTest.Podman([]string{"container", "top", "test1", "capeff"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
Expect(result.OutputToString()).ToNot(
And(
ContainSubstring("SETUID"),
ContainSubstring("FOWNER"),
))
})
verifyNSHandling := func(nspath, option string) {
SkipIfRootlessCgroupsV1("Not supported for rootless + CgroupsV1")
os.Setenv("CONTAINERS_CONF", "config/containers-ns.conf")
if IsRemote() {
podmanTest.RestartRemoteService()
}
// containers.conf default ipcns to default to host
session := podmanTest.Podman([]string{"run", ALPINE, "ls", "-l", nspath})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
fields := strings.Split(session.OutputToString(), " ")
ctrNS := strings.TrimSuffix(fields[len(fields)-1], "\n")
cmd := exec.Command("ls", "-l", nspath)
res, err := cmd.Output()
Expect(err).ToNot(HaveOccurred())
fields = strings.Split(string(res), " ")
hostNS := strings.TrimSuffix(fields[len(fields)-1], "\n")
Expect(hostNS).To(Equal(ctrNS))
session = podmanTest.Podman([]string{"run", option, "private", ALPINE, "ls", "-l", nspath})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
fields = strings.Split(session.OutputToString(), " ")
ctrNS = fields[len(fields)-1]
Expect(hostNS).ToNot(Equal(ctrNS))
}
It("netns", func() {
verifyNSHandling("/proc/self/ns/net", "--network")
})
It("ipcns", func() {
verifyNSHandling("/proc/self/ns/ipc", "--ipc")
})
It("utsns", func() {
verifyNSHandling("/proc/self/ns/uts", "--uts")
})
It("pidns", func() {
verifyNSHandling("/proc/self/ns/pid", "--pid")
})
It("cgroupns", func() {
verifyNSHandling("/proc/self/ns/cgroup", "--cgroupns")
})
It("using journald for container with container log_tag", func() {
SkipIfJournaldUnavailable()
os.Setenv("CONTAINERS_CONF", "config/containers-journald.conf")
if IsRemote() {
podmanTest.RestartRemoteService()
}
logc := podmanTest.Podman([]string{"run", "-d", ALPINE, "sh", "-c", "echo podman; sleep 0.1; echo podman; sleep 0.1; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).Should(ExitCleanly())
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).Should(ExitCleanly())
// Flake prevention: journalctl makes no timeliness guarantees.
time.Sleep(1 * time.Second)
cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_TAG", fmt.Sprintf("CONTAINER_ID_FULL=%s", cid))
out, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred())
Expect(out).To(ContainSubstring("alpine"))
})
It("add volumes", func() {
conffile := filepath.Join(podmanTest.TempDir, "container.conf")
volume := filepath.Join(podmanTest.TempDir, "vol")
err = os.MkdirAll(volume, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
err := os.WriteFile(conffile, []byte(fmt.Sprintf("[containers]\nvolumes=[\"%s:%s:Z\",]\n", volume, volume)), 0755)
Expect(err).ToNot(HaveOccurred())
os.Setenv("CONTAINERS_CONF", conffile)
if IsRemote() {
podmanTest.RestartRemoteService()
}
result := podmanTest.Podman([]string{"run", ALPINE, "ls", volume})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
})
It("sysctl test", func() {
// containers.conf is set to "net.ipv4.ping_group_range=0 1000"
session := podmanTest.Podman([]string{"run", "--rm", fedoraMinimal, "cat", "/proc/sys/net/ipv4/ping_group_range"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("1000"))
// Ignore containers.conf setting if --net=host
session = podmanTest.Podman([]string{"run", "--rm", "--net", "host", fedoraMinimal, "cat", "/proc/sys/net/ipv4/ping_group_range"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).ToNot(ContainSubstring("1000"))
})
It("search domain", func() {
session := podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToStringArray()).To(ContainElement(HavePrefix("search foobar.com")))
})
It("add dns server", func() {
session := podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToStringArray()).To(ContainElement(HavePrefix("nameserver 1.2.3.4")))
})
It("add dns option", func() {
session := podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToStringArray()).To(ContainElement(HavePrefix("options debug")))
})
It("remove all search domain", func() {
session := podmanTest.Podman([]string{"run", "--dns-search=.", ALPINE, "cat", "/etc/resolv.conf"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToStringArray()).To(Not(ContainElement(HavePrefix("search"))))
})
It("add search domain", func() {
session := podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToStringArray()).To(ContainElement(HavePrefix("search")))
Expect(session.OutputToString()).To(
And(
ContainSubstring("foobar.com"),
ContainSubstring("1.2.3.4"),
ContainSubstring("debug"),
))
})
It("add timezone", func() {
// containers.conf timezone set to Pacific/Honolulu
session := podmanTest.Podman([]string{"run", "--tz", "", ALPINE, "date", "+'%H %Z'"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("HST"))
// verify flag still overrides
// Arizona does not observe DST so this command is safe at all times of the year
session = podmanTest.Podman([]string{"run", "--tz", "America/Phoenix", ALPINE, "date", "+'%H %Z'"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("MST"))
})
It("add umask", func() {
// containers.conf umask set to 0002
if !strings.Contains(podmanTest.OCIRuntime, "crun") {
Skip("Test only works on crun")
}
session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "sh", "-c", "umask"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("0002"))
})
It("network slirp options to allow host loopback", func() {
session := podmanTest.Podman([]string{"run", "--network", "slirp4netns", ALPINE, "ping", "-c1", "10.0.2.2"})
session.Wait(30)
Expect(session).Should(ExitCleanly())
})
It("podman-remote test localcontainers.conf", func() {
SkipIfNotRemote("this test is only for remote")
os.Setenv("CONTAINERS_CONF", "config/containers-remote.conf")
// Configuration that comes from remote server
// env
session := podmanTest.Podman([]string{"run", ALPINE, "printenv", "foo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("bar"))
// dns-search, server, options
session = podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToStringArray()).To(ContainElement(HavePrefix("search")))
Expect(session.OutputToString()).To(
And(
ContainSubstring("foobar.com"),
ContainSubstring("1.2.3.4"),
ContainSubstring("debug"),
))
// sysctls
session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/proc/sys/net/ipv4/ping_group_range"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("1000"))
// shm-size
session = podmanTest.Podman([]string{"run", ALPINE, "grep", "shm", "/proc/self/mounts"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("size=200k"))
// ulimits
session = podmanTest.Podman([]string{"run", "--rm", fedoraMinimal, "ulimit", "-n"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("500"))
// Configuration that comes from remote client
// Timezone
session = podmanTest.Podman([]string{"run", ALPINE, "date", "+'%H %Z'"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(
Or(
ContainSubstring("EST"),
ContainSubstring("EDT"),
))
// Umask
session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "sh", "-c", "umask"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("0022"))
})
It("add annotations", func() {
// containers.conf is set to "run.oci.keep_original_groups=1"
session := podmanTest.Podman([]string{"create", "--rm", "--name", "test", fedoraMinimal})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
inspect := podmanTest.Podman([]string{"inspect", "--format", "{{ .Config.Annotations }}", "test"})
inspect.WaitWithDefaultTimeout()
Expect(inspect.OutputToString()).To(ContainSubstring(fmt.Sprintf("%s:1", define.RunOCIKeepOriginalGroups)))
})
It("--add-host and no-hosts=true fails", func() {
session := podmanTest.Podman([]string{"run", "-dt", "--add-host", "test1:127.0.0.1", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError(125, "--no-hosts and --add-host cannot be set together"))
session = podmanTest.Podman([]string{"run", "-dt", "--add-host", "test1:127.0.0.1", "--no-hosts=false", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
It("no-hosts=true /etc/hosts does not include hostname", func() {
session := podmanTest.Podman([]string{"run", "--rm", "--name", "test", ALPINE, "cat", "/etc/hosts"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).ToNot(ContainSubstring("test"))
session = podmanTest.Podman([]string{"run", "--rm", "--name", "test", "--no-hosts=false", ALPINE, "cat", "/etc/hosts"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring("test"))
})
Describe("base_hosts_file in containers.conf", func() {
var baseHostsFile string
var session *PodmanSessionIntegration
JustBeforeEach(func() {
conffile := filepath.Join(podmanTest.TempDir, "containers.conf")
err = os.WriteFile(conffile, []byte(fmt.Sprintf("[containers]\nbase_hosts_file=\"%s\"\nno_hosts=false\n", baseHostsFile)), 0755)
Expect(err).ToNot(HaveOccurred())
os.Setenv("CONTAINERS_CONF_OVERRIDE", conffile)
if IsRemote() {
podmanTest.RestartRemoteService()
}
dockerfile := strings.Join([]string{
`FROM quay.io/libpod/alpine:latest`,
`RUN echo '56.78.12.34 image.example.com' > /etc/hosts`,
}, "\n")
podmanTest.BuildImage(dockerfile, "foobar.com/hosts_test:latest", "false", "--no-hosts")
session = podmanTest.Podman([]string{"run", "--name", "hosts_test", "--hostname", "hosts_test.dev", "--rm", "foobar.com/hosts_test:latest", "cat", "/etc/hosts"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
})
Describe("base_hosts_file=path", func() {
BeforeEach(func() {
hostsPath := filepath.Join(podmanTest.TempDir, "hosts")
err := os.WriteFile(hostsPath, []byte("12.34.56.78 file.example.com"), 0755)
Expect(err).ToNot(HaveOccurred())
baseHostsFile = hostsPath
})
It("should use the hosts file from the file path", func() {
Expect(session.OutputToString()).ToNot(ContainSubstring("56.78.12.34 image.example.com"))
Expect(session.OutputToString()).To(ContainSubstring("12.34.56.78 file.example.com"))
Expect(session.OutputToString()).To(ContainSubstring("127.0.0.1 localhost"))
Expect(session.OutputToString()).To(ContainSubstring("::1 localhost"))
Expect(session.OutputToString()).To(ContainSubstring("host.containers.internal host.docker.internal"))
Expect(session.OutputToString()).To(ContainSubstring("hosts_test.dev hosts_test"))
})
})
Describe("base_hosts_file=image", func() {
BeforeEach(func() {
baseHostsFile = "image"
})
It("should use the hosts file from the container image", func() {
Expect(session.OutputToString()).To(ContainSubstring("56.78.12.34 image.example.com"))
Expect(session.OutputToString()).ToNot(ContainSubstring("12.34.56.78 file.example.com"))
Expect(session.OutputToString()).To(ContainSubstring("127.0.0.1 localhost"))
Expect(session.OutputToString()).To(ContainSubstring("::1 localhost"))
Expect(session.OutputToString()).To(ContainSubstring("host.containers.internal host.docker.internal"))
Expect(session.OutputToString()).To(ContainSubstring("hosts_test.dev hosts_test"))
})
})
Describe("base_hosts_file=none", func() {
BeforeEach(func() {
baseHostsFile = "none"
})
It("should not use any hosts files", func() {
Expect(session.OutputToString()).ToNot(ContainSubstring("56.78.12.34 image.example.com"))
Expect(session.OutputToString()).ToNot(ContainSubstring("12.34.56.78 file.example.com"))
Expect(session.OutputToString()).To(ContainSubstring("127.0.0.1 localhost"))
Expect(session.OutputToString()).To(ContainSubstring("::1 localhost"))
Expect(session.OutputToString()).To(ContainSubstring("host.containers.internal host.docker.internal"))
Expect(session.OutputToString()).To(ContainSubstring("hosts_test.dev hosts_test"))
})
})
})
It("seccomp profile path", func() {
configPath := filepath.Join(podmanTest.TempDir, "containers.conf")
os.Setenv("CONTAINERS_CONF", configPath)
profile := filepath.Join(podmanTest.TempDir, "seccomp.json")
containersConf := []byte(fmt.Sprintf("[containers]\nseccomp_profile=\"%s\"", profile))
err = os.WriteFile(configPath, containersConf, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
if IsRemote() {
podmanTest.RestartRemoteService()
}
session := podmanTest.Podman([]string{"info", "--format", "{{.Host.Security.SECCOMPProfilePath}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal(profile))
})
It("add image_copy_tmp_dir", func() {
// Prevents overwriting of TMPDIR environment
if cacheDir, found := os.LookupEnv("TMPDIR"); found {
defer os.Setenv("TMPDIR", cacheDir)
os.Unsetenv("TMPDIR")
} else {
defer os.Unsetenv("TMPDIR")
}
if IsRemote() {
podmanTest.RestartRemoteService()
}
session := podmanTest.Podman([]string{"info", "--format", "{{.Store.ImageCopyTmpDir}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("/var/tmp"))
storagePath := filepath.Join(podmanTest.TempDir, "storage")
configPath := filepath.Join(podmanTest.TempDir, "containers.conf")
os.Setenv("CONTAINERS_CONF", configPath)
containersConf := []byte("[engine]\nimage_copy_tmp_dir=\"/foobar\"")
err = os.WriteFile(configPath, containersConf, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
if IsRemote() {
podmanTest.RestartRemoteService()
}
session = podmanTest.Podman([]string{"info", "--format", "{{.Store.ImageCopyTmpDir}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("/foobar"))
containersConf = []byte(fmt.Sprintf("[engine]\nimage_copy_tmp_dir=%q", storagePath))
err = os.WriteFile(configPath, containersConf, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
if IsRemote() {
podmanTest.RestartRemoteService()
}
session = podmanTest.Podman([]string{"info", "--format", "{{.Store.ImageCopyTmpDir}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(ContainSubstring(storagePath))
containersConf = []byte("[engine]\nimage_copy_tmp_dir=\"storage1\"")
err = os.WriteFile(configPath, containersConf, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
if !IsRemote() {
session = podmanTest.Podman([]string{"info", "--format", "{{.Store.ImageCopyTmpDir}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitWithError(125, `invalid image_copy_tmp_dir value "storage1" (relative paths are not accepted)`))
os.Setenv("TMPDIR", "/hoge")
session = podmanTest.Podman([]string{"info", "--format", "{{.Store.ImageCopyTmpDir}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("/hoge"))
os.Unsetenv("TMPDIR")
}
})
// FIXME not sure why this is here
It("system service --help shows (default 20)", func() {
SkipIfRemote("system service is not supported on clients")
result := podmanTest.Podman([]string{"system", "service", "--help"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
Expect(result.OutputToString()).To(ContainSubstring("(default 1234)"))
})
It("bad infra_image name", func() {
infra1 := "i.do/not/exist:image"
infra2 := "i.still.do/not/exist:image"
errorString := "initializing source docker://" + infra1
error2String := "initializing source docker://" + infra2
configPath := filepath.Join(podmanTest.TempDir, "containers.conf")
os.Setenv("CONTAINERS_CONF", configPath)
containersConf := []byte("[engine]\ninfra_image=\"" + infra1 + "\"")
err = os.WriteFile(configPath, containersConf, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
if IsRemote() {
podmanTest.RestartRemoteService()
}
result := podmanTest.Podman([]string{"pod", "create", "--infra-image", infra2})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitWithError(125, error2String))
result = podmanTest.Podman([]string{"pod", "create"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitWithError(125, errorString))
result = podmanTest.Podman([]string{"create", "--pod", "new:pod1", ALPINE})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitWithError(125, errorString))
})
It("set .engine.remote=true", func() {
SkipIfRemote("only meaningful when running ABI/local")
// Need to restore CONTAINERS_CONF or AfterEach() will fail
if path, found := os.LookupEnv("CONTAINERS_CONF"); found {
defer os.Setenv("CONTAINERS_CONF", path)
}
configPath := filepath.Join(podmanTest.TempDir, "containers-engine-remote.conf")
os.Setenv("CONTAINERS_CONF", configPath)
defer os.Remove(configPath)
err := os.WriteFile(configPath, []byte("[engine]\nremote=true"), os.ModePerm)
Expect(err).ToNot(HaveOccurred())
// podmanTest.Podman() cannot be used as it was initialized remote==false
cmd := exec.Command(podmanTest.PodmanBinary, "info", "--format", "{{.Host.ServiceIsRemote}}")
session, err := Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
description := "Should have failed as there is no running remote API service available."
Eventually(session, DefaultWaitTimeout).Should(Exit(125), description)
Expect(session.Err).Should(Say("Error: unable to connect to Podman socket"))
})
It("podman containers.conf cgroups=disabled", func() {
if !strings.Contains(podmanTest.OCIRuntime, "crun") {
// Assume this will never be fixed in runc
Skip("NoCgroups requires crun")
}
conffile := filepath.Join(podmanTest.TempDir, "container.conf")
err := os.WriteFile(conffile, []byte("[containers]\ncgroups=\"disabled\"\n"), 0755)
Expect(err).ToNot(HaveOccurred())
result := podmanTest.Podman([]string{"create", ALPINE, "true"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
inspect := podmanTest.Podman([]string{"inspect", "--format", "{{ .HostConfig.Cgroups }}", result.OutputToString()})
inspect.WaitWithDefaultTimeout()
Expect(inspect.OutputToString()).ToNot(Equal("disabled"))
os.Setenv("CONTAINERS_CONF", conffile)
if IsRemote() {
podmanTest.RestartRemoteService()
}
result = podmanTest.Podman([]string{"create", ALPINE, "true"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
inspect = podmanTest.Podman([]string{"inspect", "--format", "{{ .HostConfig.Cgroups }}", result.OutputToString()})
inspect.WaitWithDefaultTimeout()
Expect(inspect.OutputToString()).To(Equal("disabled"))
// Check we can also create a pod when cgroups=disabled
result = podmanTest.Podman([]string{"pod", "create"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
})
It("podman containers.conf runtime", func() {
SkipIfRemote("--runtime option is not available for remote commands")
conffile := filepath.Join(podmanTest.TempDir, "container.conf")
err := os.WriteFile(conffile, []byte("[engine]\nruntime=\"testruntime\"\n"), 0755)
Expect(err).ToNot(HaveOccurred())
os.Setenv("CONTAINERS_CONF", conffile)
result := podmanTest.Podman([]string{"--help"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
Expect(result.OutputToString()).To(ContainSubstring("Path to the OCI-compatible binary used to run containers. (default \"testruntime\")"))
})
It("podman default_rootless_network_cmd", func() {
SkipIfNotRootless("default_rootless_network_cmd is only used rootless")
for _, mode := range []string{"pasta", "slirp4netns", "invalid"} {
conffile := filepath.Join(podmanTest.TempDir, "container.conf")
content := "[network]\ndefault_rootless_network_cmd=\"" + mode + "\"\n"
err := os.WriteFile(conffile, []byte(content), 0755)
Expect(err).ToNot(HaveOccurred())
os.Setenv("CONTAINERS_CONF_OVERRIDE", conffile)
if IsRemote() {
podmanTest.RestartRemoteService()
}
podman := podmanTest.Podman([]string{"create", "--name", mode, ALPINE, "ip", "addr"})
podman.WaitWithDefaultTimeout()
if mode == "invalid" {
Expect(podman).Should(ExitWithError(125, `invalid default_rootless_network_cmd option "invalid"`))
continue
}
Expect(podman).Should(ExitCleanly())
inspect := podmanTest.Podman([]string{"inspect", "--format", "{{.HostConfig.NetworkMode}}", mode})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(ExitCleanly())
Expect(inspect.OutputToString()).Should(Equal(mode))
}
})
startContainer := func(params ...string) string {
args := []string{"create"}
for _, param := range params {
if param == "--name" {
args = append(args, "--replace")
break
}
}
args = append(args, params...)
args = append(args, ALPINE, "true")
result := podmanTest.Podman(args)
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
containerID := result.OutputToString()
return containerID
}
getContainerConfig := func(containerID string, formatParam string) string {
inspect := podmanTest.Podman([]string{"inspect", "--format", formatParam, containerID})
inspect.WaitWithDefaultTimeout()
value := inspect.OutputToString()
return value
}
It("podman containers.conf container_name_as_hostname", func() {
// With default containers.conf
// Start container with no options
containerID := startContainer()
hostname := getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should be the first 12 characters of the containerID
Expect(hostname).To(Equal(containerID[:12]))
// Start container with name
containerID = startContainer("--name", "cname1")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should still be the first 12 characters of the containerID
Expect(hostname).To(Equal(containerID[:12]))
// Start container with just hostname
containerID = startContainer("--hostname", "cname1.dev")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should now be "cname1.dev"
Expect(hostname).To(Equal("cname1.dev"))
// Start container with name and hostname
containerID = startContainer("--name", "cname1", "--hostname", "cname1.dev")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should now be "cname1.dev"
Expect(hostname).To(Equal("cname1.dev"))
// Create containers.conf override with container_name_as_hostname=true
conffile := filepath.Join(podmanTest.TempDir, "container.conf")
err := os.WriteFile(conffile, []byte("[containers]\ncontainer_name_as_hostname=true\n"), 0755)
Expect(err).ToNot(HaveOccurred())
os.Setenv("CONTAINERS_CONF_OVERRIDE", conffile)
if IsRemote() {
podmanTest.RestartRemoteService()
}
// Start container with no options
containerID = startContainer()
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
name := getContainerConfig(containerID, "{{ .Name }}")
// Hostname should be the auto generated container name with '_' removed
Expect(hostname).To(Equal(strings.ReplaceAll(name, "_", "")))
// Start container with name
containerID = startContainer("--name", "cname1")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should be the container name
Expect(hostname).To(Equal("cname1"))
// Start container with name containing '_'
containerID = startContainer("--name", "cname1_2_3")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should be the set container name with all '_' removed
Expect(hostname).To(Equal("cname123"))
// Start container with just hostname
containerID = startContainer("--hostname", "cname1.dev")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should now be "cname1.dev"
Expect(hostname).To(Equal("cname1.dev"))
// Start container with name and hostname
containerID = startContainer("--name", "cname1", "--hostname", "cname1.dev")
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
// Hostname should still be "cname1.dev"
Expect(hostname).To(Equal("cname1.dev"))
// Start container with name = 260 characters
longHostname := "cnabcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890.abcdefghijklmnopqrstuvwxyz1234567890"
containerID = startContainer("--name", longHostname)
hostname = getContainerConfig(containerID, "{{ .Config.Hostname }}")
name = getContainerConfig(containerID, "{{ .Name }}")
// Double check that name actually got set correctly
Expect(name).To(Equal(longHostname))
// Hostname should be the container name truncated to 253 characters
Expect(hostname).To(Equal(name[:253]))
})
})