diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container.go | 25 | ||||
-rw-r--r-- | libpod/container_inspect.go | 11 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 2 | ||||
-rw-r--r-- | libpod/define/container_inspect.go | 1 | ||||
-rw-r--r-- | libpod/oci_conmon_linux.go | 43 | ||||
-rw-r--r-- | libpod/stats.go | 24 |
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. |