mirror of
https://github.com/containers/podman.git
synced 2025-06-24 11:28:24 +08:00
Merge pull request #6693 from goochjj/libpod-sd-notify-cmdline
Implement --sdnotify cmdline option to control sd-notify behavior
This commit is contained in:
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containers/common/pkg/auth"
|
"github.com/containers/common/pkg/auth"
|
||||||
"github.com/containers/libpod/v2/cmd/podman/registry"
|
"github.com/containers/libpod/v2/cmd/podman/registry"
|
||||||
|
"github.com/containers/libpod/v2/libpod/define"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -394,6 +395,11 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
|
|||||||
"rootfs", false,
|
"rootfs", false,
|
||||||
"The first argument is not an image but the rootfs to the exploded container",
|
"The first argument is not an image but the rootfs to the exploded container",
|
||||||
)
|
)
|
||||||
|
createFlags.StringVar(
|
||||||
|
&cf.SdNotifyMode,
|
||||||
|
"sdnotify", define.SdNotifyModeContainer,
|
||||||
|
`control sd-notify behavior ("container"|"conmon"|"ignore")`,
|
||||||
|
)
|
||||||
createFlags.StringArrayVar(
|
createFlags.StringArrayVar(
|
||||||
&cf.SecurityOpt,
|
&cf.SecurityOpt,
|
||||||
"security-opt", containerConfig.SecurityOptions(),
|
"security-opt", containerConfig.SecurityOptions(),
|
||||||
|
@ -81,6 +81,7 @@ type ContainerCLIOpts struct {
|
|||||||
Rm bool
|
Rm bool
|
||||||
RootFS bool
|
RootFS bool
|
||||||
SecurityOpt []string
|
SecurityOpt []string
|
||||||
|
SdNotifyMode string
|
||||||
ShmSize string
|
ShmSize string
|
||||||
StopSignal string
|
StopSignal string
|
||||||
StopTimeout uint
|
StopTimeout uint
|
||||||
|
@ -443,6 +443,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.Systemd = c.Systemd
|
s.Systemd = c.Systemd
|
||||||
|
s.SdNotifyMode = c.SdNotifyMode
|
||||||
if s.ResourceLimits == nil {
|
if s.ResourceLimits == nil {
|
||||||
s.ResourceLimits = &specs.LinuxResources{}
|
s.ResourceLimits = &specs.LinuxResources{}
|
||||||
}
|
}
|
||||||
|
@ -702,6 +702,17 @@ If specified, the first argument refers to an exploded container on the file sys
|
|||||||
This is useful to run a container without requiring any image management, the rootfs
|
This is useful to run a container without requiring any image management, the rootfs
|
||||||
of the container is assumed to be managed externally.
|
of the container is assumed to be managed externally.
|
||||||
|
|
||||||
|
**--sdnotify**=**container**|**conmon**|**ignore**
|
||||||
|
|
||||||
|
Determines how to use the NOTIFY_SOCKET, as passed with systemd and Type=notify.
|
||||||
|
|
||||||
|
Default is **container**, which means allow the OCI runtime to proxy the socket into the
|
||||||
|
container to receive ready notification. Podman will set the MAINPID to conmon's pid.
|
||||||
|
The **conmon** option sets MAINPID to conmon's pid, and sends READY when the container
|
||||||
|
has started. The socket is never passed to the runtime or the container.
|
||||||
|
The **ignore** option removes NOTIFY_SOCKET from the environment for itself and child processes,
|
||||||
|
for the case where some other process above Podman uses NOTIFY_SOCKET and Podman should not use it.
|
||||||
|
|
||||||
**--seccomp-policy**=*policy*
|
**--seccomp-policy**=*policy*
|
||||||
|
|
||||||
Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
|
Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
|
||||||
|
@ -723,6 +723,17 @@ of the container is assumed to be managed externally.
|
|||||||
Note: On **SELinux** systems, the rootfs needs the correct label, which is by default
|
Note: On **SELinux** systems, the rootfs needs the correct label, which is by default
|
||||||
**unconfined_u:object_r:container_file_t**.
|
**unconfined_u:object_r:container_file_t**.
|
||||||
|
|
||||||
|
**--sdnotify**=**container**|**conmon**|**ignore**
|
||||||
|
|
||||||
|
Determines how to use the NOTIFY_SOCKET, as passed with systemd and Type=notify.
|
||||||
|
|
||||||
|
Default is **container**, which means allow the OCI runtime to proxy the socket into the
|
||||||
|
container to receive ready notification. Podman will set the MAINPID to conmon's pid.
|
||||||
|
The **conmon** option sets MAINPID to conmon's pid, and sends READY when the container
|
||||||
|
has started. The socket is never passed to the runtime or the container.
|
||||||
|
The **ignore** option removes NOTIFY_SOCKET from the environment for itself and child processes,
|
||||||
|
for the case where some other process above Podman uses NOTIFY_SOCKET and Podman should not use it.
|
||||||
|
|
||||||
**--seccomp-policy**=*policy*
|
**--seccomp-policy**=*policy*
|
||||||
|
|
||||||
Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
|
Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
|
||||||
|
@ -414,6 +414,8 @@ type ContainerConfig struct {
|
|||||||
// sharing kernel namespaces in a pod
|
// sharing kernel namespaces in a pod
|
||||||
IsInfra bool `json:"pause"`
|
IsInfra bool `json:"pause"`
|
||||||
|
|
||||||
|
// SdNotifyMode tells libpod what to do with a NOTIFY_SOCKET if passed
|
||||||
|
SdNotifyMode string `json:"sdnotifyMode,omitempty"`
|
||||||
// Systemd tells libpod to setup the container in systemd mode
|
// Systemd tells libpod to setup the container in systemd mode
|
||||||
Systemd bool `json:"systemd"`
|
Systemd bool `json:"systemd"`
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/containers/storage/pkg/archive"
|
"github.com/containers/storage/pkg/archive"
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
"github.com/containers/storage/pkg/mount"
|
"github.com/containers/storage/pkg/mount"
|
||||||
|
"github.com/coreos/go-systemd/v22/daemon"
|
||||||
securejoin "github.com/cyphar/filepath-securejoin"
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/opencontainers/runtime-tools/generate"
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
@ -1192,6 +1193,19 @@ func (c *Container) start() error {
|
|||||||
|
|
||||||
c.state.State = define.ContainerStateRunning
|
c.state.State = define.ContainerStateRunning
|
||||||
|
|
||||||
|
if c.config.SdNotifyMode != define.SdNotifyModeIgnore {
|
||||||
|
payload := fmt.Sprintf("MAINPID=%d", c.state.ConmonPID)
|
||||||
|
if c.config.SdNotifyMode == define.SdNotifyModeConmon {
|
||||||
|
payload += "\n"
|
||||||
|
payload += daemon.SdNotifyReady
|
||||||
|
}
|
||||||
|
if sent, err := daemon.SdNotify(false, payload); err != nil {
|
||||||
|
logrus.Errorf("Error notifying systemd of Conmon PID: %s", err.Error())
|
||||||
|
} else if sent {
|
||||||
|
logrus.Debugf("Notify sent successfully")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if c.config.HealthCheckConfig != nil {
|
if c.config.HealthCheckConfig != nil {
|
||||||
if err := c.updateHealthStatus(define.HealthCheckStarting); err != nil {
|
if err := c.updateHealthStatus(define.HealthCheckStarting); err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
|
@ -75,3 +75,10 @@ const JSONLogging = "json-file"
|
|||||||
|
|
||||||
// NoLogging is the string conmon expects when specifying to use no log driver whatsoever
|
// NoLogging is the string conmon expects when specifying to use no log driver whatsoever
|
||||||
const NoLogging = "none"
|
const NoLogging = "none"
|
||||||
|
|
||||||
|
// Strings used for --sdnotify option to podman
|
||||||
|
const (
|
||||||
|
SdNotifyModeContainer = "container"
|
||||||
|
SdNotifyModeConmon = "conmon"
|
||||||
|
SdNotifyModeIgnore = "ignore"
|
||||||
|
)
|
||||||
|
@ -444,7 +444,7 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
conmonEnv, extraFiles, err := r.configureConmonEnv(runtimeDir)
|
conmonEnv, extraFiles, err := r.configureConmonEnv(c, runtimeDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/containers/libpod/v2/utils"
|
"github.com/containers/libpod/v2/utils"
|
||||||
pmount "github.com/containers/storage/pkg/mount"
|
pmount "github.com/containers/storage/pkg/mount"
|
||||||
"github.com/coreos/go-systemd/v22/activation"
|
"github.com/coreos/go-systemd/v22/activation"
|
||||||
|
"github.com/coreos/go-systemd/v22/daemon"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/opencontainers/selinux/go-selinux"
|
"github.com/opencontainers/selinux/go-selinux"
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
@ -365,8 +366,10 @@ func (r *ConmonOCIRuntime) StartContainer(ctr *Container) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)}
|
env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)}
|
||||||
if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
|
if ctr.config.SdNotifyMode == define.SdNotifyModeContainer {
|
||||||
env = append(env, fmt.Sprintf("NOTIFY_SOCKET=%s", notify))
|
if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
|
||||||
|
env = append(env, fmt.Sprintf("NOTIFY_SOCKET=%s", notify))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if path, ok := os.LookupEnv("PATH"); ok {
|
if path, ok := os.LookupEnv("PATH"); ok {
|
||||||
env = append(env, fmt.Sprintf("PATH=%s", path))
|
env = append(env, fmt.Sprintf("PATH=%s", path))
|
||||||
@ -887,6 +890,12 @@ 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 %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
args := r.sharedConmonArgs(ctr, ctr.ID(), ctr.bundlePath(), filepath.Join(ctr.state.RunDir, "pidfile"), ctr.LogPath(), r.exitsDir, ociLog, ctr.LogDriver(), logTag)
|
args := r.sharedConmonArgs(ctr, ctr.ID(), ctr.bundlePath(), filepath.Join(ctr.state.RunDir, "pidfile"), ctr.LogPath(), r.exitsDir, ociLog, ctr.LogDriver(), logTag)
|
||||||
|
|
||||||
if ctr.config.Spec.Process.Terminal {
|
if ctr.config.Spec.Process.Terminal {
|
||||||
@ -940,7 +949,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0, 1 and 2 are stdin, stdout and stderr
|
// 0, 1 and 2 are stdin, stdout and stderr
|
||||||
conmonEnv, envFiles, err := r.configureConmonEnv(runtimeDir)
|
conmonEnv, envFiles, err := r.configureConmonEnv(ctr, runtimeDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1034,6 +1043,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
|
// 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)
|
logrus.Infof("Got Conmon PID as %d", conmonPID)
|
||||||
ctr.state.ConmonPID = conmonPID
|
ctr.state.ConmonPID = conmonPID
|
||||||
|
if ctr.config.SdNotifyMode != define.SdNotifyModeIgnore {
|
||||||
|
if sent, err := daemon.SdNotify(false, fmt.Sprintf("MAINPID=%d", conmonPID)); err != nil {
|
||||||
|
logrus.Errorf("Error notifying systemd of Conmon PID: %s", err.Error())
|
||||||
|
} else if sent {
|
||||||
|
logrus.Debugf("Notify MAINPID sent successfully")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctr.config.PreserveFDs > 0 {
|
if ctr.config.PreserveFDs > 0 {
|
||||||
@ -1137,7 +1153,7 @@ func prepareProcessExec(c *Container, cmd, env []string, tty bool, cwd, user, se
|
|||||||
|
|
||||||
// configureConmonEnv gets the environment values to add to conmon's exec struct
|
// configureConmonEnv gets the environment values to add to conmon's exec struct
|
||||||
// TODO this may want to be less hardcoded/more configurable in the future
|
// TODO this may want to be less hardcoded/more configurable in the future
|
||||||
func (r *ConmonOCIRuntime) configureConmonEnv(runtimeDir string) ([]string, []*os.File, error) {
|
func (r *ConmonOCIRuntime) configureConmonEnv(ctr *Container, runtimeDir string) ([]string, []*os.File, error) {
|
||||||
env := make([]string, 0, 6)
|
env := make([]string, 0, 6)
|
||||||
env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
|
env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
|
||||||
env = append(env, fmt.Sprintf("_CONTAINERS_USERNS_CONFIGURED=%s", os.Getenv("_CONTAINERS_USERNS_CONFIGURED")))
|
env = append(env, fmt.Sprintf("_CONTAINERS_USERNS_CONFIGURED=%s", os.Getenv("_CONTAINERS_USERNS_CONFIGURED")))
|
||||||
@ -1149,8 +1165,10 @@ func (r *ConmonOCIRuntime) configureConmonEnv(runtimeDir string) ([]string, []*o
|
|||||||
env = append(env, fmt.Sprintf("HOME=%s", home))
|
env = append(env, fmt.Sprintf("HOME=%s", home))
|
||||||
|
|
||||||
extraFiles := make([]*os.File, 0)
|
extraFiles := make([]*os.File, 0)
|
||||||
if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
|
if ctr.config.SdNotifyMode == define.SdNotifyModeContainer {
|
||||||
env = append(env, fmt.Sprintf("NOTIFY_SOCKET=%s", notify))
|
if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
|
||||||
|
env = append(env, fmt.Sprintf("NOTIFY_SOCKET=%s", notify))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !r.sdNotify {
|
if !r.sdNotify {
|
||||||
if listenfds, ok := os.LookupEnv("LISTEN_FDS"); ok {
|
if listenfds, ok := os.LookupEnv("LISTEN_FDS"); ok {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/containers/common/pkg/config"
|
"github.com/containers/common/pkg/config"
|
||||||
@ -22,6 +23,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Runtime Creation Options
|
// Runtime Creation Options
|
||||||
|
var (
|
||||||
|
// SdNotifyModeValues describes the only values that SdNotifyMode can be
|
||||||
|
SdNotifyModeValues = []string{define.SdNotifyModeContainer, define.SdNotifyModeConmon, define.SdNotifyModeIgnore}
|
||||||
|
)
|
||||||
|
|
||||||
// WithStorageConfig uses the given configuration to set up container storage.
|
// WithStorageConfig uses the given configuration to set up container storage.
|
||||||
// If this is not specified, the system default configuration will be used
|
// If this is not specified, the system default configuration will be used
|
||||||
@ -550,6 +555,23 @@ func WithSystemd() CtrCreateOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithSdNotifyMode sets the sd-notify method
|
||||||
|
func WithSdNotifyMode(mode string) CtrCreateOption {
|
||||||
|
return func(ctr *Container) error {
|
||||||
|
if ctr.valid {
|
||||||
|
return define.ErrCtrFinalized
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify values
|
||||||
|
if len(mode) > 0 && !util.StringInSlice(strings.ToLower(mode), SdNotifyModeValues) {
|
||||||
|
return errors.Wrapf(define.ErrInvalidArg, "--sdnotify values must be one of %q", strings.Join(SdNotifyModeValues, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctr.config.SdNotifyMode = mode
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithShmSize sets the size of /dev/shm tmpfs mount.
|
// WithShmSize sets the size of /dev/shm tmpfs mount.
|
||||||
func WithShmSize(size int64) CtrCreateOption {
|
func WithShmSize(size int64) CtrCreateOption {
|
||||||
return func(ctr *Container) error {
|
return func(ctr *Container) error {
|
||||||
|
@ -3,6 +3,7 @@ package specgen
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/libpod/v2/libpod/define"
|
||||||
"github.com/containers/libpod/v2/pkg/rootless"
|
"github.com/containers/libpod/v2/pkg/rootless"
|
||||||
"github.com/containers/libpod/v2/pkg/util"
|
"github.com/containers/libpod/v2/pkg/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -13,6 +14,8 @@ var (
|
|||||||
ErrInvalidSpecConfig = errors.New("invalid configuration")
|
ErrInvalidSpecConfig = errors.New("invalid configuration")
|
||||||
// SystemDValues describes the only values that SystemD can be
|
// SystemDValues describes the only values that SystemD can be
|
||||||
SystemDValues = []string{"true", "false", "always"}
|
SystemDValues = []string{"true", "false", "always"}
|
||||||
|
// SdNotifyModeValues describes the only values that SdNotifyMode can be
|
||||||
|
SdNotifyModeValues = []string{define.SdNotifyModeContainer, define.SdNotifyModeConmon, define.SdNotifyModeIgnore}
|
||||||
// ImageVolumeModeValues describes the only values that ImageVolumeMode can be
|
// ImageVolumeModeValues describes the only values that ImageVolumeMode can be
|
||||||
ImageVolumeModeValues = []string{"ignore", "tmpfs", "anonymous"}
|
ImageVolumeModeValues = []string{"ignore", "tmpfs", "anonymous"}
|
||||||
)
|
)
|
||||||
@ -40,6 +43,10 @@ func (s *SpecGenerator) Validate() error {
|
|||||||
if len(s.ContainerBasicConfig.Systemd) > 0 && !util.StringInSlice(strings.ToLower(s.ContainerBasicConfig.Systemd), SystemDValues) {
|
if len(s.ContainerBasicConfig.Systemd) > 0 && !util.StringInSlice(strings.ToLower(s.ContainerBasicConfig.Systemd), SystemDValues) {
|
||||||
return errors.Wrapf(ErrInvalidSpecConfig, "--systemd values must be one of %q", strings.Join(SystemDValues, ", "))
|
return errors.Wrapf(ErrInvalidSpecConfig, "--systemd values must be one of %q", strings.Join(SystemDValues, ", "))
|
||||||
}
|
}
|
||||||
|
// sdnotify values must be container, conmon, or ignore
|
||||||
|
if len(s.ContainerBasicConfig.SdNotifyMode) > 0 && !util.StringInSlice(strings.ToLower(s.ContainerBasicConfig.SdNotifyMode), SdNotifyModeValues) {
|
||||||
|
return errors.Wrapf(ErrInvalidSpecConfig, "--sdnotify values must be one of %q", strings.Join(SdNotifyModeValues, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// ContainerStorageConfig
|
// ContainerStorageConfig
|
||||||
|
@ -175,6 +175,10 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
|
|||||||
|
|
||||||
options = append(options, libpod.WithSystemd())
|
options = append(options, libpod.WithSystemd())
|
||||||
}
|
}
|
||||||
|
if len(s.SdNotifyMode) > 0 {
|
||||||
|
options = append(options, libpod.WithSdNotifyMode(s.SdNotifyMode))
|
||||||
|
}
|
||||||
|
|
||||||
if len(s.Name) > 0 {
|
if len(s.Name) > 0 {
|
||||||
logrus.Debugf("setting container name %s", s.Name)
|
logrus.Debugf("setting container name %s", s.Name)
|
||||||
options = append(options, libpod.WithName(s.Name))
|
options = append(options, libpod.WithName(s.Name))
|
||||||
|
@ -107,6 +107,11 @@ type ContainerBasicConfig struct {
|
|||||||
// If not specified, "false" will be assumed.
|
// If not specified, "false" will be assumed.
|
||||||
// Optional.
|
// Optional.
|
||||||
Systemd string `json:"systemd,omitempty"`
|
Systemd string `json:"systemd,omitempty"`
|
||||||
|
// Determine how to handle the NOTIFY_SOCKET - do we participate or pass it through
|
||||||
|
// "container" - let the OCI runtime deal with it, advertise conmon's MAINPID
|
||||||
|
// "conmon-only" - advertise conmon's MAINPID, send READY when started, don't pass to OCI
|
||||||
|
// "ignore" - unset NOTIFY_SOCKET
|
||||||
|
SdNotifyMode string `json:"sdnotifyMode,omitempty"`
|
||||||
// Namespace is the libpod namespace the container will be placed in.
|
// Namespace is the libpod namespace the container will be placed in.
|
||||||
// Optional.
|
// Optional.
|
||||||
Namespace string `json:"namespace,omitempty"`
|
Namespace string `json:"namespace,omitempty"`
|
||||||
|
142
test/system/260-sdnotify.bats
Normal file
142
test/system/260-sdnotify.bats
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#!/usr/bin/env bats -*- bats -*-
|
||||||
|
#
|
||||||
|
# Tests for systemd sdnotify
|
||||||
|
#
|
||||||
|
|
||||||
|
load helpers
|
||||||
|
|
||||||
|
# Shared throughout this module: PID of socat process, and path to its log
|
||||||
|
_SOCAT_PID=
|
||||||
|
_SOCAT_LOG=
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
skip_if_remote
|
||||||
|
|
||||||
|
# TODO: remove this once CI systems have newer crun and container-selinux
|
||||||
|
skip "TEMPORARY SKIP - until CI systems get new crun, container-selinux"
|
||||||
|
|
||||||
|
basic_setup
|
||||||
|
}
|
||||||
|
|
||||||
|
function teardown() {
|
||||||
|
unset NOTIFY_SOCKET
|
||||||
|
|
||||||
|
_stop_socat
|
||||||
|
|
||||||
|
basic_teardown
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# BEGIN helpers
|
||||||
|
|
||||||
|
# Run socat process on a socket, logging to well-known path. Each received
|
||||||
|
# packet is logged with a newline appended, for ease of parsing the log file.
|
||||||
|
function _start_socat() {
|
||||||
|
_SOCAT_LOG="$PODMAN_TMPDIR/socat.log"
|
||||||
|
|
||||||
|
rm -f $_SOCAT_LOG
|
||||||
|
socat unix-recvfrom:"$NOTIFY_SOCKET",fork \
|
||||||
|
system:"(cat;echo) >> $_SOCAT_LOG" &
|
||||||
|
_SOCAT_PID=$!
|
||||||
|
}
|
||||||
|
|
||||||
|
# Stop the socat background process and clean up logs
|
||||||
|
function _stop_socat() {
|
||||||
|
if [[ -n "$_SOCAT_PID" ]]; then
|
||||||
|
kill $_SOCAT_PID
|
||||||
|
fi
|
||||||
|
_SOCAT_PID=
|
||||||
|
|
||||||
|
if [[ -n "$_SOCAT_LOG" ]]; then
|
||||||
|
rm -f $_SOCAT_LOG
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check that MAINPID=xxxxx points to a running conmon process
|
||||||
|
function _assert_mainpid_is_conmon() {
|
||||||
|
local mainpid=$(expr "$1" : "MAINPID=\([0-9]\+\)")
|
||||||
|
test -n "$mainpid" || die "Could not parse '$1' as 'MAINPID=nnnn'"
|
||||||
|
|
||||||
|
test -d /proc/$mainpid || die "sdnotify MAINPID=$mainpid - but /proc/$mainpid does not exist"
|
||||||
|
|
||||||
|
# e.g. /proc/12345/exe -> /usr/bin/conmon
|
||||||
|
local mainpid_bin=$(readlink /proc/$mainpid/exe)
|
||||||
|
is "$mainpid_bin" ".*/conmon" "sdnotify MAINPID=$mainpid is conmon process"
|
||||||
|
}
|
||||||
|
|
||||||
|
# END helpers
|
||||||
|
###############################################################################
|
||||||
|
# BEGIN tests themselves
|
||||||
|
|
||||||
|
@test "sdnotify : ignore" {
|
||||||
|
export NOTIFY_SOCKET=$PODMAN_TMPDIR/ignore.sock
|
||||||
|
_start_socat
|
||||||
|
|
||||||
|
run_podman 1 run --rm --sdnotify=ignore $IMAGE printenv NOTIFY_SOCKET
|
||||||
|
is "$output" "" "\$NOTIFY_SOCKET in container"
|
||||||
|
|
||||||
|
is "$(< $_SOCAT_LOG)" "" "nothing received on socket"
|
||||||
|
_stop_socat
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "sdnotify : conmon" {
|
||||||
|
export NOTIFY_SOCKET=$PODMAN_TMPDIR/conmon.sock
|
||||||
|
_start_socat
|
||||||
|
|
||||||
|
run_podman run -d --name sdnotify_conmon_c \
|
||||||
|
--sdnotify=conmon \
|
||||||
|
$IMAGE \
|
||||||
|
sh -c 'printenv NOTIFY_SOCKET;echo READY;while ! test -f /stop;do sleep 0.1;done'
|
||||||
|
cid="$output"
|
||||||
|
wait_for_ready $cid
|
||||||
|
|
||||||
|
run_podman logs sdnotify_conmon_c
|
||||||
|
is "$output" "READY" "\$NOTIFY_SOCKET in container"
|
||||||
|
|
||||||
|
run cat $_SOCAT_LOG
|
||||||
|
is "${lines[-1]}" "READY=1" "final output from sdnotify"
|
||||||
|
|
||||||
|
_assert_mainpid_is_conmon "${lines[0]}"
|
||||||
|
|
||||||
|
# Done. Stop container, clean up.
|
||||||
|
run_podman exec $cid touch /stop
|
||||||
|
run_podman rm $cid
|
||||||
|
_stop_socat
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "sdnotify : container" {
|
||||||
|
# Sigh... we need to pull a humongous image because it has systemd-notify.
|
||||||
|
# FIXME: is there a smaller image we could use?
|
||||||
|
_FEDORA=registry.fedoraproject.org/fedora:latest
|
||||||
|
|
||||||
|
# Pull that image. Retry in case of flakes.
|
||||||
|
run_podman pull $_FEDORA || \
|
||||||
|
run_podman pull $_FEDORA || \
|
||||||
|
run_podman pull $_FEDORA
|
||||||
|
|
||||||
|
export NOTIFY_SOCKET=$PODMAN_TMPDIR/container.sock
|
||||||
|
_start_socat
|
||||||
|
|
||||||
|
run_podman run -d --sdnotify=container $_FEDORA \
|
||||||
|
sh -c 'printenv NOTIFY_SOCKET;echo READY;systemd-notify --ready;while ! test -f /stop;do sleep 0.1;done'
|
||||||
|
cid="$output"
|
||||||
|
wait_for_ready $cid
|
||||||
|
|
||||||
|
run_podman logs $cid
|
||||||
|
is "${lines[0]}" "/.*/container\.sock/notify" "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
|
||||||
|
run cat $_SOCAT_LOG
|
||||||
|
is "$output" ".*READY=1" "received READY=1 through notify socket"
|
||||||
|
|
||||||
|
_assert_mainpid_is_conmon "${lines[0]}"
|
||||||
|
|
||||||
|
# Done. Stop container, clean up.
|
||||||
|
run_podman exec $cid touch /stop
|
||||||
|
run_podman rm $cid
|
||||||
|
run_podman rmi $_FEDORA
|
||||||
|
_stop_socat
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: filetype=sh
|
84
vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go
generated
vendored
Normal file
84
vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// Copyright 2014 Docker, Inc.
|
||||||
|
// Copyright 2015-2018 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Package daemon provides a Go implementation of the sd_notify protocol.
|
||||||
|
// It can be used to inform systemd of service start-up completion, watchdog
|
||||||
|
// events, and other status changes.
|
||||||
|
//
|
||||||
|
// https://www.freedesktop.org/software/systemd/man/sd_notify.html#Description
|
||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SdNotifyReady tells the service manager that service startup is finished
|
||||||
|
// or the service finished loading its configuration.
|
||||||
|
SdNotifyReady = "READY=1"
|
||||||
|
|
||||||
|
// SdNotifyStopping tells the service manager that the service is beginning
|
||||||
|
// its shutdown.
|
||||||
|
SdNotifyStopping = "STOPPING=1"
|
||||||
|
|
||||||
|
// SdNotifyReloading tells the service manager that this service is
|
||||||
|
// reloading its configuration. Note that you must call SdNotifyReady when
|
||||||
|
// it completed reloading.
|
||||||
|
SdNotifyReloading = "RELOADING=1"
|
||||||
|
|
||||||
|
// SdNotifyWatchdog tells the service manager to update the watchdog
|
||||||
|
// timestamp for the service.
|
||||||
|
SdNotifyWatchdog = "WATCHDOG=1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SdNotify sends a message to the init daemon. It is common to ignore the error.
|
||||||
|
// If `unsetEnvironment` is true, the environment variable `NOTIFY_SOCKET`
|
||||||
|
// will be unconditionally unset.
|
||||||
|
//
|
||||||
|
// It returns one of the following:
|
||||||
|
// (false, nil) - notification not supported (i.e. NOTIFY_SOCKET is unset)
|
||||||
|
// (false, err) - notification supported, but failure happened (e.g. error connecting to NOTIFY_SOCKET or while sending data)
|
||||||
|
// (true, nil) - notification supported, data has been sent
|
||||||
|
func SdNotify(unsetEnvironment bool, state string) (bool, error) {
|
||||||
|
socketAddr := &net.UnixAddr{
|
||||||
|
Name: os.Getenv("NOTIFY_SOCKET"),
|
||||||
|
Net: "unixgram",
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTIFY_SOCKET not set
|
||||||
|
if socketAddr.Name == "" {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if unsetEnvironment {
|
||||||
|
if err := os.Unsetenv("NOTIFY_SOCKET"); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
|
||||||
|
// Error connecting to NOTIFY_SOCKET
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if _, err = conn.Write([]byte(state)); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
73
vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go
generated
vendored
Normal file
73
vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// Copyright 2016 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SdWatchdogEnabled returns watchdog information for a service.
|
||||||
|
// Processes should call daemon.SdNotify(false, daemon.SdNotifyWatchdog) every
|
||||||
|
// time / 2.
|
||||||
|
// If `unsetEnvironment` is true, the environment variables `WATCHDOG_USEC` and
|
||||||
|
// `WATCHDOG_PID` will be unconditionally unset.
|
||||||
|
//
|
||||||
|
// It returns one of the following:
|
||||||
|
// (0, nil) - watchdog isn't enabled or we aren't the watched PID.
|
||||||
|
// (0, err) - an error happened (e.g. error converting time).
|
||||||
|
// (time, nil) - watchdog is enabled and we can send ping.
|
||||||
|
// time is delay before inactive service will be killed.
|
||||||
|
func SdWatchdogEnabled(unsetEnvironment bool) (time.Duration, error) {
|
||||||
|
wusec := os.Getenv("WATCHDOG_USEC")
|
||||||
|
wpid := os.Getenv("WATCHDOG_PID")
|
||||||
|
if unsetEnvironment {
|
||||||
|
wusecErr := os.Unsetenv("WATCHDOG_USEC")
|
||||||
|
wpidErr := os.Unsetenv("WATCHDOG_PID")
|
||||||
|
if wusecErr != nil {
|
||||||
|
return 0, wusecErr
|
||||||
|
}
|
||||||
|
if wpidErr != nil {
|
||||||
|
return 0, wpidErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if wusec == "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
s, err := strconv.Atoi(wusec)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("error converting WATCHDOG_USEC: %s", err)
|
||||||
|
}
|
||||||
|
if s <= 0 {
|
||||||
|
return 0, fmt.Errorf("error WATCHDOG_USEC must be a positive number")
|
||||||
|
}
|
||||||
|
interval := time.Duration(s) * time.Microsecond
|
||||||
|
|
||||||
|
if wpid == "" {
|
||||||
|
return interval, nil
|
||||||
|
}
|
||||||
|
p, err := strconv.Atoi(wpid)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("error converting WATCHDOG_PID: %s", err)
|
||||||
|
}
|
||||||
|
if os.Getpid() != p {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return interval, nil
|
||||||
|
}
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -200,6 +200,7 @@ github.com/containers/storage/pkg/unshare
|
|||||||
github.com/coreos/go-iptables/iptables
|
github.com/coreos/go-iptables/iptables
|
||||||
# github.com/coreos/go-systemd/v22 v22.1.0
|
# github.com/coreos/go-systemd/v22 v22.1.0
|
||||||
github.com/coreos/go-systemd/v22/activation
|
github.com/coreos/go-systemd/v22/activation
|
||||||
|
github.com/coreos/go-systemd/v22/daemon
|
||||||
github.com/coreos/go-systemd/v22/dbus
|
github.com/coreos/go-systemd/v22/dbus
|
||||||
github.com/coreos/go-systemd/v22/internal/dlopen
|
github.com/coreos/go-systemd/v22/internal/dlopen
|
||||||
github.com/coreos/go-systemd/v22/journal
|
github.com/coreos/go-systemd/v22/journal
|
||||||
|
Reference in New Issue
Block a user