Merge pull request #9577 from containerd/dependabot/go_modules/github.com/intel/goresctrl-0.6.0

build(deps): bump github.com/intel/goresctrl from 0.5.0 to 0.6.0
This commit is contained in:
Akihiro Suda 2023-12-28 00:29:05 +00:00 committed by GitHub
commit ee9638dbba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 117 additions and 1059 deletions

2
go.mod
View File

@ -34,7 +34,7 @@ require (
github.com/google/uuid v1.5.0 github.com/google/uuid v1.5.0
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/intel/goresctrl v0.5.0 github.com/intel/goresctrl v0.6.0
github.com/klauspost/compress v1.17.4 github.com/klauspost/compress v1.17.4
github.com/minio/sha256-simd v1.0.1 github.com/minio/sha256-simd v1.0.1
github.com/moby/locker v1.0.1 github.com/moby/locker v1.0.1

4
go.sum
View File

@ -177,8 +177,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/intel/goresctrl v0.5.0 h1:kcDhjE3ZF/mNrJuRzLS3LY2Hp6atFaF1XVFBT7SVL2g= github.com/intel/goresctrl v0.6.0 h1:lOqo9o+uXtqPwSB4vpd1greUcWlkBSTPdnbTFgRILf4=
github.com/intel/goresctrl v0.5.0/go.mod h1:mIe63ggylWYr0cU/l8n11FAkesqfvuP3oktIsxvu0T0= github.com/intel/goresctrl v0.6.0/go.mod h1:Qg+rhwvfW78p22OJi649sCH71bJIBX7zT0b+IGe69eE=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=

View File

@ -115,7 +115,6 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
"github.com/intel/goresctrl/pkg/cgroups"
grclog "github.com/intel/goresctrl/pkg/log" grclog "github.com/intel/goresctrl/pkg/log"
goresctrlpath "github.com/intel/goresctrl/pkg/path" goresctrlpath "github.com/intel/goresctrl/pkg/path"
) )
@ -143,7 +142,7 @@ var log grclog.Logger = grclog.NewLoggerWrapper(stdlog.New(os.Stderr, "[ blockio
// classBlockIO connects user-defined block I/O classes to // classBlockIO connects user-defined block I/O classes to
// corresponding cgroups blockio controller parameters. // corresponding cgroups blockio controller parameters.
var classBlockIO = map[string]cgroups.BlockIOParameters{} var classBlockIO = map[string]BlockIOParameters{}
// SetLogger sets the logger instance to be used by the package. // SetLogger sets the logger instance to be used by the package.
// Examples: // Examples:
@ -173,7 +172,7 @@ func SetConfigFromFile(filename string, force bool) error {
// SetConfigFromData parses and applies configuration from data. // SetConfigFromData parses and applies configuration from data.
func SetConfigFromData(data []byte, force bool) error { func SetConfigFromData(data []byte, force bool) error {
config := &Config{} config := &Config{}
if err := yaml.Unmarshal(data, &config); err != nil { if err := yaml.UnmarshalStrict(data, &config); err != nil {
return err return err
} }
return SetConfig(config, force) return SetConfig(config, force)
@ -184,7 +183,7 @@ func SetConfig(opt *Config, force bool) error {
if opt == nil { if opt == nil {
// Setting nil configuration clears current configuration. // Setting nil configuration clears current configuration.
// SetConfigFromData([]byte(""), dontcare) arrives here. // SetConfigFromData([]byte(""), dontcare) arrives here.
classBlockIO = map[string]cgroups.BlockIOParameters{} classBlockIO = map[string]BlockIOParameters{}
return nil return nil
} }
@ -193,7 +192,7 @@ func SetConfig(opt *Config, force bool) error {
log.Warnf("configuration validation partly disabled due to I/O scheduler detection error %#v", ioSchedulerDetectionError.Error()) log.Warnf("configuration validation partly disabled due to I/O scheduler detection error %#v", ioSchedulerDetectionError.Error())
} }
classBlockIO = map[string]cgroups.BlockIOParameters{} classBlockIO = map[string]BlockIOParameters{}
// Create cgroup blockio parameters for each blockio class // Create cgroup blockio parameters for each blockio class
for class := range opt.Classes { for class := range opt.Classes {
cgBlockIO, err := devicesParametersToCgBlockIO(opt.Classes[class], currentIOSchedulers) cgBlockIO, err := devicesParametersToCgBlockIO(opt.Classes[class], currentIOSchedulers)
@ -219,22 +218,6 @@ func GetClasses() []string {
return classNames return classNames
} }
// SetCgroupClass sets cgroup blkio controller parameters to match
// blockio class. "group" is the cgroup directory of the container
// without mountpoint and controller (blkio) directories:
// "/kubepods/burstable/POD_ID/CONTAINER_ID".
func SetCgroupClass(group string, class string) error {
cgBlockIO, ok := classBlockIO[class]
if !ok {
return fmt.Errorf("no BlockIO parameters for class %#v", class)
}
err := cgroups.ResetBlkioParameters(group, cgBlockIO)
if err != nil {
return fmt.Errorf("assigning container in cgroup %q to class %#v failed: %w", group, class, err)
}
return nil
}
// getCurrentIOSchedulers returns currently active I/O scheduler used for each block device in the system. // getCurrentIOSchedulers returns currently active I/O scheduler used for each block device in the system.
// Returns schedulers in a map: {"/dev/sda": "bfq"} // Returns schedulers in a map: {"/dev/sda": "bfq"}
func getCurrentIOSchedulers() (map[string]string, error) { func getCurrentIOSchedulers() (map[string]string, error) {
@ -274,9 +257,9 @@ func getCurrentIOSchedulers() (map[string]string, error) {
} }
// deviceParametersToCgBlockIO converts single blockio class parameters into cgroups blkio format. // deviceParametersToCgBlockIO converts single blockio class parameters into cgroups blkio format.
func devicesParametersToCgBlockIO(dps []DevicesParameters, currentIOSchedulers map[string]string) (cgroups.BlockIOParameters, error) { func devicesParametersToCgBlockIO(dps []DevicesParameters, currentIOSchedulers map[string]string) (BlockIOParameters, error) {
errs := []error{} errs := []error{}
blkio := cgroups.NewBlockIOParameters() blkio := NewBlockIOParameters()
for _, dp := range dps { for _, dp := range dps {
var err error var err error
var weight, throttleReadBps, throttleWriteBps, throttleReadIOPS, throttleWriteIOPS int64 var weight, throttleReadBps, throttleWriteBps, throttleReadIOPS, throttleWriteIOPS int64

View File

@ -0,0 +1,103 @@
// 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 blockio
// BlockIOParameters contains cgroups blockio controller parameters.
//
// Effects of Weight and Rate values in SetBlkioParameters():
// Value | Effect
// -------+-------------------------------------------------------------------
//
// -1 | Do not write to cgroups, value is missing.
// 0 | Write to cgroups, will clear the setting as specified in cgroups blkio interface.
// other | Write to cgroups, sets the value.
type BlockIOParameters struct {
Weight int64
WeightDevice DeviceWeights
ThrottleReadBpsDevice DeviceRates
ThrottleWriteBpsDevice DeviceRates
ThrottleReadIOPSDevice DeviceRates
ThrottleWriteIOPSDevice DeviceRates
}
// DeviceWeight contains values for
// - blkio.[io-scheduler].weight
type DeviceWeight struct {
Major int64
Minor int64
Weight int64
}
// DeviceRate contains values for
// - blkio.throttle.read_bps_device
// - blkio.throttle.write_bps_device
// - blkio.throttle.read_iops_device
// - blkio.throttle.write_iops_device
type DeviceRate struct {
Major int64
Minor int64
Rate int64
}
// DeviceWeights contains weights for devices.
type DeviceWeights []DeviceWeight
// DeviceRates contains throttling rates for devices.
type DeviceRates []DeviceRate
// NewBlockIOParameters creates new BlockIOParameters instance.
func NewBlockIOParameters() BlockIOParameters {
return BlockIOParameters{
Weight: -1,
}
}
// DeviceParameters interface provides functions common to DeviceWeights and DeviceRates.
type DeviceParameters interface {
Append(maj, min, val int64)
Update(maj, min, val int64)
}
// Append appends (major, minor, value) to DeviceWeights slice.
func (w *DeviceWeights) Append(maj, min, val int64) {
*w = append(*w, DeviceWeight{Major: maj, Minor: min, Weight: val})
}
// Append appends (major, minor, value) to DeviceRates slice.
func (r *DeviceRates) Append(maj, min, val int64) {
*r = append(*r, DeviceRate{Major: maj, Minor: min, Rate: val})
}
// Update updates device weight in DeviceWeights slice, or appends it if not found.
func (w *DeviceWeights) Update(maj, min, val int64) {
for index, devWeight := range *w {
if devWeight.Major == maj && devWeight.Minor == min {
(*w)[index].Weight = val
return
}
}
w.Append(maj, min, val)
}
// Update updates device rate in DeviceRates slice, or appends it if not found.
func (r *DeviceRates) Update(maj, min, val int64) {
for index, devRate := range *r {
if devRate.Major == maj && devRate.Minor == min {
(*r)[index].Rate = val
return
}
}
r.Append(maj, min, val)
}

View File

@ -20,8 +20,6 @@ import (
"fmt" "fmt"
oci "github.com/opencontainers/runtime-spec/specs-go" oci "github.com/opencontainers/runtime-spec/specs-go"
"github.com/intel/goresctrl/pkg/cgroups"
) )
// OciLinuxBlockIO returns OCI LinuxBlockIO structure corresponding to the class. // OciLinuxBlockIO returns OCI LinuxBlockIO structure corresponding to the class.
@ -43,7 +41,7 @@ func OciLinuxBlockIO(class string) (*oci.LinuxBlockIO, error) {
return &ociBlockio, nil return &ociBlockio, nil
} }
func ociLinuxWeightDevices(dws cgroups.DeviceWeights) []oci.LinuxWeightDevice { func ociLinuxWeightDevices(dws DeviceWeights) []oci.LinuxWeightDevice {
if len(dws) == 0 { if len(dws) == 0 {
return nil return nil
} }
@ -57,7 +55,7 @@ func ociLinuxWeightDevices(dws cgroups.DeviceWeights) []oci.LinuxWeightDevice {
return olwds return olwds
} }
func ociLinuxThrottleDevices(drs cgroups.DeviceRates) []oci.LinuxThrottleDevice { func ociLinuxThrottleDevices(drs DeviceRates) []oci.LinuxThrottleDevice {
if len(drs) == 0 { if len(drs) == 0 {
return nil return nil
} }

View File

@ -1,312 +0,0 @@
// 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 (
"errors"
"fmt"
"strconv"
"strings"
)
// cgroups blkio parameter filenames.
var blkioWeightFiles = []string{"blkio.bfq.weight", "blkio.weight"}
var blkioWeightDeviceFiles = []string{"blkio.bfq.weight_device", "blkio.weight_device"}
var blkioThrottleReadBpsFiles = []string{"blkio.throttle.read_bps_device"}
var blkioThrottleWriteBpsFiles = []string{"blkio.throttle.write_bps_device"}
var blkioThrottleReadIOPSFiles = []string{"blkio.throttle.read_iops_device"}
var blkioThrottleWriteIOPSFiles = []string{"blkio.throttle.write_iops_device"}
// BlockIOParameters contains cgroups blockio controller parameters.
//
// Effects of Weight and Rate values in SetBlkioParameters():
// Value | Effect
// -------+-------------------------------------------------------------------
//
// -1 | Do not write to cgroups, value is missing.
// 0 | Write to cgroups, will clear the setting as specified in cgroups blkio interface.
// other | Write to cgroups, sets the value.
type BlockIOParameters struct {
Weight int64
WeightDevice DeviceWeights
ThrottleReadBpsDevice DeviceRates
ThrottleWriteBpsDevice DeviceRates
ThrottleReadIOPSDevice DeviceRates
ThrottleWriteIOPSDevice DeviceRates
}
// DeviceWeight contains values for
// - blkio.[io-scheduler].weight
type DeviceWeight struct {
Major int64
Minor int64
Weight int64
}
// DeviceRate contains values for
// - blkio.throttle.read_bps_device
// - blkio.throttle.write_bps_device
// - blkio.throttle.read_iops_device
// - blkio.throttle.write_iops_device
type DeviceRate struct {
Major int64
Minor int64
Rate int64
}
// DeviceWeights contains weights for devices.
type DeviceWeights []DeviceWeight
// DeviceRates contains throttling rates for devices.
type DeviceRates []DeviceRate
// DeviceParameters interface provides functions common to DeviceWeights and DeviceRates.
type DeviceParameters interface {
Append(maj, min, val int64)
Update(maj, min, val int64)
}
// Append appends (major, minor, value) to DeviceWeights slice.
func (w *DeviceWeights) Append(maj, min, val int64) {
*w = append(*w, DeviceWeight{Major: maj, Minor: min, Weight: val})
}
// Append appends (major, minor, value) to DeviceRates slice.
func (r *DeviceRates) Append(maj, min, val int64) {
*r = append(*r, DeviceRate{Major: maj, Minor: min, Rate: val})
}
// Update updates device weight in DeviceWeights slice, or appends it if not found.
func (w *DeviceWeights) Update(maj, min, val int64) {
for index, devWeight := range *w {
if devWeight.Major == maj && devWeight.Minor == min {
(*w)[index].Weight = val
return
}
}
w.Append(maj, min, val)
}
// Update updates device rate in DeviceRates slice, or appends it if not found.
func (r *DeviceRates) Update(maj, min, val int64) {
for index, devRate := range *r {
if devRate.Major == maj && devRate.Minor == min {
(*r)[index].Rate = val
return
}
}
r.Append(maj, min, val)
}
// NewBlockIOParameters creates new BlockIOParameters instance.
func NewBlockIOParameters() BlockIOParameters {
return BlockIOParameters{
Weight: -1,
}
}
// NewDeviceWeight creates new DeviceWeight instance.
func NewDeviceWeight() DeviceWeight {
return DeviceWeight{
Major: -1,
Minor: -1,
Weight: -1,
}
}
// NewDeviceRate creates new DeviceRate instance.
func NewDeviceRate() DeviceRate {
return DeviceRate{
Major: -1,
Minor: -1,
Rate: -1,
}
}
type devMajMin struct {
Major int64
Minor int64
}
// ResetBlkioParameters adds new, changes existing and removes missing blockIO parameters in cgroupsDir.
func ResetBlkioParameters(groupDir string, blockIO BlockIOParameters) error {
errs := []error{}
oldBlockIO, _ := GetBlkioParameters(groupDir)
newBlockIO := NewBlockIOParameters()
newBlockIO.Weight = blockIO.Weight
newBlockIO.WeightDevice = resetDevWeights(oldBlockIO.WeightDevice, blockIO.WeightDevice)
newBlockIO.ThrottleReadBpsDevice = resetDevRates(oldBlockIO.ThrottleReadBpsDevice, blockIO.ThrottleReadBpsDevice)
newBlockIO.ThrottleWriteBpsDevice = resetDevRates(oldBlockIO.ThrottleWriteBpsDevice, blockIO.ThrottleWriteBpsDevice)
newBlockIO.ThrottleReadIOPSDevice = resetDevRates(oldBlockIO.ThrottleReadIOPSDevice, blockIO.ThrottleReadIOPSDevice)
newBlockIO.ThrottleWriteIOPSDevice = resetDevRates(oldBlockIO.ThrottleWriteIOPSDevice, blockIO.ThrottleWriteIOPSDevice)
errs = append(errs, SetBlkioParameters(groupDir, newBlockIO))
return errors.Join(errs...)
}
// resetDevWeights adds wanted weight parameters to new and resets unwanted weights.
func resetDevWeights(old, wanted []DeviceWeight) []DeviceWeight {
new := []DeviceWeight{}
seenDev := map[devMajMin]bool{}
for _, wdp := range wanted {
seenDev[devMajMin{wdp.Major, wdp.Minor}] = true
new = append(new, wdp)
}
for _, wdp := range old {
if !seenDev[devMajMin{wdp.Major, wdp.Minor}] {
new = append(new, DeviceWeight{wdp.Major, wdp.Minor, 0})
}
}
return new
}
// resetDevRates adds wanted rate parameters to new and resets unwanted rates.
func resetDevRates(old, wanted []DeviceRate) []DeviceRate {
new := []DeviceRate{}
seenDev := map[devMajMin]bool{}
for _, rdp := range wanted {
new = append(new, rdp)
seenDev[devMajMin{rdp.Major, rdp.Minor}] = true
}
for _, rdp := range old {
if !seenDev[devMajMin{rdp.Major, rdp.Minor}] {
new = append(new, DeviceRate{rdp.Major, rdp.Minor, 0})
}
}
return new
}
// GetBlkioParameters returns BlockIO parameters from files in cgroups blkio controller directory.
func GetBlkioParameters(group string) (BlockIOParameters, error) {
errs := []error{}
blockIO := NewBlockIOParameters()
errs = append(errs, readWeight(group, blkioWeightFiles, &blockIO.Weight))
errs = append(errs, readDeviceParameters(group, blkioWeightDeviceFiles, &blockIO.WeightDevice))
errs = append(errs, readDeviceParameters(group, blkioThrottleReadBpsFiles, &blockIO.ThrottleReadBpsDevice))
errs = append(errs, readDeviceParameters(group, blkioThrottleWriteBpsFiles, &blockIO.ThrottleWriteBpsDevice))
errs = append(errs, readDeviceParameters(group, blkioThrottleReadIOPSFiles, &blockIO.ThrottleReadIOPSDevice))
errs = append(errs, readDeviceParameters(group, blkioThrottleWriteIOPSFiles, &blockIO.ThrottleWriteIOPSDevice))
return blockIO, errors.Join(errs...)
}
// readWeight parses int64 from a cgroups entry.
func readWeight(groupDir string, filenames []string, rv *int64) error {
contents, err := readFirstFile(groupDir, filenames)
if err != nil {
return err
}
parsed, err := strconv.ParseInt(strings.TrimSuffix(contents, "\n"), 10, 64)
if err != nil {
return fmt.Errorf("parsing weight from %#v found in %v failed: %w", contents, filenames, err)
}
*rv = parsed
return nil
}
// readDeviceParameters parses device lines used for weights and throttling rates.
func readDeviceParameters(groupDir string, filenames []string, params DeviceParameters) error {
errs := []error{}
contents, err := readFirstFile(groupDir, filenames)
if err != nil {
return err
}
for _, line := range strings.Split(contents, "\n") {
// Device weight files may have "default NNN" line at the beginning. Skip it.
if line == "" || strings.HasPrefix(line, "default ") {
continue
}
// Expect syntax MAJOR:MINOR VALUE
devVal := strings.Split(line, " ")
if len(devVal) != 2 {
errs = append(errs, fmt.Errorf("invalid line %q, single space expected", line))
continue
}
majMin := strings.Split(devVal[0], ":")
if len(majMin) != 2 {
errs = append(errs, fmt.Errorf("invalid line %q, single colon expected before space", line))
continue
}
major, majErr := strconv.ParseInt(majMin[0], 10, 64)
minor, minErr := strconv.ParseInt(majMin[1], 10, 64)
value, valErr := strconv.ParseInt(devVal[1], 10, 64)
if majErr != nil || minErr != nil || valErr != nil {
errs = append(errs, fmt.Errorf("invalid number when parsing \"major:minor value\" from \"%s:%s %s\"", majMin[0], majMin[1], devVal[1]))
continue
}
params.Append(major, minor, value)
}
return errors.Join(errs...)
}
// readFirstFile returns contents of the first successfully read entry.
func readFirstFile(groupDir string, filenames []string) (string, error) {
errs := []error{}
// If reading all the files fails, return list of read errors.
for _, filename := range filenames {
content, err := Blkio.Group(groupDir).Read(filename)
if err == nil {
return content, nil
}
errs = append(errs, err)
}
err := errors.Join(errs...)
if err != nil {
return "", fmt.Errorf("could not read any of files %q: %w", filenames, err)
}
return "", nil
}
// SetBlkioParameters writes BlockIO parameters to files in cgroups blkio contoller directory.
func SetBlkioParameters(group string, blockIO BlockIOParameters) error {
errs := []error{}
if blockIO.Weight >= 0 {
errs = append(errs, writeFirstFile(group, blkioWeightFiles, "%d", blockIO.Weight))
}
for _, wd := range blockIO.WeightDevice {
errs = append(errs, writeFirstFile(group, blkioWeightDeviceFiles, "%d:%d %d", wd.Major, wd.Minor, wd.Weight))
}
for _, rd := range blockIO.ThrottleReadBpsDevice {
errs = append(errs, writeFirstFile(group, blkioThrottleReadBpsFiles, "%d:%d %d", rd.Major, rd.Minor, rd.Rate))
}
for _, rd := range blockIO.ThrottleWriteBpsDevice {
errs = append(errs, writeFirstFile(group, blkioThrottleWriteBpsFiles, "%d:%d %d", rd.Major, rd.Minor, rd.Rate))
}
for _, rd := range blockIO.ThrottleReadIOPSDevice {
errs = append(errs, writeFirstFile(group, blkioThrottleReadIOPSFiles, "%d:%d %d", rd.Major, rd.Minor, rd.Rate))
}
for _, rd := range blockIO.ThrottleWriteIOPSDevice {
errs = append(errs, writeFirstFile(group, blkioThrottleWriteIOPSFiles, "%d:%d %d", rd.Major, rd.Minor, rd.Rate))
}
return errors.Join(errs...)
}
// writeFirstFile writes content to the first existing file in the list under groupDir.
func writeFirstFile(groupDir string, filenames []string, format string, args ...interface{}) error {
errs := []error{}
// Returns list of errors from writes, list of single error due to all filenames missing or nil on success.
for _, filename := range filenames {
if err := Blkio.Group(groupDir).Write(filename, format, args...); err != nil {
errs = append(errs, err)
continue
}
return nil
}
err := errors.Join(errs...)
if err != nil {
data := fmt.Sprintf(format, args...)
return fmt.Errorf("writing all files %v failed, errors: %w, content %q", filenames, err, data)
}
return nil
}

View File

@ -1,237 +0,0 @@
// 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 cgroupPath(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(cgroupPath(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), cgroupPath()+"/")
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), cgroupPath()+"/")
return fmt.Errorf("cgroup "+name+": "+format, args...)
}

View File

@ -1,65 +0,0 @@
package cgroups
import (
"fmt"
"os"
"path/filepath"
"sync"
)
// CgroupID implements mapping kernel cgroup IDs to cgroupfs paths with transparent caching.
type CgroupID struct {
root string
cache map[uint64]string
sync.Mutex
}
// NewCgroupID creates a new CgroupID map/cache.
func NewCgroupID(root string) *CgroupID {
return &CgroupID{
root: root,
cache: make(map[uint64]string),
}
}
// Find finds the path for the given cgroup id.
func (cgid *CgroupID) Find(id uint64) (string, error) {
found := false
var p string
cgid.Lock()
defer cgid.Unlock()
if path, ok := cgid.cache[id]; ok {
return path, nil
}
err := fsi.Walk(cgid.root, func(path string, info os.FileInfo, err error) error {
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
if found {
return filepath.SkipDir
}
if info.IsDir() && id == getID(path) {
found = true
p = path
return filepath.SkipDir
}
return nil
})
if err != nil {
return "", err
} else if !found {
return "", fmt.Errorf("cgroupid %v not found", id)
} else {
cgid.cache[id] = p
return p, nil
}
}

View File

@ -1,18 +0,0 @@
//go:build linux
// +build linux
package cgroups
import (
"encoding/binary"
"golang.org/x/sys/unix"
)
func getID(path string) uint64 {
h, _, err := unix.NameToHandleAt(unix.AT_FDCWD, path, 0)
if err != nil {
return 0
}
return binary.LittleEndian.Uint64(h.Bytes())
}

View File

@ -1,8 +0,0 @@
//go:build !linux
// +build !linux
package cgroups
func getID(path string) uint64 {
return 0
}

View File

@ -1,53 +0,0 @@
// Copyright 2020 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 (
goresctrlpath "github.com/intel/goresctrl/pkg/path"
)
// nolint
const (
// Tasks is a cgroup's "tasks" entry.
Tasks = "tasks"
// Procs is cgroup's "cgroup.procs" entry.
Procs = "cgroup.procs"
// CpuShares is the cpu controller's "cpu.shares" entry.
CpuShares = "cpu.shares"
// CpuPeriod is the cpu controller's "cpu.cfs_period_us" entry.
CpuPeriod = "cpu.cfs_period_us"
// CpuQuota is the cpu controller's "cpu.cfs_quota_us" entry.
CpuQuota = "cpu.cfs_quota_us"
// CpusetCpus is the cpuset controller's cpuset.cpus entry.
CpusetCpus = "cpuset.cpus"
// CpusetMems is the cpuset controller's cpuset.mems entry.
CpusetMems = "cpuset.mems"
)
const cgroupBasePath = "sys/fs/cgroup"
// GetMountDir returns the common mount point for cgroup v1 controllers.
func GetMountDir() string {
return cgroupPath()
}
// GetV2Dir returns the cgroup v2 unified mount directory.
func GetV2Dir() string {
return cgroupPath("unified")
}
func cgroupPath(elems ...string) string {
return goresctrlpath.Path(append([]string{cgroupBasePath}, elems...)...)
}

View File

@ -1,39 +0,0 @@
// 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 defines filesystem interface (fsi) through which
// cgroups package accesses files.
package cgroups
import (
"os"
"path/filepath"
)
type fsiIface interface {
Open(name string) (fileIface, error)
OpenFile(name string, flag int, perm os.FileMode) (fileIface, error)
Walk(string, filepath.WalkFunc) error
Lstat(path string) (os.FileInfo, error)
}
type fileIface interface {
Close() error
Read(p []byte) (n int, err error)
Write(b []byte) (n int, err error)
}
// Set the default filesystem interface
var fsi fsiIface = newFsiOS()

View File

@ -1,230 +0,0 @@
// 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...)
}

View File

@ -1,63 +0,0 @@
// 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 provides the native implementation of the filesystem
// interface (fsi).
package cgroups
import (
"os"
"path/filepath"
)
type fsOs struct{}
type osFile struct {
file *os.File
}
func newFsiOS() fsiIface {
return fsOs{}
}
func (fsOs) OpenFile(name string, flag int, perm os.FileMode) (fileIface, error) {
f, err := os.OpenFile(name, flag, perm)
return osFile{f}, err
}
func (fsOs) Open(name string) (fileIface, error) {
f, err := os.Open(name)
return osFile{f}, err
}
func (fsOs) Lstat(name string) (os.FileInfo, error) {
return os.Lstat(name)
}
func (fsOs) Walk(root string, walkFn filepath.WalkFunc) error {
return filepath.Walk(root, walkFn)
}
func (osf osFile) Write(b []byte) (n int, err error) {
return osf.file.Write(b)
}
func (osf osFile) Read(b []byte) (n int, err error) {
return osf.file.Read(b)
}
func (osf osFile) Close() error {
return osf.file.Close()
}

View File

@ -234,7 +234,7 @@ func SetConfig(c *Config, force bool) error {
// reconfigures the resctrl filesystem. // reconfigures the resctrl filesystem.
func SetConfigFromData(data []byte, force bool) error { func SetConfigFromData(data []byte, force bool) error {
cfg := &Config{} cfg := &Config{}
if err := yaml.Unmarshal(data, &cfg); err != nil { if err := yaml.UnmarshalStrict(data, cfg); err != nil {
return fmt.Errorf("failed to parse configuration data: %v", err) return fmt.Errorf("failed to parse configuration data: %v", err)
} }

View File

@ -169,7 +169,7 @@ func (s *IDSet) UnmarshalJSON(data []byte) error {
} }
for _, idstr := range strings.Split(str, ",") { for _, idstr := range strings.Split(str, ",") {
id, err := strconv.ParseUint(idstr, 10, 0) id, err := strconv.ParseInt(idstr, 10, 0)
if err != nil { if err != nil {
return fmt.Errorf("invalid IDSet entry '%s': %v", idstr, err) return fmt.Errorf("invalid IDSet entry '%s': %v", idstr, err)
} }

3
vendor/modules.txt vendored
View File

@ -256,10 +256,9 @@ github.com/grpc-ecosystem/go-grpc-prometheus
github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule
github.com/grpc-ecosystem/grpc-gateway/v2/runtime github.com/grpc-ecosystem/grpc-gateway/v2/runtime
github.com/grpc-ecosystem/grpc-gateway/v2/utilities github.com/grpc-ecosystem/grpc-gateway/v2/utilities
# github.com/intel/goresctrl v0.5.0 # github.com/intel/goresctrl v0.6.0
## explicit; go 1.20 ## explicit; go 1.20
github.com/intel/goresctrl/pkg/blockio github.com/intel/goresctrl/pkg/blockio
github.com/intel/goresctrl/pkg/cgroups
github.com/intel/goresctrl/pkg/kubernetes github.com/intel/goresctrl/pkg/kubernetes
github.com/intel/goresctrl/pkg/log github.com/intel/goresctrl/pkg/log
github.com/intel/goresctrl/pkg/path github.com/intel/goresctrl/pkg/path