From c6c637da0012d54ddce32e06706c8903564b41cc Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 9 Jul 2019 13:19:15 +0200 Subject: [PATCH] healthcheck: support rootless mode now that dbus authentication works fine from a user namespace (systemd 241 works fine), we can enable rootless healthchecks. It uses "systemd-run --user" for creating the healthcheck timer and communicates with the user instance of systemd listening at $XDG_RUNTIME_DIR/systemd/private. Closes: https://github.com/containers/libpod/issues/3523 Signed-off-by: Giuseppe Scrivano --- libpod/healthcheck_linux.go | 49 ++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/libpod/healthcheck_linux.go b/libpod/healthcheck_linux.go index d47a3b7cd7..53fb271d1b 100644 --- a/libpod/healthcheck_linux.go +++ b/libpod/healthcheck_linux.go @@ -4,13 +4,50 @@ import ( "fmt" "os" "os/exec" + "path/filepath" + "strconv" "strings" + "github.com/containers/libpod/pkg/rootless" "github.com/coreos/go-systemd/dbus" + godbus "github.com/godbus/dbus" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) +func dbusAuthRootlessConnection(createBus func(opts ...godbus.ConnOption) (*godbus.Conn, error)) (*godbus.Conn, error) { + conn, err := createBus() + if err != nil { + return nil, err + } + + methods := []godbus.Auth{godbus.AuthExternal(strconv.Itoa(rootless.GetRootlessUID()))} + + err = conn.Auth(methods) + if err != nil { + conn.Close() + return nil, err + } + + return conn, nil +} + +func newRootlessConnection() (*dbus.Conn, error) { + return dbus.NewConnection(func() (*godbus.Conn, error) { + return dbusAuthRootlessConnection(func(opts ...godbus.ConnOption) (*godbus.Conn, error) { + path := filepath.Join(os.Getenv("XDG_RUNTIME_DIR"), "systemd/private") + return godbus.Dial(fmt.Sprintf("unix:path=%s", path)) + }) + }) +} + +func getConnection() (*dbus.Conn, error) { + if rootless.IsRootless() { + return newRootlessConnection() + } + return dbus.NewSystemdConnection() +} + // createTimer systemd timers for healthchecks of a container func (c *Container) createTimer() error { if c.disableHealthCheckSystemd() { @@ -21,9 +58,13 @@ func (c *Container) createTimer() error { return errors.Wrapf(err, "failed to get path for podman for a health check timer") } - var cmd = []string{"--unit", fmt.Sprintf("%s", c.ID()), fmt.Sprintf("--on-unit-inactive=%s", c.HealthCheckConfig().Interval.String()), "--timer-property=AccuracySec=1s", podman, "healthcheck", "run", c.ID()} + var cmd = []string{} + if rootless.IsRootless() { + cmd = append(cmd, "--user") + } + cmd = append(cmd, "--unit", fmt.Sprintf("%s", c.ID()), fmt.Sprintf("--on-unit-inactive=%s", c.HealthCheckConfig().Interval.String()), "--timer-property=AccuracySec=1s", podman, "healthcheck", "run", c.ID()) - conn, err := dbus.NewSystemdConnection() + conn, err := getConnection() if err != nil { return errors.Wrapf(err, "unable to get systemd connection to add healthchecks") } @@ -42,7 +83,7 @@ func (c *Container) startTimer() error { if c.disableHealthCheckSystemd() { return nil } - conn, err := dbus.NewSystemdConnection() + conn, err := getConnection() if err != nil { return errors.Wrapf(err, "unable to get systemd connection to start healthchecks") } @@ -57,7 +98,7 @@ func (c *Container) removeTimer() error { if c.disableHealthCheckSystemd() { return nil } - conn, err := dbus.NewSystemdConnection() + conn, err := getConnection() if err != nil { return errors.Wrapf(err, "unable to get systemd connection to remove healthchecks") }