libpod: allow the notify socket to be passed programatically

The notify socket can now either be specified via an environment
variable or programatically (where the env is ignored).  The
notify mode and the socket are now also displayed in `container inspect`
which comes in handy for debugging and allows for propper testing.

Signed-off-by: Valentin Rothberg <vrothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2022-08-05 14:22:54 +02:00
parent 67a2e7351b
commit 3fc126e152
10 changed files with 46 additions and 17 deletions

View File

@ -124,10 +124,6 @@ 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
}

View File

@ -386,6 +386,8 @@ type ContainerMiscConfig struct {
IsService bool `json:"isService"`
// SdNotifyMode tells libpod what to do with a NOTIFY_SOCKET if passed
SdNotifyMode string `json:"sdnotifyMode,omitempty"`
// SdNotifySocket stores NOTIFY_SOCKET in use by the container
SdNotifySocket string `json:"sdnotifySocket,omitempty"`
// Systemd tells libpod to set up the container in systemd mode, a value of nil denotes false
Systemd *bool `json:"systemd,omitempty"`
// HealthCheckConfig has the health check command and related timings

View File

@ -414,6 +414,8 @@ func (c *Container) generateInspectContainerConfig(spec *spec.Spec) *define.Insp
ctrConfig.Passwd = c.config.Passwd
ctrConfig.ChrootDirs = append(ctrConfig.ChrootDirs, c.config.ChrootDirs...)
ctrConfig.SdNotifyMode = c.config.SdNotifyMode
ctrConfig.SdNotifySocket = c.config.SdNotifySocket
return ctrConfig
}

View File

@ -31,6 +31,7 @@ import (
"github.com/containers/podman/v4/pkg/lookup"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/selinux"
"github.com/containers/podman/v4/pkg/systemd/notifyproxy"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
@ -1224,9 +1225,9 @@ func (c *Container) start() error {
payload += "\n"
payload += daemon.SdNotifyReady
}
if sent, err := daemon.SdNotify(false, payload); err != nil {
if err := notifyproxy.SendMessage(c.config.SdNotifySocket, payload); err != nil {
logrus.Errorf("Notifying systemd of Conmon PID: %s", err.Error())
} else if sent {
} else {
logrus.Debugf("Notify sent successfully")
}
}

View File

@ -969,12 +969,9 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
// 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 {
if c.config.SdNotifySocket == "" {
return nil
}
c.notifySocket = notify
if c.config.SdNotifyMode != define.SdNotifyModeContainer {
return nil
}

View File

@ -79,6 +79,10 @@ type InspectContainerConfig struct {
// treated as root directories. Standard bind mounts will be mounted
// into paths relative to these directories.
ChrootDirs []string `json:"ChrootDirs,omitempty"`
// SdNotifyMode is the sd-notify mode of the container.
SdNotifyMode string `json:"sdNotifyMode,omitempty"`
// SdNotifySocket is the NOTIFY_SOCKET in use by/configured for the container.
SdNotifySocket string `json:"sdNotifySocket,omitempty"`
}
// InspectRestartPolicy holds information about the container's restart policy.

View File

@ -1062,8 +1062,8 @@ 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.SdNotifyMode == define.SdNotifyModeContainer && ctr.config.SdNotifySocket != "" {
args = append(args, fmt.Sprintf("--sdnotify-socket=%s", ctr.config.SdNotifySocket))
}
if ctr.config.Spec.Process.Terminal {
@ -1391,14 +1391,13 @@ func startCommand(cmd *exec.Cmd, ctr *Container) error {
// Make sure to unset the NOTIFY_SOCKET and reset it afterwards if needed.
switch ctr.config.SdNotifyMode {
case define.SdNotifyModeContainer, define.SdNotifyModeIgnore:
if ctr.notifySocket != "" {
if prev := os.Getenv("NOTIFY_SOCKET"); prev != "" {
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("Resetting NOTIFY_SOCKET=%s", ctr.notifySocket)
if err := os.Setenv("NOTIFY_SOCKET", prev); err != nil {
logrus.Errorf("Resetting NOTIFY_SOCKET=%s", prev)
}
}()
}

View File

@ -613,6 +613,17 @@ func WithSystemd() CtrCreateOption {
}
}
// WithSdNotifySocket sets the sd-notify of the container
func WithSdNotifySocket(socketPath string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
ctr.config.SdNotifySocket = socketPath
return nil
}
}
// WithSdNotifyMode sets the sd-notify method
func WithSdNotifyMode(mode string) CtrCreateOption {
return func(ctr *Container) error {

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
@ -353,6 +354,10 @@ func createContainerOptions(rt *libpod.Runtime, s *specgen.SpecGenerator, pod *l
if len(s.SdNotifyMode) > 0 {
options = append(options, libpod.WithSdNotifyMode(s.SdNotifyMode))
}
if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
options = append(options, libpod.WithSdNotifySocket(notify))
}
if pod != nil {
logrus.Debugf("adding container to pod %s", pod.Name())
options = append(options, rt.WithPod(pod))

View File

@ -88,7 +88,13 @@ function _assert_mainpid_is_conmon() {
export NOTIFY_SOCKET=$PODMAN_TMPDIR/ignore.sock
_start_socat
run_podman 1 run --rm --sdnotify=ignore $IMAGE printenv NOTIFY_SOCKET
run_podman create --rm --sdnotify=ignore $IMAGE printenv NOTIFY_SOCKET
cid="$output"
run_podman container inspect $cid --format "{{.Config.SdNotifyMode}} {{.Config.SdNotifySocket}}"
is "$output" "ignore $NOTIFY_SOCKET"
run_podman 1 start --attach $cid
is "$output" "" "\$NOTIFY_SOCKET in container"
is "$(< $_SOCAT_LOG)" "" "nothing received on socket"
@ -106,6 +112,9 @@ function _assert_mainpid_is_conmon() {
cid="$output"
wait_for_ready $cid
run_podman container inspect $cid --format "{{.Config.SdNotifyMode}} {{.Config.SdNotifySocket}}"
is "$output" "conmon $NOTIFY_SOCKET"
run_podman container inspect sdnotify_conmon_c --format "{{.State.ConmonPid}}"
mainPID="$output"
@ -151,6 +160,9 @@ READY=1" "sdnotify sent MAINPID and READY"
cid="$output"
wait_for_ready $cid
run_podman container inspect $cid --format "{{.Config.SdNotifyMode}} {{.Config.SdNotifySocket}}"
is "$output" "container $NOTIFY_SOCKET"
run_podman logs $cid
is "${lines[0]}" "/run/notify/notify.sock" "NOTIFY_SOCKET is passed to container"