From a6466792b4a78638871a8ed4af65f25555b24520 Mon Sep 17 00:00:00 2001 From: zhongjiawei Date: Wed, 26 Jul 2023 16:34:51 +0800 Subject: [PATCH] runc:make runc spec compatible 1.0.0.rc3 --- spec.go | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 1 deletion(-) diff --git a/spec.go b/spec.go index 806d2f1..7170648 100644 --- a/spec.go +++ b/spec.go @@ -112,8 +112,95 @@ created by an unprivileged user. }, } +type compatSpec struct { + specs.Spec + Linux *linux `json:"linux,omitempty" platform:"linux"` +} + +type linux struct { + specs.Linux + Resources *linuxResources `json:"resources,omitempty"` +} + +type linuxResources struct { + specs.LinuxResources + // DisableOOMKiller disables the OOM killer for out of memory conditions + DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"` + // Specify an oom_score_adj for the container. + OOMScoreAdj *int `json:"oomScoreAdj,omitempty"` + // BlockIO restriction configuration + BlockIO *LinuxBlockIO `json:"blockIO,omitempty"` +} + +// LinuxBlockIO for Linux cgroup 'blkio' resource management +type LinuxBlockIO struct { + // Specifies per cgroup weight, range is from 10 to 1000 + Weight *uint16 `json:"blkioWeight,omitempty"` + // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only + LeafWeight *uint16 `json:"blkioLeafWeight,omitempty"` + // Weight per cgroup per device, can override BlkioWeight + WeightDevice []LinuxWeightDevice `json:"blkioWeightDevice,omitempty"` + // IO read rate limit per cgroup per device, bytes per second + ThrottleReadBpsDevice []LinuxThrottleDevice `json:"blkioThrottleReadBpsDevice,omitempty"` + // IO write rate limit per cgroup per device, bytes per second + ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"blkioThrottleWriteBpsDevice,omitempty"` + // IO read rate limit per cgroup per device, IO per second + ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"blkioThrottleReadIOPSDevice,omitempty"` + // IO write rate limit per cgroup per device, IO per second + ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"blkioThrottleWriteIOPSDevice,omitempty"` +} + +// linuxBlockIODevice holds major:minor format supported in blkio cgroup +type linuxBlockIODevice struct { + // Major is the device's major number. + Major int64 `json:"major"` + // Minor is the device's minor number. + Minor int64 `json:"minor"` +} + +// LinuxWeightDevice struct holds a `major:minor weight` pair for blkioWeightDevice +type LinuxWeightDevice struct { + linuxBlockIODevice + // Weight is the bandwidth rate for the device, range is from 10 to 1000 + Weight *uint16 `json:"weight,omitempty"` + // LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only + LeafWeight *uint16 `json:"leafWeight,omitempty"` +} + +// LinuxThrottleDevice struct holds a `major:minor rate_per_second` pair +type LinuxThrottleDevice struct { + linuxBlockIODevice + // Rate is the IO rate limit per cgroup per device + Rate uint64 `json:"rate"` +} + +func versionRc6Plus(ver string) bool { + if len(ver) < 5 { // version should be a.b.c[-rcn][x] + return false + } + + // docker-18.09 1.0.1 + if ver[:5] < "1.0.1" { + return true + } + + // < 1.0.0-rc6: include 1.0.0-rc5xxx + return false +} + // loadSpec loads the specification from the provided path. func loadSpec(cPath string) (spec *specs.Spec, err error) { + spec, err = loadOriginSpec(cPath) + if err != nil || versionRc6Plus(spec.Version) { + return loadCompactSpec(cPath) + } + + return spec, validateProcessSpec(spec.Process) + +} + +// loadSpec loads the specification from the provided path. +func loadOriginSpec(cPath string) (spec *specs.Spec, err error) { cf, err := os.Open(cPath) if err != nil { if os.IsNotExist(err) { @@ -126,7 +213,99 @@ func loadSpec(cPath string) (spec *specs.Spec, err error) { if err = json.NewDecoder(cf).Decode(&spec); err != nil { return nil, err } - return spec, validateProcessSpec(spec.Process) + return spec, nil +} + +func loadCompactSpec(cPath string) (*specs.Spec, error) { + var compatSpec compatSpec + cf, err := os.Open(cPath) + if err != nil { + if os.IsNotExist(err) { + return nil, fmt.Errorf("JSON specification file %s not found", cPath) + } + return nil, err + } + defer cf.Close() + + if err = json.NewDecoder(cf).Decode(&compatSpec); err != nil { + return nil, fmt.Errorf("config.json %q error :%v", cPath, err) + } + + var spec *specs.Spec + if spec, err = updateCompactSpec(&compatSpec); err != nil { + return nil, err + } + + return spec, nil +} + +func updateCompactSpec(compatSpec *compatSpec) (*specs.Spec, error) { + compatjson, _ := json.Marshal(compatSpec) + var spec specs.Spec + err := json.Unmarshal(compatjson, &spec) + if err != nil { + return nil, fmt.Errorf("update config failed %v", err) + } + + if compatSpec != nil && compatSpec.Linux != nil && + compatSpec.Linux.Resources != nil && + compatSpec.Linux.Resources.DisableOOMKiller != nil { + if spec.Linux.Resources.Memory == nil { + memory := &specs.LinuxMemory{ + DisableOOMKiller: compatSpec.Linux.Resources.DisableOOMKiller, + } + spec.Linux.Resources.Memory = memory + } else { + spec.Linux.Resources.Memory.DisableOOMKiller = compatSpec.Linux.Resources.DisableOOMKiller + } + } + + if compatSpec != nil && compatSpec.Linux != nil && + compatSpec.Linux.Resources != nil && + compatSpec.Linux.Resources.OOMScoreAdj != nil { + if spec.Process == nil { + process := &specs.Process{ + OOMScoreAdj: compatSpec.Linux.Resources.OOMScoreAdj, + } + spec.Process = process + } else { + spec.Process.OOMScoreAdj = compatSpec.Linux.Resources.OOMScoreAdj + } + } + + if compatSpec.Linux.Resources.BlockIO != nil { + spec.Linux.Resources.BlockIO.Weight = compatSpec.Linux.Resources.BlockIO.Weight + spec.Linux.Resources.BlockIO.LeafWeight = compatSpec.Linux.Resources.BlockIO.LeafWeight + if compatSpec.Linux.Resources.BlockIO.WeightDevice != nil { + for _, wd := range compatSpec.Linux.Resources.BlockIO.WeightDevice { + wdSpec := specs.LinuxWeightDevice{ + Weight: wd.Weight, + LeafWeight: wd.LeafWeight, + } + wdSpec.Major = wd.Major + wdSpec.Minor = wd.Minor + spec.Linux.Resources.BlockIO.WeightDevice = append(spec.Linux.Resources.BlockIO.WeightDevice, wdSpec) + } + } + procLinuxThrottleDevice := func(src []LinuxThrottleDevice, dest *[]specs.LinuxThrottleDevice) { + if src != nil { + for _, ltd := range src { + ltdSpec := specs.LinuxThrottleDevice{ + Rate: ltd.Rate, + } + ltdSpec.Major = ltd.Major + ltdSpec.Minor = ltd.Minor + *dest = append(*dest, ltdSpec) + } + } + } + procLinuxThrottleDevice(compatSpec.Linux.Resources.BlockIO.ThrottleReadBpsDevice, &spec.Linux.Resources.BlockIO.ThrottleReadBpsDevice) + procLinuxThrottleDevice(compatSpec.Linux.Resources.BlockIO.ThrottleWriteBpsDevice, &spec.Linux.Resources.BlockIO.ThrottleWriteBpsDevice) + procLinuxThrottleDevice(compatSpec.Linux.Resources.BlockIO.ThrottleReadIOPSDevice, &spec.Linux.Resources.BlockIO.ThrottleReadIOPSDevice) + procLinuxThrottleDevice(compatSpec.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice, &spec.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice) + } + + return &spec, nil } func createLibContainerRlimit(rlimit specs.POSIXRlimit) (configs.Rlimit, error) { -- 2.33.0