116 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
| package libpod
 | |
| 
 | |
| 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() {
 | |
| 		return nil
 | |
| 	}
 | |
| 	podman, err := os.Executable()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrapf(err, "failed to get path for podman for a health check timer")
 | |
| 	}
 | |
| 
 | |
| 	var cmd = []string{}
 | |
| 	if rootless.IsRootless() {
 | |
| 		cmd = append(cmd, "--user")
 | |
| 	}
 | |
| 	cmd = append(cmd, "--unit", c.ID(), fmt.Sprintf("--on-unit-inactive=%s", c.HealthCheckConfig().Interval.String()), "--timer-property=AccuracySec=1s", podman, "healthcheck", "run", c.ID())
 | |
| 
 | |
| 	conn, err := getConnection()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrapf(err, "unable to get systemd connection to add healthchecks")
 | |
| 	}
 | |
| 	conn.Close()
 | |
| 	logrus.Debugf("creating systemd-transient files: %s %s", "systemd-run", cmd)
 | |
| 	systemdRun := exec.Command("systemd-run", cmd...)
 | |
| 	_, err = systemdRun.CombinedOutput()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // startTimer starts a systemd timer for the healthchecks
 | |
| func (c *Container) startTimer() error {
 | |
| 	if c.disableHealthCheckSystemd() {
 | |
| 		return nil
 | |
| 	}
 | |
| 	conn, err := getConnection()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrapf(err, "unable to get systemd connection to start healthchecks")
 | |
| 	}
 | |
| 	defer conn.Close()
 | |
| 	_, err = conn.StartUnit(fmt.Sprintf("%s.service", c.ID()), "fail", nil)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // removeTimer removes the systemd timer and unit files
 | |
| // for the container
 | |
| func (c *Container) removeTimer() error {
 | |
| 	if c.disableHealthCheckSystemd() {
 | |
| 		return nil
 | |
| 	}
 | |
| 	conn, err := getConnection()
 | |
| 	if err != nil {
 | |
| 		return errors.Wrapf(err, "unable to get systemd connection to remove healthchecks")
 | |
| 	}
 | |
| 	defer conn.Close()
 | |
| 	timerFile := fmt.Sprintf("%s.timer", c.ID())
 | |
| 	_, err = conn.StopUnit(timerFile, "fail", nil)
 | |
| 
 | |
| 	// We want to ignore errors where the timer unit has already been removed. The error
 | |
| 	// return is generic so we have to check against the string in the error
 | |
| 	if err != nil && strings.HasSuffix(err.Error(), ".timer not loaded.") {
 | |
| 		return nil
 | |
| 	}
 | |
| 	return err
 | |
| }
 |