cri: support blockio class in pod and container annotations
This patch adds support for a container annotation and two separate
pod annotations for controlling the blockio class of containers.
The container annotation can be used by a CRI client:
  "io.kubernetes.cri.blockio-class"
Pod annotations specify the blockio class in the K8s pod spec level:
  "blockio.resources.beta.kubernetes.io/pod"
  (pod-wide default for all containers within)
  "blockio.resources.beta.kubernetes.io/container.<container_name>"
  (container-specific overrides)
Correspondingly, this patch adds support for --blockio-class and
--blockio-config-file to ctr, too.
This implementation follows the resource class annotation pattern
introduced in RDT and merged in commit 893701220.
Signed-off-by: Antti Kervinen <antti.kervinen@intel.com>
			
			
This commit is contained in:
		
							
								
								
									
										237
									
								
								vendor/github.com/intel/goresctrl/pkg/cgroups/cgroupcontrol.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								vendor/github.com/intel/goresctrl/pkg/cgroups/cgroupcontrol.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,237 @@
 | 
			
		||||
// Copyright 2020-2021 Intel Corporation. All Rights Reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
package cgroups
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Controller is our enumerated type for cgroup controllers.
 | 
			
		||||
type Controller int
 | 
			
		||||
 | 
			
		||||
// Group represents a control group.
 | 
			
		||||
type Group string
 | 
			
		||||
 | 
			
		||||
//nolint
 | 
			
		||||
