Skip to content

Commit

Permalink
use runc creation logic
Browse files Browse the repository at this point in the history
switch c/common to use runc cgroup creation so that we can use resource limits

this entails modifying both the CgroupControl struct to contain a runc configs.Cgroup entity
as well as adding actual functionality to all of the Apply() functions for the various resource groups

Signed-off-by: cdoern <cdoern@redhat.com>
Signed-off-by: cdoern <cbdoer23@g.holycross.edu>
  • Loading branch information
cdoern committed Mar 2, 2022
1 parent 9880eb4 commit 2c44075
Show file tree
Hide file tree
Showing 39 changed files with 4,251 additions and 170 deletions.
2 changes: 1 addition & 1 deletion docs/containers.conf.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ Number of seconds to wait for container to exit before sending kill signal.

**exit_command_delay**=300

Number of seconds to wait for the API process for the exec call before sending exit command mimicing the Docker behavior of 5 minutes (in seconds).
Number of seconds to wait for the API process for the exec call before sending exit command mimicking the Docker behavior of 5 minutes (in seconds).

**tmp_dir**="/run/libpod"

Expand Down
2 changes: 1 addition & 1 deletion libnetwork/netavark/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo
return nil, errors.Wrapf(types.ErrInvalidArg, "unsupported driver %s", newNetwork.Driver)
}

// add gatway when not internal or dns enabled
// add gateway when not internal or dns enabled
addGateway := !newNetwork.Internal || newNetwork.DNSEnabled
err = internalutil.ValidateSubnets(newNetwork, addGateway, usedNetworks)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion libnetwork/netavark/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ func parseNetwork(network *types.Network) error {
return errors.Errorf("invalid network ID %q", network.ID)
}

// add gatway when not internal or dns enabled
// add gateway when not internal or dns enabled
addGateway := !network.Internal || network.DNSEnabled
return util.ValidateSubnets(network, addGateway, nil)
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/cgroups/blkio.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build !linux
// +build !linux

package cgroups

import (
Expand Down
206 changes: 206 additions & 0 deletions pkg/cgroups/blkio_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
//go:build linux
// +build linux

package cgroups

import (
"bufio"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/pkg/errors"
)

type linuxBlkioHandler struct {
blkio fs.BlkioGroup
}

func getBlkioHandler() *linuxBlkioHandler {
return &linuxBlkioHandler{}
}

// Apply set the specified constraints
func (c *linuxBlkioHandler) Apply(ctr *CgroupControl, res *configs.Resources) error {
if ctr.cgroup2 {
path := filepath.Join(cgroupRoot, ctr.config.Path)
var bfq *os.File
// This has to do with checking for the bfq handler
if res.BlkioWeight != 0 || len(res.BlkioWeightDevice) > 0 {
var err error
bfq, err = cgroups.OpenFile(path, "io.bfq.weight", os.O_RDWR)
if err == nil {
defer bfq.Close()
} else if !os.IsNotExist(err) {
return err
}
}

if res.BlkioWeight != 0 {
if bfq != nil {
if _, err := bfq.WriteString(strconv.FormatUint(uint64(res.BlkioWeight), 10)); err != nil {
return err
}
} else {
v := cgroups.ConvertBlkIOToIOWeightValue(res.BlkioWeight)
if err := cgroups.WriteFile(path, "io.weight", strconv.FormatUint(v, 10)); err != nil {
return err
}
}
}
if bfqDeviceWeightSupported(bfq) {
for _, wd := range res.BlkioWeightDevice {
if _, err := bfq.WriteString(wd.WeightString() + "\n"); err != nil {
return fmt.Errorf("setting device weight %q: %w", wd.WeightString(), err)
}
}
}
for _, td := range res.BlkioThrottleReadBpsDevice {
if err := cgroups.WriteFile(path, "io.max", td.StringName("rbps")); err != nil {
return err
}
}
for _, td := range res.BlkioThrottleWriteBpsDevice {
if err := cgroups.WriteFile(path, "io.max", td.StringName("wbps")); err != nil {
return err
}
}
for _, td := range res.BlkioThrottleReadIOPSDevice {
if err := cgroups.WriteFile(path, "io.max", td.StringName("riops")); err != nil {
return err
}
}
for _, td := range res.BlkioThrottleWriteIOPSDevice {
if err := cgroups.WriteFile(path, "io.max", td.StringName("wiops")); err != nil {
return err
}
}
return nil
}
// use the runc fs1 functions otherwise, maintaining the fs2 functions here for future development
path := filepath.Join(cgroupRoot, Blkio, ctr.config.Path)
return c.blkio.Set(path, res)
}

// Create the cgroup
func (c *linuxBlkioHandler) Create(ctr *CgroupControl) (bool, error) {
return ctr.createCgroupDirectory(Blkio)
}

// Destroy the cgroup
func (c *linuxBlkioHandler) Destroy(ctr *CgroupControl) error {
return rmDirRecursively(ctr.getCgroupv1Path(Blkio))
}

// Stat fills a metrics structure with usage stats for the controller
func (c *linuxBlkioHandler) Stat(ctr *CgroupControl, m *cgroups.Stats) error {
var ioServiceBytesRecursive []cgroups.BlkioStatEntry

if ctr.cgroup2 {
// more details on the io.stat file format:X https://facebookmicrosites.github.io/cgroup2/docs/io-controller.html
values, err := readCgroup2MapFile(ctr, "io.stat")
if err != nil {
return err
}
for k, v := range values {
d := strings.Split(k, ":")
if len(d) != 2 {
continue
}
minor, err := strconv.ParseUint(d[0], 10, 0)
if err != nil {
return err
}
major, err := strconv.ParseUint(d[1], 10, 0)
if err != nil {
return err
}

for _, item := range v {
d := strings.Split(item, "=")
if len(d) != 2 {
continue
}
op := d[0]

// Accommodate the cgroup v1 naming
switch op {
case "rbytes":
op = "read"
case "wbytes":
op = "write"
}

value, err := strconv.ParseUint(d[1], 10, 0)
if err != nil {
return err
}

entry := cgroups.BlkioStatEntry{
Op: op,
Major: major,
Minor: minor,
Value: value,
}
ioServiceBytesRecursive = append(ioServiceBytesRecursive, entry)
}
}
} else {
BlkioRoot := ctr.getCgroupv1Path(Blkio)

p := filepath.Join(BlkioRoot, "blkio.throttle.io_service_bytes_recursive")
f, err := os.Open(p)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return errors.Wrapf(err, "open %s", p)
}
defer f.Close()

scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
parts := strings.Fields(line)
if len(parts) < 3 {
continue
}
d := strings.Split(parts[0], ":")
if len(d) != 2 {
continue
}
minor, err := strconv.ParseUint(d[0], 10, 0)
if err != nil {
return err
}
major, err := strconv.ParseUint(d[1], 10, 0)
if err != nil {
return err
}

op := parts[1]

value, err := strconv.ParseUint(parts[2], 10, 0)
if err != nil {
return err
}
entry := cgroups.BlkioStatEntry{
Op: op,
Major: major,
Minor: minor,
Value: value,
}
ioServiceBytesRecursive = append(ioServiceBytesRecursive, entry)
}
if err := scanner.Err(); err != nil {
return errors.Wrapf(err, "parse %s", p)
}
}
m.BlkioStats.IoServiceBytesRecursive = ioServiceBytesRecursive
return nil
}
61 changes: 3 additions & 58 deletions pkg/cgroups/cgroups.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build !linux
// +build !linux

