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:
@@ -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")
}
