summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go25
-rw-r--r--libpod/container_inspect.go11
-rw-r--r--libpod/container_internal_linux.go2
-rw-r--r--libpod/define/container_inspect.go1
-rw-r--r--libpod/oci_conmon_linux.go43
-rw-r--r--libpod/stats.go24
6 files changed, 75 insertions, 31 deletions
diff --git a/libpod/container.go b/libpod/container.go
index c38acb513..482af43f3 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -6,9 +6,11 @@ import (
"io/ioutil"
"net"
"os"
+ "strings"
"time"
types040 "github.com/containernetworking/cni/pkg/types/040"
+ "github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/secrets"
"github.com/containers/image/v5/manifest"
"github.com/containers/podman/v3/libpod/define"
@@ -963,6 +965,29 @@ func (c *Container) cGroupPath() (string, error) {
return "", errors.Errorf("could not find any cgroup in %q", procPath)
}
+ cgroupManager := c.CgroupManager()
+ switch {
+ case c.config.CgroupsMode == cgroupSplit:
+ name := fmt.Sprintf("/libpod-payload-%s/", c.ID())
+ if index := strings.LastIndex(cgroupPath, name); index >= 0 {
+ return cgroupPath[:index+len(name)-1], nil
+ }
+ case cgroupManager == config.CgroupfsCgroupsManager:
+ name := fmt.Sprintf("/libpod-%s/", c.ID())
+ if index := strings.LastIndex(cgroupPath, name); index >= 0 {
+ return cgroupPath[:index+len(name)-1], nil
+ }
+ case cgroupManager == config.SystemdCgroupsManager:
+ // When running under systemd, try to detect the scope that was requested
+ // to be created. It improves the heuristic since we report the first
+ // cgroup that was created instead of the cgroup where PID 1 might have
+ // moved to.
+ name := fmt.Sprintf("/libpod-%s.scope/", c.ID())
+ if index := strings.LastIndex(cgroupPath, name); index >= 0 {
+ return cgroupPath[:index+len(name)-1], nil
+ }
+ }
+
return cgroupPath, nil
}
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 76a08ce30..83b643266 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -97,6 +97,16 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
return nil, err
}
+ cgroupPath, err := c.cGroupPath()
+ if err != nil {
+ // Handle the case where the container is not running or has no cgroup.
+ if errors.Is(err, define.ErrNoCgroups) || errors.Is(err, define.ErrCtrStopped) {
+ cgroupPath = ""
+ } else {
+ return nil, err
+ }
+ }
+
data := &define.InspectContainerData{
ID: config.ID,
Created: config.CreatedTime,
@@ -116,6 +126,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
StartedAt: runtimeInfo.StartedTime,
FinishedAt: runtimeInfo.FinishedTime,
Checkpointed: runtimeInfo.Checkpointed,
+ CgroupPath: cgroupPath,
},
Image: config.RootfsImageID,
ImageName: config.RootfsImageName,
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 364b77f29..956460c32 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -2618,7 +2618,7 @@ func (c *Container) getOCICgroupPath() (string, error) {
if err != nil {
return "", err
}
- return filepath.Join(selfCgroup, "container"), nil
+ return filepath.Join(selfCgroup, fmt.Sprintf("libpod-payload-%s", c.ID())), nil
case cgroupManager == config.SystemdCgroupsManager:
// When the OCI runtime is set to use Systemd as a cgroup manager, it
// expects cgroups to be passed as follows:
diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go
index 8e07cff81..677b39218 100644
--- a/libpod/define/container_inspect.go
+++ b/libpod/define/container_inspect.go
@@ -204,6 +204,7 @@ type InspectContainerState struct {
FinishedAt time.Time `json:"FinishedAt"`
Health HealthCheckResults `json:"Health,omitempty"`
Checkpointed bool `json:"Checkpointed,omitempty"`
+ CgroupPath string `json:"CgroupPath,omitempty"`
}
// Healthcheck returns the HealthCheckResults. This is used for old podman compat
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 3aab6864a..a83f166a3 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -816,41 +816,36 @@ func (r *ConmonOCIRuntime) CheckpointContainer(ctr *Container, options Container
filepath.Join("..", preCheckpointDir),
)
}
+
+ args = append(args, ctr.ID())
+ logrus.Debugf("the args to checkpoint: %s %s", r.path, strings.Join(args, " "))
+
runtimeDir, err := util.GetRuntimeDir()
if err != nil {
return 0, err
}
- args = append(args, ctr.ID())
- logrus.Debugf("the args to checkpoint: %s %s", r.path, strings.Join(args, " "))
-
- oldRuntimeDir, oldRuntimeDirSet := os.LookupEnv("XDG_RUNTIME_DIR")
- if err = os.Setenv("XDG_RUNTIME_DIR", runtimeDir); err != nil {
- return 0, errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
+ env := []string{fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir)}
+ if path, ok := os.LookupEnv("PATH"); ok {
+ env = append(env, fmt.Sprintf("PATH=%s", path))
}
+
runtime.LockOSThread()
if err := label.SetSocketLabel(ctr.ProcessLabel()); err != nil {
return 0, err
}
- defer func() {
- if oldRuntimeDirSet {
- if err := os.Setenv("XDG_RUNTIME_DIR", oldRuntimeDir); err != nil {
- logrus.Warnf("cannot resset XDG_RUNTIME_DIR: %v", err)
- }
- } else {
- if err := os.Unsetenv("XDG_RUNTIME_DIR"); err != nil {
- logrus.Warnf("cannot unset XDG_RUNTIME_DIR: %v", err)
- }
- }
- }()
runtimeCheckpointStarted := time.Now()
- err = utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, nil, r.path, args...)
+ err = utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, env, r.path, args...)
// Ignore error returned from SetSocketLabel("") call,
// can't recover.
- if labelErr := label.SetSocketLabel(""); labelErr != nil {
+ if labelErr := label.SetSocketLabel(""); labelErr == nil {
+ // Unlock the thread only if the process label could be restored
+ // successfully. Otherwise leave the thread locked and the Go runtime
+ // will terminate it once it returns to the threads pool.
+ runtime.UnlockOSThread()
+ } else {
logrus.Errorf("Unable to reset socket label: %q", labelErr)
}
- runtime.UnlockOSThread()
runtimeCheckpointDuration := func() int64 {
if options.PrintStats {
@@ -1464,10 +1459,14 @@ func startCommandGivenSelinux(cmd *exec.Cmd, ctr *Container) error {
err = cmd.Start()
// Ignore error returned from SetProcessLabel("") call,
// can't recover.
- if labelErr := label.SetProcessLabel(""); labelErr != nil {
+ if labelErr := label.SetProcessLabel(""); labelErr == nil {
+ // Unlock the thread only if the process label could be restored
+ // successfully. Otherwise leave the thread locked and the Go runtime
+ // will terminate it once it returns to the threads pool.
+ runtime.UnlockOSThread()
+ } else {
logrus.Errorf("Unable to set process label: %q", labelErr)
}
- runtime.UnlockOSThread()
return err
}
diff --git a/libpod/stats.go b/libpod/stats.go
index 975152535..cc1250e83 100644
--- a/libpod/stats.go
+++ b/libpod/stats.go
@@ -3,6 +3,7 @@
package libpod
import (
+ "math"
"strings"
"syscall"
"time"
@@ -68,7 +69,7 @@ func (c *Container) GetContainerStats(previousStats *define.ContainerStats) (*de
stats.AvgCPU = calculateAvgCPU(stats.CPU, previousStats.AvgCPU, previousStats.DataPoints)
stats.DataPoints = previousStats.DataPoints + 1
stats.MemUsage = cgroupStats.Memory.Usage.Usage
- stats.MemLimit = getMemLimit(cgroupStats.Memory.Usage.Limit)
+ stats.MemLimit = c.getMemLimit()
stats.MemPerc = (float64(stats.MemUsage) / float64(stats.MemLimit)) * 100
stats.PIDs = 0
if conState == define.ContainerStateRunning || conState == define.ContainerStatePaused {
@@ -91,22 +92,29 @@ func (c *Container) GetContainerStats(previousStats *define.ContainerStats) (*de
return stats, nil
}
-// getMemory limit returns the memory limit for a given cgroup
-// If the configured memory limit is larger than the total memory on the sys, the
-// physical system memory size is returned
-func getMemLimit(cgroupLimit uint64) uint64 {
+// getMemory limit returns the memory limit for a container
+func (c *Container) getMemLimit() uint64 {
+ memLimit := uint64(math.MaxUint64)
+
+ if c.config.Spec.Linux != nil && c.config.Spec.Linux.Resources != nil &&
+ c.config.Spec.Linux.Resources.Memory != nil && c.config.Spec.Linux.Resources.Memory.Limit != nil {
+ memLimit = uint64(*c.config.Spec.Linux.Resources.Memory.Limit)
+ }
+
si := &syscall.Sysinfo_t{}
err := syscall.Sysinfo(si)
if err != nil {
- return cgroupLimit
+ return memLimit
}
//nolint:unconvert
physicalLimit := uint64(si.Totalram)
- if cgroupLimit > physicalLimit {
+
+ if memLimit <= 0 || memLimit > physicalLimit {
return physicalLimit
}
- return cgroupLimit
+
+ return memLimit
}
// calculateCPUPercent calculates the cpu usage using the latest measurement in stats.