summaryrefslogtreecommitdiff
path: root/pkg/specgen
diff options
context:
space:
mode:
authorCharlie Doern <cdoern@redhat.com>2022-07-07 14:44:10 -0400
committerCharlie Doern <cdoern@redhat.com>2022-07-21 14:50:01 -0400
commitc00ea686fef5a382849307d393226971fb1da1f3 (patch)
tree4c63fc7fbbd8601fd639c7a30f22f9219ce8e013 /pkg/specgen
parent5f53a67742d6151fee3f62f4d82226da6246b461 (diff)
downloadpodman-c00ea686fef5a382849307d393226971fb1da1f3.tar.gz
podman-c00ea686fef5a382849307d393226971fb1da1f3.tar.bz2
podman-c00ea686fef5a382849307d393226971fb1da1f3.zip
resource limits for pods
added the following flags and handling for podman pod create --memory-swap --cpuset-mems --device-read-bps --device-write-bps --blkio-weight --blkio-weight-device --cpu-shares given the new backend for systemd in c/common, all of these can now be exposed to pod create. most of the heavy lifting (nearly all) is done within c/common. However, some rewiring needed to be done here as well! Signed-off-by: Charlie Doern <cdoern@redhat.com>
Diffstat (limited to 'pkg/specgen')
-rw-r--r--pkg/specgen/generate/container.go114
-rw-r--r--pkg/specgen/generate/container_create.go3
-rw-r--r--pkg/specgen/generate/oci.go35
-rw-r--r--pkg/specgen/generate/pod_create.go37
4 files changed, 124 insertions, 65 deletions
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 2248c9235..9bb7caace 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -302,60 +302,6 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
return warnings, nil
}
-// FinishThrottleDevices takes the temporary representation of the throttle
-// devices in the specgen and looks up the major and major minors. it then
-// sets the throttle devices proper in the specgen
-func FinishThrottleDevices(s *specgen.SpecGenerator) error {
- if bps := s.ThrottleReadBpsDevice; len(bps) > 0 {
- for k, v := range bps {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return err
- }
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
- if s.ResourceLimits.BlockIO == nil {
- s.ResourceLimits.BlockIO = new(spec.LinuxBlockIO)
- }
- s.ResourceLimits.BlockIO.ThrottleReadBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleReadBpsDevice, v)
- }
- }
- if bps := s.ThrottleWriteBpsDevice; len(bps) > 0 {
- for k, v := range bps {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return err
- }
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
- s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v)
- }
- }
- if iops := s.ThrottleReadIOPSDevice; len(iops) > 0 {
- for k, v := range iops {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return err
- }
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
- s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v)
- }
- }
- if iops := s.ThrottleWriteIOPSDevice; len(iops) > 0 {
- for k, v := range iops {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return err
- }
- v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
- v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
- s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v)
- }
- }
- return nil
-}
-
// ConfigToSpec takes a completed container config and converts it back into a specgenerator for purposes of cloning an existing container
func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID string) (*libpod.Container, *libpod.InfraInherit, error) {
c, err := rt.LookupContainer(contaierID)
@@ -540,3 +486,63 @@ func mapSecurityConfig(c *libpod.ContainerConfig, s *specgen.SpecGenerator) {
s.Groups = c.Groups
s.HostUsers = c.HostUsers
}
+
+// FinishThrottleDevices takes the temporary representation of the throttle
+// devices in the specgen and looks up the major and major minors. it then
+// sets the throttle devices proper in the specgen
+func FinishThrottleDevices(s *specgen.SpecGenerator) error {
+ if s.ResourceLimits == nil {
+ s.ResourceLimits = &spec.LinuxResources{}
+ }
+ if s.ResourceLimits.BlockIO == nil {
+ s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{}
+ }
+ if bps := s.ThrottleReadBpsDevice; len(bps) > 0 {
+ for k, v := range bps {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
+ }
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ if s.ResourceLimits.BlockIO == nil {
+ s.ResourceLimits.BlockIO = new(spec.LinuxBlockIO)
+ }
+ s.ResourceLimits.BlockIO.ThrottleReadBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleReadBpsDevice, v)
+ }
+ }
+ if bps := s.ThrottleWriteBpsDevice; len(bps) > 0 {
+ for k, v := range bps {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
+ }
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v)
+ }
+ }
+ if iops := s.ThrottleReadIOPSDevice; len(iops) > 0 {
+ for k, v := range iops {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
+ }
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v)
+ }
+ }
+ if iops := s.ThrottleWriteIOPSDevice; len(iops) > 0 {
+ for k, v := range iops {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return fmt.Errorf("could not parse throttle device at %s: %w", k, err)
+ }
+ v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v)
+ }
+ }
+ return nil
+}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 51d290bb4..389900820 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -55,9 +55,6 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
}
}
- if err := FinishThrottleDevices(s); err != nil {
- return nil, nil, nil, err
- }
// Set defaults for unset namespaces
if s.PidNS.IsDefault() {
defaultNS, err := GetDefaultNamespaceMode("pid", rtc, pod)
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index bb5f2d0ec..f59fe1011 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -309,6 +309,17 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
g.Config.Linux.Resources = s.ResourceLimits
}
+
+ weightDevices, err := WeightDevices(s.WeightDevice)
+ if err != nil {
+ return nil, err
+ }
+ if len(weightDevices) > 0 {
+ for _, dev := range weightDevices {
+ g.AddLinuxResourcesBlockIOWeightDevice(dev.Major, dev.Minor, *dev.Weight)
+ }
+ }
+
// Devices
// set the default rule at the beginning of device configuration
if !inUserNS && !s.Privileged {
@@ -345,14 +356,6 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
}
}
- for k, v := range s.WeightDevice {
- statT := unix.Stat_t{}
- if err := unix.Stat(k, &statT); err != nil {
- return nil, fmt.Errorf("failed to inspect '%s' in --blkio-weight-device: %w", k, err)
- }
- g.AddLinuxResourcesBlockIOWeightDevice((int64(unix.Major(uint64(statT.Rdev)))), (int64(unix.Minor(uint64(statT.Rdev)))), *v.Weight) //nolint: unconvert
- }
-
BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g)
g.ClearProcessEnv()
@@ -413,3 +416,19 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
return configSpec, nil
}
+
+func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) {
+ devs := []spec.LinuxWeightDevice{}
+ for k, v := range wtDevices {
+ statT := unix.Stat_t{}
+ if err := unix.Stat(k, &statT); err != nil {
+ return nil, fmt.Errorf("failed to inspect '%s' in --blkio-weight-device: %w", k, err)
+ }
+ dev := new(spec.LinuxWeightDevice)
+ dev.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+ dev.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+ dev.Weight = v.Weight
+ devs = append(devs, *dev)
+ }
+ return devs, nil
+}
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index 212d613fe..4e6362c9b 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -13,6 +13,7 @@ import (
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/podman/v4/pkg/specgenutil"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
)
@@ -21,6 +22,10 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) {
return nil, err
}
+ if p.PodSpecGen.ResourceLimits == nil {
+ p.PodSpecGen.ResourceLimits = &specs.LinuxResources{}
+ }
+
if !p.PodSpecGen.NoInfra {
imageName, err := PullOrBuildInfraImage(rt, p.PodSpecGen.InfraImage)
if err != nil {
@@ -38,10 +43,33 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) {
}
}
+ if !p.PodSpecGen.NoInfra {
+ err := FinishThrottleDevices(p.PodSpecGen.InfraContainerSpec)
+ if err != nil {
+ return nil, err
+ }
+ if p.PodSpecGen.InfraContainerSpec.ResourceLimits.BlockIO != nil {
+ p.PodSpecGen.ResourceLimits.BlockIO = p.PodSpecGen.InfraContainerSpec.ResourceLimits.BlockIO
+ }
+
+ weightDevices, err := WeightDevices(p.PodSpecGen.InfraContainerSpec.WeightDevice)
+ if err != nil {
+ return nil, err
+ }
+
+ if p.PodSpecGen.ResourceLimits != nil && len(weightDevices) > 0 {
+ if p.PodSpecGen.ResourceLimits.BlockIO == nil {
+ p.PodSpecGen.ResourceLimits.BlockIO = &specs.LinuxBlockIO{}
+ }
+ p.PodSpecGen.ResourceLimits.BlockIO.WeightDevice = weightDevices
+ }
+ }
+
options, err := createPodOptions(&p.PodSpecGen)
if err != nil {
return nil, err
}
+
pod, err := rt.NewPod(context.Background(), p.PodSpecGen, options...)
if err != nil {
return nil, err
@@ -55,6 +83,11 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) {
return nil, err
}
p.PodSpecGen.InfraContainerSpec.User = "" // infraSpec user will get incorrectly assigned via the container creation process, overwrite here
+ // infra's resource limits are used as a parsing tool,
+ // we do not want infra to get these resources in its cgroup
+ // make sure of that here.
+ p.PodSpecGen.InfraContainerSpec.ResourceLimits = nil
+ p.PodSpecGen.InfraContainerSpec.WeightDevice = nil
rtSpec, spec, opts, err := MakeContainer(context.Background(), rt, p.PodSpecGen.InfraContainerSpec, false, nil)
if err != nil {
return nil, err
@@ -122,6 +155,10 @@ func createPodOptions(p *specgen.PodSpecGenerator) ([]libpod.PodCreateOption, er
options = append(options, libpod.WithPodHostname(p.Hostname))
}
+ if p.ResourceLimits != nil {
+ options = append(options, libpod.WithPodResources(*p.ResourceLimits))
+ }
+
options = append(options, libpod.WithPodExitPolicy(p.ExitPolicy))
return options, nil