const (
 | 
			
		||||
	// UnkownController represents a controller of unknown type.
 | 
			
		||||
	UnknownController Controller = iota
 | 
			
		||||
	// blkio cgroup controller.
 | 
			
		||||
	Blkio
 | 
			
		||||
	// cpu cgroup controller.
 | 
			
		||||
	Cpu
 | 
			
		||||
	// cpuacct cgroup controller.
 | 
			
		||||
	Cpuacct
 | 
			
		||||
	// cpuset cgroup controller.
 | 
			
		||||
	Cpuset
 | 
			
		||||
	// devices cgroup controller.
 | 
			
		||||
	Devices
 | 
			
		||||
	// freezer cgroup controller.
 | 
			
		||||
	Freezer
 | 
			
		||||
	// hugetlb cgroup controller.
 | 
			
		||||
	Hugetlb
 | 
			
		||||
	// memory cgroup controller.
 | 
			
		||||
	Memory
 | 
			
		||||
	// net_cls cgroup controller.
 | 
			
		||||
	NetCls
 | 
			
		||||
	// net_prio cgroup controller.
 | 
			
		||||
	NetPrio
 | 
			
		||||
	// per_event cgroup controller.
 | 
			
		||||
	PerfEvent
 | 
			
		||||
	// pids cgroup controller.
 | 
			
		||||
	Pids
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// controllerNames maps controllers to names/relative paths.
 | 
			
		||||
	controllerNames = map[Controller]string{
 | 
			
		||||
		Blkio:     "blkio",
 | 
			
		||||
		Cpu:       "cpu",
 | 
			
		||||
		Cpuacct:   "cpuacct",
 | 
			
		||||
		Cpuset:    "cpuset",
 | 
			
		||||
		Devices:   "devices",
 | 
			
		||||
		Freezer:   "freezer",
 | 
			
		||||
		Hugetlb:   "hugetlb",
 | 
			
		||||
		Memory:    "memory",
 | 
			
		||||
		NetCls:    "net_cls",
 | 
			
		||||
		NetPrio:   "net_prio",
 | 
			
		||||
		PerfEvent: "perf_event",
 | 
			
		||||
		Pids:      "pids",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// controllerNames maps controllers to names/relative paths.
 | 
			
		||||
	controllerDirs = map[string]Controller{
 | 
			
		||||
		"blkio":      Blkio,
 | 
			
		||||
		"cpu":        Cpu,
 | 
			
		||||
		"cpuacct":    Cpuacct,
 | 
			
		||||
		"cpuset":     Cpuset,
 | 
			
		||||
		"devices":    Devices,
 | 
			
		||||
		"freezer":    Freezer,
 | 
			
		||||
		"hugetlb":    Hugetlb,
 | 
			
		||||
		"memory":     Memory,
 | 
			
		||||
		"net_cls":    NetCls,
 | 
			
		||||
		"net_prio":   NetPrio,
 | 
			
		||||
		"perf_event": PerfEvent,
 | 
			
		||||
		"pids":       Pids,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// String returns the name of the given controller.
 | 
			
		||||
func (c Controller) String() string {
 | 
			
		||||
	if name, ok := controllerNames[c]; ok {
 | 
			
		||||
		return name
 | 
			
		||||
	}
 | 
			
		||||
	return "unknown"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Path returns the absolute path of the given controller.
 | 
			
		||||
func (c Controller) Path() string {
 | 
			
		||||
	return path.Join(mountDir, c.String())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RelPath returns the relative path of the given controller.
 | 
			
		||||
func (c Controller) RelPath() string {
 | 
			
		||||
	return c.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Group returns the given group for the controller.
 | 
			
		||||
func (c Controller) Group(group string) Group {
 | 
			
		||||
	return Group(path.Join(mountDir, c.String(), group))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AsGroup returns the group for the given absolute directory path.
 | 
			
		||||
func AsGroup(absDir string) Group {
 | 
			
		||||
	return Group(absDir)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Controller returns the controller for the group.
 | 
			
		||||
func (g Group) Controller() Controller {
 | 
			
		||||
	relPath := strings.TrimPrefix(string(g), mountDir+"/")
 | 
			
		||||
	split := strings.SplitN(relPath, "/", 2)
 | 
			
		||||
	if len(split) > 0 {
 | 
			
		||||
		return controllerDirs[split[0]]
 | 
			
		||||
	}
 | 
			
		||||
	return UnknownController
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetTasks reads the pids of threads currently assigned to the group.
 | 
			
		||||
func (g Group) GetTasks() ([]string, error) {
 | 
			
		||||
	return g.readPids(Tasks)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetProcesses reads the pids of processes currently assigned to the group.
 | 
			
		||||
func (g Group) GetProcesses() ([]string, error) {
 | 
			
		||||
	return g.readPids(Procs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddTasks writes the given thread pids to the group.
 | 
			
		||||
func (g Group) AddTasks(pids ...string) error {
 | 
			
		||||
	return g.writePids(Tasks, pids...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddProcesses writes the given process pids to the group.
 | 
			
		||||
func (g Group) AddProcesses(pids ...string) error {
 | 
			
		||||
	return g.writePids(Procs, pids...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write writes the formatted data to the groups entry.
 | 
			
		||||
func (g Group) Write(entry, format string, args ...interface{}) error {
 | 
			
		||||
	entryPath := path.Join(string(g), entry)
 | 
			
		||||
	f, err := fsi.OpenFile(entryPath, os.O_WRONLY, 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return g.errorf("%q: failed to open for writing: %v", entry, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	data := fmt.Sprintf(format, args...)
 | 
			
		||||
	if _, err := f.Write([]byte(data)); err != nil {
 | 
			
		||||
		return g.errorf("%q: failed to write %q: %v", entry, data, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read the groups entry and return contents in a string
 | 
			
		||||
func (g Group) Read(entry string) (string, error) {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	entryPath := path.Join(string(g), entry)
 | 
			
		||||
	f, err := fsi.OpenFile(entryPath, os.O_RDONLY, 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", g.errorf("%q: failed to open for reading: %v", entry, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
	if _, err := buf.ReadFrom(f); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return buf.String(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// readPids reads pids from a cgroup's tasks or procs entry.
 | 
			
		||||
func (g Group) readPids(entry string) ([]string, error) {
 | 
			
		||||
	var pids []string
 | 
			
		||||
 | 
			
		||||
	pidFile := path.Join(string(g), entry)
 | 
			
		||||
 | 
			
		||||
	f, err := fsi.OpenFile(pidFile, os.O_RDONLY, 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, g.errorf("failed to open %q: %v", entry, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	s := bufio.NewScanner(f)
 | 
			
		||||
	for s.Scan() {
 | 
			
		||||
		pids = append(pids, s.Text())
 | 
			
		||||
	}
 | 
			
		||||
	if s.Err() != nil {
 | 
			
		||||
		return nil, g.errorf("failed to read %q: %v", entry, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pids, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// writePids writes pids to a cgroup's tasks or procs entry.
 | 
			
		||||
func (g Group) writePids(entry string, pids ...string) error {
 | 
			
		||||
	pidFile := path.Join(string(g), entry)
 | 
			
		||||
 | 
			
		||||
	f, err := fsi.OpenFile(pidFile, os.O_WRONLY, 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return g.errorf("failed to write pids to %q: %v", pidFile, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	for _, pid := range pids {
 | 
			
		||||
		if _, err := f.Write([]byte(pid)); err != nil {
 | 
			
		||||
			if !errors.Is(err, syscall.ESRCH) {
 | 
			
		||||
				return g.errorf("failed to write pid %s to %q: %v",
 | 
			
		||||
					pidFile, pid, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// error returns a formatted group-specific error.
 | 
			
		||||
func (g Group) errorf(format string, args ...interface{}) error {
 | 
			
		||||
	name := strings.TrimPrefix(string(g), mountDir+"/")
 | 
			
		||||
	return fmt.Errorf("cgroup "+name+": "+format, args...)
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user