containerd/vendor/github.com/intel/goresctrl/pkg/cgroups/fsimock.go
Antti Kervinen 10576c298e 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>
2022-04-29 11:44:09 +03:00

231 lines
5.3 KiB
Go

// Copyright 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.
// This module implements a mock filesystem that can be used as a
// replacement for the native filesystem interface (fsi).
package cgroups
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
)
type fsMock struct {
files map[string]*mockFile // filesystem contents
}
type mockFile struct {
// User-defined file properties
data []byte // contents of the file
// User/fsimock-defined properties
info *mockFileInfo
// File-specific user-overrides for the default file behavior
open func(string) (fileIface, error)
read func([]byte) (int, error)
write func([]byte) (int, error)
// fsimock-defined properties
fs *fsMock
filename string
handle *mockFileHandle
writeHistory [][]byte
}
type mockFileHandle struct {
pos int
}
type mockFileInfo struct {
mode os.FileMode
name string
mf *mockFile
}
func NewFsiMock(files map[string]mockFile) fsiIface {
mfs := fsMock{}
mfs.files = map[string]*mockFile{}
for filename, usermf := range files {
mf := usermf
if mf.info == nil {
mf.info = &mockFileInfo{}
}
if mf.info.name == "" {
mf.info.name = filepath.Base(filename)
}
mf.filename = filename
mf.info.mf = &mf
mf.fs = &mfs
mfs.files[filename] = &mf
}
return &mfs
}
func (mfs fsMock) OpenFile(name string, flag int, perm os.FileMode) (fileIface, error) {
fsmockLog("OpenFile(%q, %d, %d)", name, flag, perm)
if mf, ok := mfs.files[name]; ok {
mf.handle = &mockFileHandle{}
if mf.open != nil {
return mf.open(name)
}
return *mf, nil
}
return nil, fsmockErrorf("%q: file not found", name)
}
func (mfs fsMock) Open(name string) (fileIface, error) {
return mfs.OpenFile(name, 0, 0)
}
func (mfs fsMock) Walk(path string, walkFn filepath.WalkFunc) error {
dirPath := strings.TrimSuffix(path, "/")
info, err := mfs.Lstat(dirPath)
if err != nil {
err = walkFn(path, nil, err)
return err
}
if !info.IsDir() {
return walkFn(path, info, nil)
}
err = walkFn(path, info, nil)
if err != nil {
return err
}
for _, name := range mfs.dirContents(dirPath) {
if err = mfs.Walk(dirPath+"/"+name, walkFn); err != nil && err != filepath.SkipDir {
return err
}
}
return nil
}
func (mfs fsMock) dirContents(path string) []string {
dirPathS := strings.TrimSuffix(path, "/") + "/"
contentSet := map[string]struct{}{}
for filename := range mfs.files {
if !strings.HasPrefix(filename, dirPathS) {
continue
}
relToDirPath := strings.TrimPrefix(filename, dirPathS)
names := strings.SplitN(relToDirPath, "/", 2)
contentSet[names[0]] = struct{}{}
}
contents := make([]string, 0, len(contentSet))
for name := range contentSet {
contents = append(contents, name)
}
return contents
}
func (mfs fsMock) Lstat(path string) (os.FileInfo, error) {
if mf, ok := mfs.files[path]; ok {
return *mf.info, nil
}
if len(mfs.dirContents(path)) > 0 {
return mockFileInfo{
name: filepath.Base(path),
mode: os.ModeDir,
}, nil
}
return mockFileInfo{}, fsmockErrorf("%q: file not found", path)
}
func (mfi mockFileInfo) Name() string {
return mfi.name
}
func (mfi mockFileInfo) Size() int64 {
if mfi.mf != nil {
return int64(len(mfi.mf.data))
}
return 0
}
func (mfi mockFileInfo) Mode() os.FileMode {
return mfi.mode
}
func (mfi mockFileInfo) ModTime() time.Time {
return time.Time{}
}
func (mfi mockFileInfo) IsDir() bool {
return mfi.mode&os.ModeDir != 0
}
func (mfi mockFileInfo) Sys() interface{} {
return nil
}
func (mf mockFile) Write(b []byte) (n int, err error) {
pos := mf.handle.pos
if mf.write != nil {
n, err = mf.write(b)
if err == nil {
mf.fs.files[mf.filename].writeHistory = append(mf.fs.files[mf.filename].writeHistory, b)
}
} else {
newpos := pos + len(b)
if newpos > cap(mf.data) {
newdata := make([]byte, newpos)
copy(newdata, mf.data)
mf.data = newdata
}
copy(mf.data[pos:newpos], b)
mf.handle.pos = newpos
if f, ok := mf.fs.files[mf.filename]; ok {
f.data = mf.data
}
mf.fs.files[mf.filename].writeHistory = append(mf.fs.files[mf.filename].writeHistory, b)
}
fsmockLog("{%q, pos=%d}.Write([%d]byte(%q)) = (%d, %v) %q", mf.filename, pos, len(b), string(b), n, err, mf.fs.files[mf.filename].data)
return n, err
}
func (mf mockFile) Read(b []byte) (n int, err error) {
pos := mf.handle.pos
if mf.read != nil {
n, err = mf.read(b)
} else {
n = len(mf.data) - pos
err = nil
if n <= 0 {
err = io.EOF
}
if n > cap(b) {
n = cap(b)
}
copy(b, mf.data[pos:pos+n])
mf.handle.pos += n
}
fsmockLog("{%q, pos=%d}.Read([%d]byte) = (%d, %v)\n", mf.filename, pos, len(b), n, err)
return
}
func (mf mockFile) Close() error {
return nil
}
func fsmockLog(format string, args ...interface{}) {
fmt.Printf("fsmock: "+format+"\n", args...)
}
func fsmockErrorf(format string, args ...interface{}) error {
return fmt.Errorf("fsmock: "+format, args...)
}