mirror of
https://github.com/containers/podman.git
synced 2025-05-21 00:56:36 +08:00

currently, setting any sort of resource limit in a pod does nothing. With the newly refactored creation process in c/common, podman ca now set resources at a pod level meaning that resource related flags can now be exposed to podman pod create. cgroupfs and systemd are both supported with varying completion. cgroupfs is a much simpler process and one that is virtually complete for all resource types, the flags now just need to be added. systemd on the other hand has to be handeled via the dbus api meaning that the limits need to be passed as recognized properties to systemd. The properties added so far are the ones that podman pod create supports as well as `cpuset-mems` as this will be the next flag I work on. Signed-off-by: Charlie Doern <cdoern@redhat.com>
142 lines
3.9 KiB
Go
142 lines
3.9 KiB
Go
//go:build linux
|
|
// +build linux
|
|
|
|
package libpod
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/containers/common/pkg/cgroups"
|
|
"github.com/containers/podman/v4/libpod/define"
|
|
"github.com/containers/podman/v4/pkg/rootless"
|
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
|
"github.com/opencontainers/selinux/go-selinux/label"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// systemdSliceFromPath makes a new systemd slice under the given parent with
|
|
// the given name.
|
|
// The parent must be a slice. The name must NOT include ".slice"
|
|
func systemdSliceFromPath(parent, name string, resources *spec.LinuxResources) (string, error) {
|
|
cgroupPath, err := assembleSystemdCgroupName(parent, name)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
logrus.Debugf("Created cgroup path %s for parent %s and name %s", cgroupPath, parent, name)
|
|
|
|
if err := makeSystemdCgroup(cgroupPath, resources); err != nil {
|
|
return "", errors.Wrapf(err, "error creating cgroup %s", cgroupPath)
|
|
}
|
|
|
|
logrus.Debugf("Created cgroup %s", cgroupPath)
|
|
|
|
return cgroupPath, nil
|
|
}
|
|
|
|
func getDefaultSystemdCgroup() string {
|
|
if rootless.IsRootless() {
|
|
return SystemdDefaultRootlessCgroupParent
|
|
}
|
|
return SystemdDefaultCgroupParent
|
|
}
|
|
|
|
// makeSystemdCgroup creates a systemd Cgroup at the given location.
|
|
func makeSystemdCgroup(path string, resources *spec.LinuxResources) error {
|
|
res, err := GetLimits(resources)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
controller, err := cgroups.NewSystemd(getDefaultSystemdCgroup(), &res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if rootless.IsRootless() {
|
|
return controller.CreateSystemdUserUnit(path, rootless.GetRootlessUID())
|
|
}
|
|
err = controller.CreateSystemdUnit(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// deleteSystemdCgroup deletes the systemd cgroup at the given location
|
|
func deleteSystemdCgroup(path string, resources *spec.LinuxResources) error {
|
|
res, err := GetLimits(resources)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
controller, err := cgroups.NewSystemd(getDefaultSystemdCgroup(), &res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if rootless.IsRootless() {
|
|
conn, err := cgroups.GetUserConnection(rootless.GetRootlessUID())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer conn.Close()
|
|
return controller.DeleteByPathConn(path, conn)
|
|
}
|
|
|
|
return controller.DeleteByPath(path)
|
|
}
|
|
|
|
// assembleSystemdCgroupName creates a systemd cgroup path given a base and
|
|
// a new component to add.
|
|
// The base MUST be systemd slice (end in .slice)
|
|
func assembleSystemdCgroupName(baseSlice, newSlice string) (string, error) {
|
|
const sliceSuffix = ".slice"
|
|
|
|
if !strings.HasSuffix(baseSlice, sliceSuffix) {
|
|
return "", errors.Wrapf(define.ErrInvalidArg, "cannot assemble cgroup path with base %q - must end in .slice", baseSlice)
|
|
}
|
|
|
|
noSlice := strings.TrimSuffix(baseSlice, sliceSuffix)
|
|
final := fmt.Sprintf("%s/%s-%s%s", baseSlice, noSlice, newSlice, sliceSuffix)
|
|
|
|
return final, nil
|
|
}
|
|
|
|
var lvpRelabel = label.Relabel
|
|
var lvpInitLabels = label.InitLabels
|
|
var lvpReleaseLabel = label.ReleaseLabel
|
|
|
|
// LabelVolumePath takes a mount path for a volume and gives it an
|
|
// selinux label of either shared or not
|
|
func LabelVolumePath(path string) error {
|
|
_, mountLabel, err := lvpInitLabels([]string{})
|
|
if err != nil {
|
|
return errors.Wrapf(err, "error getting default mountlabels")
|
|
}
|
|
if err := lvpReleaseLabel(mountLabel); err != nil {
|
|
return errors.Wrapf(err, "error releasing label %q", mountLabel)
|
|
}
|
|
|
|
if err := lvpRelabel(path, mountLabel, true); err != nil {
|
|
if err == syscall.ENOTSUP {
|
|
logrus.Debugf("Labeling not supported on %q", path)
|
|
} else {
|
|
return errors.Wrapf(err, "error setting selinux label for %s to %q as shared", path, mountLabel)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Unmount umounts a target directory
|
|
func Unmount(mount string) {
|
|
if err := unix.Unmount(mount, unix.MNT_DETACH); err != nil {
|
|
if err != syscall.EINVAL {
|
|
logrus.Warnf("Failed to unmount %s : %v", mount, err)
|
|
} else {
|
|
logrus.Debugf("failed to unmount %s : %v", mount, err)
|
|
}
|
|
}
|
|
}
|