aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin Rothberg <rothberg@redhat.com>2020-08-13 12:53:28 +0200
committerMatthew Heon <matthew.heon@pm.me>2020-08-20 12:16:52 -0400
commitcb4c5fc9c262f14c935e843224ee80e098d58224 (patch)
tree4bb05014e72870a6c4bc6f54fdedc015254bea6a
parent5e50ba3ecbdd738679849d7a86fef0c4ab7f109d (diff)
downloadpodman-cb4c5fc9c262f14c935e843224ee80e098d58224.tar.gz
podman-cb4c5fc9c262f14c935e843224ee80e098d58224.tar.bz2
podman-cb4c5fc9c262f14c935e843224ee80e098d58224.zip
podman.service: use sdnotiy
Commit 2b6dd3fb4384 set the killmode of the podman.service to the systemd default which ultimately lead to the problem that systemd will kill *all* processes inside the unit's cgroup and hence kill all containers whenever the service is stopped. Fix it by setting the type to sdnotify and the killmode to process. `podman system service` will send the necessary notify messages when the NOTIFY_SOCKET is set and unset it right after to prevent the backend and container runtimes from jumping in between and send messages as well. Fixes: #7294 Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
-rw-r--r--contrib/systemd/system/podman.service3
-rw-r--r--pkg/api/server/server.go27
-rw-r--r--vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go84
-rw-r--r--vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go73
-rw-r--r--vendor/modules.txt1
5 files changed, 186 insertions, 2 deletions
diff --git a/contrib/systemd/system/podman.service b/contrib/systemd/system/podman.service
index c8751168d..e14bbe078 100644
--- a/contrib/systemd/system/podman.service
+++ b/contrib/systemd/system/podman.service
@@ -6,5 +6,6 @@ Documentation=man:podman-system-service(1)
StartLimitIntervalSec=0
[Service]
-Type=simple
+Type=notify
+KillMode=process
ExecStart=/usr/bin/podman system service
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 1c6007745..bfa5fcdce 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -2,6 +2,7 @@ package server
import (
"context"
+ "fmt"
"log"
"net"
"net/http"
@@ -17,6 +18,7 @@ import (
"github.com/containers/libpod/v2/pkg/api/handlers"
"github.com/containers/libpod/v2/pkg/api/server/idletracker"
"github.com/coreos/go-systemd/v22/activation"
+ "github.com/coreos/go-systemd/v22/daemon"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -147,8 +149,31 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
return &server, nil
}
-// Serve starts responding to HTTP requests
+// If the NOTIFY_SOCKET is set, communicate the PID and readiness, and
+// further unset NOTIFY_SOCKET to prevent containers from sending
+// messages and unset INVOCATION_ID so conmon and containers are in
+// the correct cgroup.
+func setupSystemd() {
+ if len(os.Getenv("NOTIFY_SOCKET")) == 0 {
+ return
+ }
+ payload := fmt.Sprintf("MAINPID=%d", os.Getpid())
+ payload += "\n"
+ payload += daemon.SdNotifyReady
+ if sent, err := daemon.SdNotify(true, payload); err != nil {
+ logrus.Errorf("Error notifying systemd of Conmon PID: %s", err.Error())
+ } else if sent {
+ logrus.Debugf("Notify sent successfully")
+ }
+
+ if err := os.Unsetenv("INVOCATION_ID"); err != nil {
+ logrus.Errorf("Error unsetting INVOCATION_ID: %s", err.Error())
+ }
+}
+
+// Serve starts responding to HTTP requests.
func (s *APIServer) Serve() error {
+ setupSystemd()
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
errChan := make(chan error, 1)
diff --git a/vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go b/vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go
new file mode 100644
index 000000000..ba4ae31f1
--- /dev/null
+++ b/vendor/github.com/coreos/go-systemd/v22/daemon/sdnotify.go
@@ -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
+}
diff --git a/vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go b/vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go
new file mode 100644
index 000000000..7a0e0d3a5
--- /dev/null
+++ b/vendor/github.com/coreos/go-systemd/v22/daemon/watchdog.go
@@ -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
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 17c195326..a3d21b273 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -200,6 +200,7 @@ github.com/containers/storage/pkg/unshare
github.com/coreos/go-iptables/iptables
# github.com/coreos/go-systemd/v22 v22.1.0
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/internal/dlopen
github.com/coreos/go-systemd/v22/journal