package cgroups

import (
Expand Down Expand Up @@ -248,47 +251,6 @@ func (c *CgroupControl) getCgroupv1Path(name string) string {
return filepath.Join(cgroupRoot, name, c.path)
}

// createCgroupv2Path creates the cgroupv2 path and enables all the available controllers
func createCgroupv2Path(path string) (deferredError error) {
if !strings.HasPrefix(path, cgroupRoot+"/") {
return fmt.Errorf("invalid cgroup path %s", path)
}
content, err := ioutil.ReadFile(cgroupRoot + "/cgroup.controllers")
if err != nil {
return err
}
ctrs := bytes.Fields(content)
res := append([]byte("+"), bytes.Join(ctrs, []byte(" +"))...)

current := "/sys/fs"
elements := strings.Split(path, "/")
for i, e := range elements[3:] {
current = filepath.Join(current, e)
if i > 0 {
if err := os.Mkdir(current, 0755); err != nil {
if !os.IsExist(err) {
return err
}
} else {
// If the directory was created, be sure it is not left around on errors.
defer func() {
if deferredError != nil {
os.Remove(current)
}
}()
}
}
// We enable the controllers for all the path components except the last one. It is not allowed to add
// PIDs if there are already enabled controllers.
if i < len(elements[3:])-1 {
if err := ioutil.WriteFile(filepath.Join(current, "cgroup.subtree_control"), res, 0755); err != nil {
return err
}
}
}
return nil
}

// initialize initializes the specified hierarchy
func (c *CgroupControl) initialize() (err error) {
createdSoFar := map[string]controllerHandler{}
Expand Down Expand Up @@ -332,23 +294,6 @@ func (c *CgroupControl) initialize() (err error) {
return nil
}

func (c *CgroupControl) createCgroupDirectory(controller string) (bool, error) {
cPath := c.getCgroupv1Path(controller)
_, err := os.Stat(cPath)
if err == nil {
return false, nil
}

if !os.IsNotExist(err) {
return false, err
}

if err := os.MkdirAll(cPath, 0755); err != nil {
return false, errors.Wrapf(err, "error creating cgroup for %s", controller)
}
return true, nil
}

func readFileAsUint64(path string) (uint64, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
Expand Down
Loading

0 comments on commit 2c44075

Please sign in to comment.