diff options
-rw-r--r-- | libpod/container.go | 4 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 40 | ||||
-rw-r--r-- | libpod/container_log.go | 7 | ||||
-rw-r--r-- | libpod/container_log_linux.go | 5 | ||||
-rw-r--r-- | libpod/define/info.go | 9 | ||||
-rw-r--r-- | libpod/diff.go | 1 | ||||
-rw-r--r-- | libpod/info.go | 11 | ||||
-rw-r--r-- | libpod/oci_conmon_exec_linux.go | 2 | ||||
-rw-r--r-- | libpod/oci_conmon_linux.go | 49 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 14 | ||||
-rw-r--r-- | pkg/api/handlers/compat/info.go | 20 | ||||
-rw-r--r-- | test/e2e/info_test.go | 9 | ||||
-rw-r--r-- | test/e2e/network_connect_disconnect_test.go | 8 | ||||
-rw-r--r-- | test/e2e/run_networking_test.go | 1 | ||||
-rw-r--r-- | test/system/255-auto-update.bats | 1 | ||||
-rw-r--r-- | test/system/260-sdnotify.bats | 4 |
16 files changed, 148 insertions, 37 deletions
diff --git a/libpod/container.go b/libpod/container.go index 80fd35c09..c57250d72 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -126,6 +126,10 @@ type Container struct { // This is true if a container is restored from a checkpoint. restoreFromCheckpoint bool + // Used to query the NOTIFY_SOCKET once along with setting up + // mounts etc. + notifySocket string + slirp4netnsSubnet *net.IPNet } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index f21aebb09..8b73c82de 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -352,6 +352,10 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { return nil, err } + if err := c.mountNotifySocket(g); err != nil { + return nil, err + } + // Get host UID and GID based on the container process UID and GID. hostUID, hostGID, err := butil.GetHostIDs(util.IDtoolsToRuntimeSpec(c.config.IDMappings.UIDMap), util.IDtoolsToRuntimeSpec(c.config.IDMappings.GIDMap), uint32(execUser.Uid), uint32(execUser.Gid)) if err != nil { @@ -777,6 +781,41 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { return g.Config, nil } +// mountNotifySocket mounts the NOTIFY_SOCKET into the container if it's set +// and if the sdnotify mode is set to container. It also sets c.notifySocket +// to avoid redundantly looking up the env variable. +func (c *Container) mountNotifySocket(g generate.Generator) error { + notify, ok := os.LookupEnv("NOTIFY_SOCKET") + if !ok { + return nil + } + c.notifySocket = notify + + if c.config.SdNotifyMode != define.SdNotifyModeContainer { + return nil + } + + notifyDir := filepath.Join(c.bundlePath(), "notify") + logrus.Debugf("checking notify %q dir", notifyDir) + if err := os.MkdirAll(notifyDir, 0755); err != nil { + if !os.IsExist(err) { + return errors.Wrapf(err, "unable to create notify %q dir", notifyDir) + } + } + if err := label.Relabel(notifyDir, c.MountLabel(), true); err != nil { + return errors.Wrapf(err, "relabel failed %q", notifyDir) + } + logrus.Debugf("add bindmount notify %q dir", notifyDir) + if _, ok := c.state.BindMounts["/run/notify"]; !ok { + c.state.BindMounts["/run/notify"] = notifyDir + } + + // Set the container's notify socket to the proxy socket created by conmon + g.AddProcessEnv("NOTIFY_SOCKET", "/run/notify/notify.sock") + + return nil +} + // systemd expects to have /run, /run/lock and /tmp on tmpfs // It also expects to be able to write to /sys/fs/cgroup/systemd and /var/log/journal func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) error { @@ -1730,6 +1769,7 @@ rootless=%d c.state.BindMounts[dest] = src } } + return nil } diff --git a/libpod/container_log.go b/libpod/container_log.go index 743c9c61b..3988bb654 100644 --- a/libpod/container_log.go +++ b/libpod/container_log.go @@ -14,6 +14,13 @@ import ( "github.com/sirupsen/logrus" ) +// logDrivers stores the currently available log drivers, do not modify +var logDrivers []string + +func init() { + logDrivers = append(logDrivers, define.KubernetesLogging, define.NoLogging) +} + // Log is a runtime function that can read one or more container logs. func (r *Runtime) Log(ctx context.Context, containers []*Container, options *logs.LogOptions, logChannel chan *logs.LogLine) error { for _, ctr := range containers { diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index 11f1be7f9..4eb600bfe 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/events" "github.com/containers/podman/v3/libpod/logs" "github.com/coreos/go-systemd/v22/sdjournal" @@ -24,6 +25,10 @@ const ( journaldLogErr = "3" ) +func init() { + logDrivers = append(logDrivers, define.JournaldLogging) +} + func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error { journal, err := sdjournal.NewJournal() if err != nil { diff --git a/libpod/define/info.go b/libpod/define/info.go index de709be74..95c1196dd 100644 --- a/libpod/define/info.go +++ b/libpod/define/info.go @@ -8,6 +8,7 @@ type Info struct { Host *HostInfo `json:"host"` Store *StoreInfo `json:"store"` Registries map[string]interface{} `json:"registries"` + Plugins Plugins `json:"plugins"` Version Version `json:"version"` } @@ -123,3 +124,11 @@ type ContainerStore struct { Running int `json:"running"` Stopped int `json:"stopped"` } + +type Plugins struct { + Volume []string `json:"volume"` + Network []string `json:"network"` + Log []string `json:"log"` + // FIXME what should we do with Authorization, docker seems to return nothing by default + // Authorization []string `json:"authorization"` +} diff --git a/libpod/diff.go b/libpod/diff.go index cdd5e79cb..6a50bef32 100644 --- a/libpod/diff.go +++ b/libpod/diff.go @@ -14,6 +14,7 @@ var initInodes = map[string]bool{ "/etc/resolv.conf": true, "/proc": true, "/run": true, + "/run/notify": true, "/run/.containerenv": true, "/run/secrets": true, "/sys": true, diff --git a/libpod/info.go b/libpod/info.go index 2b48ea590..8f4c7f015 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -18,6 +18,7 @@ import ( "github.com/containers/image/v5/pkg/sysregistriesv2" "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/linkmode" + "github.com/containers/podman/v3/libpod/network" "github.com/containers/podman/v3/pkg/cgroups" "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/storage" @@ -65,6 +66,16 @@ func (r *Runtime) info() (*define.Info, error) { if len(regs) > 0 { registries["search"] = regs } + volumePlugins := make([]string, 0, len(r.config.Engine.VolumePlugins)+1) + // the local driver always exists + volumePlugins = append(volumePlugins, "local") + for plugin := range r.config.Engine.VolumePlugins { + volumePlugins = append(volumePlugins, plugin) + } + info.Plugins.Volume = volumePlugins + // TODO move this into the new network interface + info.Plugins.Network = []string{network.BridgeNetworkDriver, network.MacVLANNetworkDriver} + info.Plugins.Log = logDrivers info.Registries = registries return &info, nil diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go index 05a4e19b0..469bc7d86 100644 --- a/libpod/oci_conmon_exec_linux.go +++ b/libpod/oci_conmon_exec_linux.go @@ -462,7 +462,7 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex Setpgid: true, } - err = startCommandGivenSelinux(execCmd) + err = startCommandGivenSelinux(execCmd, c) // We don't need children pipes on the parent side errorhandling.CloseQuiet(childSyncPipe) diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index 846d3815a..ff25be234 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -364,11 +364,6 @@ func (r *ConmonOCIRuntime) StartContainer(ctr *Container) error { return err } env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)} - if ctr.config.SdNotifyMode == define.SdNotifyModeContainer { - if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok { - env = append(env, fmt.Sprintf("NOTIFY_SOCKET=%s", notify)) - } - } if path, ok := os.LookupEnv("PATH"); ok { env = append(env, fmt.Sprintf("PATH=%s", path)) } @@ -1014,12 +1009,6 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co } } - if ctr.config.SdNotifyMode == define.SdNotifyModeIgnore { - if err := os.Unsetenv("NOTIFY_SOCKET"); err != nil { - logrus.Warnf("Error unsetting NOTIFY_SOCKET %v", err) - } - } - pidfile := ctr.config.PidFile if pidfile == "" { pidfile = filepath.Join(ctr.state.RunDir, "pidfile") @@ -1027,6 +1016,10 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co args := r.sharedConmonArgs(ctr, ctr.ID(), ctr.bundlePath(), pidfile, ctr.LogPath(), r.exitsDir, ociLog, ctr.LogDriver(), logTag) + if ctr.config.SdNotifyMode == define.SdNotifyModeContainer && ctr.notifySocket != "" { + args = append(args, fmt.Sprintf("--sdnotify-socket=%s", ctr.notifySocket)) + } + if ctr.config.Spec.Process.Terminal { args = append(args, "-t") } else if ctr.config.Stdin { @@ -1171,7 +1164,8 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co } } - err = startCommandGivenSelinux(cmd) + err = startCommandGivenSelinux(cmd, ctr) + // regardless of whether we errored or not, we no longer need the children pipes childSyncPipe.Close() childStartPipe.Close() @@ -1203,7 +1197,13 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co // conmon not having a pid file is a valid state, so don't set it if we don't have it logrus.Infof("Got Conmon PID as %d", conmonPID) ctr.state.ConmonPID = conmonPID - if ctr.config.SdNotifyMode != define.SdNotifyModeIgnore { + + // Send the MAINPID via sdnotify if needed. + switch ctr.config.SdNotifyMode { + case define.SdNotifyModeContainer, define.SdNotifyModeIgnore: + // Nothing to do or conmon takes care of it already. + + default: if sent, err := daemon.SdNotify(false, fmt.Sprintf("MAINPID=%d", conmonPID)); err != nil { logrus.Errorf("Error notifying systemd of Conmon PID: %v", err) } else if sent { @@ -1239,11 +1239,6 @@ func (r *ConmonOCIRuntime) configureConmonEnv(ctr *Container, runtimeDir string) } extraFiles := make([]*os.File, 0) - if ctr.config.SdNotifyMode == define.SdNotifyModeContainer { - if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok { - env = append(env, fmt.Sprintf("NOTIFY_SOCKET=%s", notify)) - } - } if !r.sdNotify { if listenfds, ok := os.LookupEnv("LISTEN_FDS"); ok { env = append(env, fmt.Sprintf("LISTEN_FDS=%s", listenfds), "LISTEN_PID=1") @@ -1335,7 +1330,23 @@ func (r *ConmonOCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, p // startCommandGivenSelinux starts a container ensuring to set the labels of // the process to make sure SELinux doesn't block conmon communication, if SELinux is enabled -func startCommandGivenSelinux(cmd *exec.Cmd) error { +func startCommandGivenSelinux(cmd *exec.Cmd, ctr *Container) error { + // Make sure to unset the NOTIFY_SOCKET and reset if afterwards if needed. + switch ctr.config.SdNotifyMode { + case define.SdNotifyModeContainer, define.SdNotifyModeIgnore: + if ctr.notifySocket != "" { + if err := os.Unsetenv("NOTIFY_SOCKET"); err != nil { + logrus.Warnf("Error unsetting NOTIFY_SOCKET %v", err) + } + + defer func() { + if err := os.Setenv("NOTIFY_SOCKET", ctr.notifySocket); err != nil { + logrus.Errorf("Error resetting NOTIFY_SOCKET=%s", ctr.notifySocket) + } + }() + } + } + if !selinux.GetEnabled() { return cmd.Start() } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 059f56798..02bbb6981 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -246,6 +246,20 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai ctr.config.Networks = netNames } + // https://github.com/containers/podman/issues/11285 + // normalize the networks aliases to use network names and never ids + if len(ctr.config.NetworkAliases) > 0 { + netAliases := make(map[string][]string, len(ctr.config.NetworkAliases)) + for nameOrID, aliases := range ctr.config.NetworkAliases { + netName, err := network.NormalizeName(r.config, nameOrID) + if err != nil { + return nil, err + } + netAliases[netName] = aliases + } + ctr.config.NetworkAliases = netAliases + } + // Inhibit shutdown until creation succeeds shutdown.Inhibit() defer shutdown.Uninhibit() diff --git a/pkg/api/handlers/compat/info.go b/pkg/api/handlers/compat/info.go index d7cefd516..2c26c7bf8 100644 --- a/pkg/api/handlers/compat/info.go +++ b/pkg/api/handlers/compat/info.go @@ -102,14 +102,18 @@ func GetInfo(w http.ResponseWriter, r *http.Request) { OomKillDisable: sysInfo.OomKillDisable, OperatingSystem: infoData.Host.Distribution.Distribution, PidsLimit: sysInfo.PidsLimit, - Plugins: docker.PluginsInfo{}, - ProductLicense: "Apache-2.0", - RegistryConfig: new(registry.ServiceConfig), - RuncCommit: docker.Commit{}, - Runtimes: getRuntimes(configInfo), - SecurityOptions: getSecOpts(sysInfo), - ServerVersion: versionInfo.Version, - SwapLimit: sysInfo.SwapLimit, + Plugins: docker.PluginsInfo{ + Volume: infoData.Plugins.Volume, + Network: infoData.Plugins.Network, + Log: infoData.Plugins.Log, + }, + ProductLicense: "Apache-2.0", + RegistryConfig: new(registry.ServiceConfig), + RuncCommit: docker.Commit{}, + Runtimes: getRuntimes(configInfo), + SecurityOptions: getSecOpts(sysInfo), + ServerVersion: versionInfo.Version, + SwapLimit: sysInfo.SwapLimit, Swarm: swarm.Info{ LocalNodeState: swarm.LocalNodeStateInactive, }, diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go index 8ac538dd2..bc3ae4443 100644 --- a/test/e2e/info_test.go +++ b/test/e2e/info_test.go @@ -77,6 +77,15 @@ var _ = Describe("Podman Info", func() { Expect(session.OutputToString()).To(ContainSubstring("registry")) }) + It("podman info --format GO template plugins", func() { + session := podmanTest.Podman([]string{"info", "--format", "{{.Plugins}}"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("local")) + Expect(session.OutputToString()).To(ContainSubstring("journald")) + Expect(session.OutputToString()).To(ContainSubstring("bridge")) + }) + It("podman info rootless storage path", func() { SkipIfNotRootless("test of rootless_storage_path is only meaningful as rootless") SkipIfRemote("Only tests storage on local client") diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go index b1f3607ab..217efdeec 100644 --- a/test/e2e/network_connect_disconnect_test.go +++ b/test/e2e/network_connect_disconnect_test.go @@ -236,8 +236,6 @@ var _ = Describe("Podman network connect and disconnect", func() { }) It("podman network connect and run with network ID", func() { - SkipIfRemote("remote flakes to much I will fix this in another PR") - SkipIfRootless("network connect and disconnect are only rootful") netName := "ID" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", netName}) session.WaitWithDefaultTimeout() @@ -249,7 +247,7 @@ var _ = Describe("Podman network connect and disconnect", func() { Expect(session).Should(Exit(0)) netID := session.OutputToString() - ctr := podmanTest.Podman([]string{"run", "-dt", "--name", "test", "--network", netID, ALPINE, "top"}) + ctr := podmanTest.Podman([]string{"run", "-dt", "--name", "test", "--network", netID, "--network-alias", "somealias", ALPINE, "top"}) ctr.WaitWithDefaultTimeout() Expect(ctr).Should(Exit(0)) @@ -269,7 +267,7 @@ var _ = Describe("Podman network connect and disconnect", func() { Expect(session).Should(Exit(0)) newNetID := session.OutputToString() - connect := podmanTest.Podman([]string{"network", "connect", newNetID, "test"}) + connect := podmanTest.Podman([]string{"network", "connect", "--alias", "secondalias", newNetID, "test"}) connect.WaitWithDefaultTimeout() Expect(connect).Should(Exit(0)) @@ -324,8 +322,6 @@ var _ = Describe("Podman network connect and disconnect", func() { }) It("podman network disconnect and run with network ID", func() { - SkipIfRemote("remote flakes to much I will fix this in another PR") - SkipIfRootless("network connect and disconnect are only rootful") netName := "aliasTest" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", netName}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 92388b099..8eabeba97 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -764,7 +764,6 @@ var _ = Describe("Podman run networking", func() { }) It("podman run check dnsname adds dns search domain", func() { - Skip("needs dnsname#57") net := "dnsname" + stringid.GenerateNonCryptoID() session := podmanTest.Podman([]string{"network", "create", net}) session.WaitWithDefaultTimeout() diff --git a/test/system/255-auto-update.bats b/test/system/255-auto-update.bats index 8bb32b5b7..7766ca3f9 100644 --- a/test/system/255-auto-update.bats +++ b/test/system/255-auto-update.bats @@ -221,7 +221,6 @@ function _confirm_update() { } @test "podman auto-update - label io.containers.autoupdate=local with rollback" { - skip "This test flakes way too often, see #11175" # sdnotify fails with runc 1.0.0-3-dev2 on Ubuntu. Let's just # assume that we work only with crun, nothing else. # [copied from 260-sdnotify.bats] diff --git a/test/system/260-sdnotify.bats b/test/system/260-sdnotify.bats index acb30de47..b5d3f9b86 100644 --- a/test/system/260-sdnotify.bats +++ b/test/system/260-sdnotify.bats @@ -130,6 +130,8 @@ function _assert_mainpid_is_conmon() { _stop_socat } +# These tests can fail in dev. environment because of SELinux. +# quick fix: chcon -t container_runtime_exec_t ./bin/podman @test "sdnotify : container" { # Sigh... we need to pull a humongous image because it has systemd-notify. # (IMPORTANT: fedora:32 and above silently removed systemd-notify; this @@ -150,7 +152,7 @@ function _assert_mainpid_is_conmon() { wait_for_ready $cid run_podman logs $cid - is "${lines[0]}" "/.*/container\.sock/notify" "NOTIFY_SOCKET is passed to container" + is "${lines[0]}" "/run/notify/notify.sock" "NOTIFY_SOCKET is passed to container" # With container, READY=1 isn't necessarily the last message received; # just look for it anywhere in received messages |