mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-01 18:52:25 -05:00
[chore]: Bump github.com/KimMachineGun/automemlimit from 0.2.4 to 0.2.5 (#1666)
Bumps [github.com/KimMachineGun/automemlimit](https://github.com/KimMachineGun/automemlimit) from 0.2.4 to 0.2.5. - [Release notes](https://github.com/KimMachineGun/automemlimit/releases) - [Commits](https://github.com/KimMachineGun/automemlimit/compare/v0.2.4...v0.2.5) --- updated-dependencies: - dependency-name: github.com/KimMachineGun/automemlimit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
parent
3f9b2336c0
commit
57dc742c76
200 changed files with 16392 additions and 38190 deletions
46
vendor/github.com/containerd/cgroups/Protobuild.toml
generated
vendored
46
vendor/github.com/containerd/cgroups/Protobuild.toml
generated
vendored
|
|
@ -1,46 +0,0 @@
|
|||
version = "unstable"
|
||||
generator = "gogoctrd"
|
||||
plugins = ["grpc"]
|
||||
|
||||
# Control protoc include paths. Below are usually some good defaults, but feel
|
||||
# free to try it without them if it works for your project.
|
||||
[includes]
|
||||
# Include paths that will be added before all others. Typically, you want to
|
||||
# treat the root of the project as an include, but this may not be necessary.
|
||||
# before = ["."]
|
||||
|
||||
# Paths that should be treated as include roots in relation to the vendor
|
||||
# directory. These will be calculated with the vendor directory nearest the
|
||||
# target package.
|
||||
# vendored = ["github.com/gogo/protobuf"]
|
||||
packages = ["github.com/gogo/protobuf"]
|
||||
|
||||
# Paths that will be added untouched to the end of the includes. We use
|
||||
# `/usr/local/include` to pickup the common install location of protobuf.
|
||||
# This is the default.
|
||||
after = ["/usr/local/include", "/usr/include"]
|
||||
|
||||
# This section maps protobuf imports to Go packages. These will become
|
||||
# `-M` directives in the call to the go protobuf generator.
|
||||
[packages]
|
||||
"gogoproto/gogo.proto" = "github.com/gogo/protobuf/gogoproto"
|
||||
"google/protobuf/any.proto" = "github.com/gogo/protobuf/types"
|
||||
"google/protobuf/descriptor.proto" = "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
|
||||
"google/protobuf/field_mask.proto" = "github.com/gogo/protobuf/types"
|
||||
"google/protobuf/timestamp.proto" = "github.com/gogo/protobuf/types"
|
||||
|
||||
# Aggregrate the API descriptors to lock down API changes.
|
||||
[[descriptors]]
|
||||
prefix = "github.com/containerd/cgroups/stats/v1"
|
||||
target = "stats/v1/metrics.pb.txt"
|
||||
ignore_files = [
|
||||
"google/protobuf/descriptor.proto",
|
||||
"gogoproto/gogo.proto"
|
||||
]
|
||||
[[descriptors]]
|
||||
prefix = "github.com/containerd/cgroups/v2/stats"
|
||||
target = "v2/stats/metrics.pb.txt"
|
||||
ignore_files = [
|
||||
"google/protobuf/descriptor.proto",
|
||||
"gogoproto/gogo.proto"
|
||||
]
|
||||
46
vendor/github.com/containerd/cgroups/Vagrantfile
generated
vendored
46
vendor/github.com/containerd/cgroups/Vagrantfile
generated
vendored
|
|
@ -1,46 +0,0 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
# Fedora box is used for testing cgroup v2 support
|
||||
config.vm.box = "fedora/35-cloud-base"
|
||||
config.vm.provider :virtualbox do |v|
|
||||
v.memory = 4096
|
||||
v.cpus = 2
|
||||
end
|
||||
config.vm.provider :libvirt do |v|
|
||||
v.memory = 4096
|
||||
v.cpus = 2
|
||||
end
|
||||
config.vm.provision "shell", inline: <<-SHELL
|
||||
set -eux -o pipefail
|
||||
# configuration
|
||||
GO_VERSION="1.17.7"
|
||||
|
||||
# install gcc and Golang
|
||||
dnf -y install gcc
|
||||
curl -fsSL "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" | tar Cxz /usr/local
|
||||
|
||||
# setup env vars
|
||||
cat >> /etc/profile.d/sh.local <<EOF
|
||||
PATH=/usr/local/go/bin:$PATH
|
||||
GO111MODULE=on
|
||||
export PATH GO111MODULE
|
||||
EOF
|
||||
source /etc/profile.d/sh.local
|
||||
|
||||
# enter /root/go/src/github.com/containerd/cgroups
|
||||
mkdir -p /root/go/src/github.com/containerd
|
||||
ln -s /vagrant /root/go/src/github.com/containerd/cgroups
|
||||
cd /root/go/src/github.com/containerd/cgroups
|
||||
|
||||
# create /test.sh
|
||||
cat > /test.sh <<EOF
|
||||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
cd /root/go/src/github.com/containerd/cgroups
|
||||
go test -v ./...
|
||||
EOF
|
||||
chmod +x /test.sh
|
||||
SHELL
|
||||
end
|
||||
6125
vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go
generated
vendored
6125
vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go
generated
vendored
File diff suppressed because it is too large
Load diff
3992
vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go
generated
vendored
3992
vendor/github.com/containerd/cgroups/v2/stats/metrics.pb.go
generated
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -22,3 +22,5 @@ cgutil:
|
|||
|
||||
proto:
|
||||
protobuild --quiet ${PACKAGES}
|
||||
# Keep them Go-idiomatic and backward-compatible with the gogo/protobuf era.
|
||||
go-fix-acronym -w -a '(Cpu|Tcp|Rss)' $(shell find cgroup1/stats/ cgroup2/stats/ -name '*.pb.go')
|
||||
31
vendor/github.com/containerd/cgroups/v3/Protobuild.toml
generated
vendored
Normal file
31
vendor/github.com/containerd/cgroups/v3/Protobuild.toml
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
version = "2"
|
||||
generators = ["go"]
|
||||
|
||||
# Control protoc include paths. Below are usually some good defaults, but feel
|
||||
# free to try it without them if it works for your project.
|
||||
[includes]
|
||||
# Include paths that will be added before all others. Typically, you want to
|
||||
# treat the root of the project as an include, but this may not be necessary.
|
||||
# before = ["."]
|
||||
|
||||
# Paths that will be added untouched to the end of the includes. We use
|
||||
# `/usr/local/include` to pickup the common install location of protobuf.
|
||||
# This is the default.
|
||||
after = ["/usr/local/include", "/usr/include"]
|
||||
|
||||
# Aggregrate the API descriptors to lock down API changes.
|
||||
[[descriptors]]
|
||||
prefix = "github.com/containerd/cgroups/cgroup1/stats"
|
||||
target = "cgroup1/stats/metrics.pb.txt"
|
||||
ignore_files = [
|
||||
"google/protobuf/descriptor.proto",
|
||||
]
|
||||
[[descriptors]]
|
||||
prefix = "github.com/containerd/cgroups/cgroup2/stats"
|
||||
target = "cgroup2/stats/metrics.pb.txt"
|
||||
ignore_files = [
|
||||
"google/protobuf/descriptor.proto",
|
||||
]
|
||||
|
||||
[parameters.go]
|
||||
paths = "source_relative"
|
||||
|
|
@ -9,7 +9,7 @@ Go package for creating, managing, inspecting, and destroying cgroups.
|
|||
The resources format for settings on the cgroup uses the OCI runtime-spec found
|
||||
[here](https://github.com/opencontainers/runtime-spec).
|
||||
|
||||
## Examples
|
||||
## Examples (v1)
|
||||
|
||||
### Create a new cgroup
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ uses the v1 implementation of cgroups.
|
|||
|
||||
```go
|
||||
shares := uint64(100)
|
||||
control, err := cgroups.New(cgroups.V1, cgroups.StaticPath("/test"), &specs.LinuxResources{
|
||||
control, err := cgroup1.New(cgroup1.StaticPath("/test"), &specs.LinuxResources{
|
||||
CPU: &specs.LinuxCPU{
|
||||
Shares: &shares,
|
||||
},
|
||||
|
|
@ -37,7 +37,7 @@ defer control.Delete()
|
|||
|
||||
|
||||
```go
|
||||
control, err := cgroups.New(cgroups.Systemd, cgroups.Slice("system.slice", "runc-test"), &specs.LinuxResources{
|
||||
control, err := cgroup1.New(cgroup1.Systemd, cgroup1.Slice("system.slice", "runc-test"), &specs.LinuxResources{
|
||||
CPU: &specs.CPU{
|
||||
Shares: &shares,
|
||||
},
|
||||
|
|
@ -48,17 +48,17 @@ control, err := cgroups.New(cgroups.Systemd, cgroups.Slice("system.slice", "runc
|
|||
### Load an existing cgroup
|
||||
|
||||
```go
|
||||
control, err = cgroups.Load(cgroups.V1, cgroups.StaticPath("/test"))
|
||||
control, err = cgroup1.Load(cgroup1.Default, cgroups.StaticPath("/test"))
|
||||
```
|
||||
|
||||
### Add a process to the cgroup
|
||||
|
||||
```go
|
||||
if err := control.Add(cgroups.Process{Pid:1234}); err != nil {
|
||||
if err := control.Add(cgroup1.Process{Pid:1234}); err != nil {
|
||||
}
|
||||
```
|
||||
|
||||
### Update the cgroup
|
||||
### Update the cgroup
|
||||
|
||||
To update the resources applied in the cgroup
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ if err := control.Thaw(); err != nil {
|
|||
### List all processes in the cgroup or recursively
|
||||
|
||||
```go
|
||||
processes, err := control.Processes(cgroups.Devices, recursive)
|
||||
processes, err := control.Processes(cgroup1.Devices, recursive)
|
||||
```
|
||||
|
||||
### Get Stats on the cgroup
|
||||
|
|
@ -95,7 +95,7 @@ stats, err := control.Stat()
|
|||
|
||||
By adding `cgroups.IgnoreNotExist` all non-existent files will be ignored, e.g. swap memory stats without swap enabled
|
||||
```go
|
||||
stats, err := control.Stat(cgroups.IgnoreNotExist)
|
||||
stats, err := control.Stat(cgroup1.IgnoreNotExist)
|
||||
```
|
||||
|
||||
### Move process across cgroups
|
||||
|
|
@ -117,22 +117,90 @@ subCgroup, err := control.New("child", resources)
|
|||
This allows you to get notified by an eventfd for v1 memory cgroups events.
|
||||
|
||||
```go
|
||||
event := cgroups.MemoryThresholdEvent(50 * 1024 * 1024, false)
|
||||
event := cgroup1.MemoryThresholdEvent(50 * 1024 * 1024, false)
|
||||
efd, err := control.RegisterMemoryEvent(event)
|
||||
```
|
||||
|
||||
```go
|
||||
event := cgroups.MemoryPressureEvent(cgroups.MediumPressure, cgroups.DefaultMode)
|
||||
event := cgroup1.MemoryPressureEvent(cgroup1.MediumPressure, cgroup1.DefaultMode)
|
||||
efd, err := control.RegisterMemoryEvent(event)
|
||||
```
|
||||
|
||||
```go
|
||||
efd, err := control.OOMEventFD()
|
||||
// or by using RegisterMemoryEvent
|
||||
event := cgroups.OOMEvent()
|
||||
event := cgroup1.OOMEvent()
|
||||
efd, err := control.RegisterMemoryEvent(event)
|
||||
```
|
||||
|
||||
## Examples (v2/unified)
|
||||
|
||||
### Check that the current system is running cgroups v2
|
||||
|
||||
```go
|
||||
var cgroupV2 bool
|
||||
if cgroups.Mode() == cgroups.Unified {
|
||||
cgroupV2 = true
|
||||
}
|
||||
```
|
||||
|
||||
### Create a new cgroup
|
||||
|
||||
This creates a new systemd v2 cgroup slice. Systemd slices consider ["-" a special character](https://www.freedesktop.org/software/systemd/man/systemd.slice.html),
|
||||
so the resulting slice would be located here on disk:
|
||||
|
||||
* /sys/fs/cgroup/my.slice/my-cgroup.slice/my-cgroup-abc.slice
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/containerd/cgroups/v3/cgroup2"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
res := cgroup2.Resources{}
|
||||
// dummy PID of -1 is used for creating a "general slice" to be used as a parent cgroup.
|
||||
// see https://github.com/containerd/cgroups/blob/1df78138f1e1e6ee593db155c6b369466f577651/v2/manager.go#L732-L735
|
||||
m, err := cgroup2.NewSystemd("/", "my-cgroup-abc.slice", -1, &res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### Load an existing cgroup
|
||||
|
||||
```go
|
||||
m, err := cgroup2.LoadSystemd("/", "my-cgroup-abc.slice")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### Delete a cgroup
|
||||
|
||||
```go
|
||||
m, err := cgroup2.LoadSystemd("/", "my-cgroup-abc.slice")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.DeleteSystemd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### Kill all processes in a cgroup
|
||||
|
||||
```go
|
||||
m, err := cgroup2.LoadSystemd("/", "my-cgroup-abc.slice")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.Kill()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### Attention
|
||||
|
||||
All static path should not include `/sys/fs/cgroup/` prefix, it should start with your own cgroups name
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
|
@ -25,7 +25,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
|
@ -71,7 +72,7 @@ func (b *blkioController) Create(path string, resources *specs.LinuxResources) e
|
|||
}
|
||||
for _, t := range createBlkioSettings(resources.BlockIO) {
|
||||
if t.value != nil {
|
||||
if err := retryingWriteFile(
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(b.Path(path), "blkio."+t.name),
|
||||
t.format(t.value),
|
||||
defaultFilePerm,
|
||||
|
|
@ -14,31 +14,34 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// New returns a new control via the cgroup cgroups interface
|
||||
func New(hierarchy Hierarchy, path Path, resources *specs.LinuxResources, opts ...InitOpts) (Cgroup, error) {
|
||||
func New(path Path, resources *specs.LinuxResources, opts ...InitOpts) (Cgroup, error) {
|
||||
config := newInitConfig()
|
||||
for _, o := range opts {
|
||||
if err := o(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
subsystems, err := hierarchy()
|
||||
subsystems, err := config.hiearchy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -68,7 +71,7 @@ func New(hierarchy Hierarchy, path Path, resources *specs.LinuxResources, opts .
|
|||
|
||||
// Load will load an existing cgroup and allow it to be controlled
|
||||
// All static path should not include `/sys/fs/cgroup/` prefix, it should start with your own cgroups name
|
||||
func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) {
|
||||
func Load(path Path, opts ...InitOpts) (Cgroup, error) {
|
||||
config := newInitConfig()
|
||||
for _, o := range opts {
|
||||
if err := o(config); err != nil {
|
||||
|
|
@ -76,7 +79,7 @@ func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) {
|
|||
}
|
||||
}
|
||||
var activeSubsystems []Subsystem
|
||||
subsystems, err := hierarchy()
|
||||
subsystems, err := config.hiearchy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -84,7 +87,7 @@ func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) {
|
|||
for _, s := range pathers(subsystems) {
|
||||
p, err := path(s.Name())
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil, ErrCgroupDeleted
|
||||
}
|
||||
if err == ErrControllerNotActive {
|
||||
|
|
@ -193,6 +196,31 @@ func (c *cgroup) AddTask(process Process, subsystems ...Name) error {
|
|||
return c.add(process, cgroupTasks, subsystems...)
|
||||
}
|
||||
|
||||
// writeCgroupsProcs writes to the file, but retries on EINVAL.
|
||||
func writeCgroupProcs(path string, content []byte, perm fs.FileMode) error {
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
_, err = f.Write(content)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
// If the process's associated task's state is TASK_NEW, the kernel
|
||||
// returns EINVAL. The function will retry on the error like runc.
|
||||
// https://github.com/torvalds/linux/blob/v6.0/kernel/sched/core.c#L10308-L10337
|
||||
// https://github.com/opencontainers/runc/pull/1950
|
||||
if !errors.Is(err, syscall.EINVAL) {
|
||||
return err
|
||||
}
|
||||
time.Sleep(30 * time.Millisecond)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *cgroup) add(process Process, pType procType, subsystems ...Name) error {
|
||||
if process.Pid <= 0 {
|
||||
return ErrInvalidPid
|
||||
|
|
@ -207,7 +235,7 @@ func (c *cgroup) add(process Process, pType procType, subsystems ...Name) error
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = retryingWriteFile(
|
||||
err = writeCgroupProcs(
|
||||
filepath.Join(s.Path(p), pType),
|
||||
[]byte(strconv.Itoa(process.Pid)),
|
||||
defaultFilePerm,
|
||||
|
|
@ -228,6 +256,15 @@ func (c *cgroup) Delete() error {
|
|||
}
|
||||
var errs []string
|
||||
for _, s := range c.subsystems {
|
||||
// kernel prevents cgroups with running process from being removed, check the tree is empty
|
||||
procs, err := c.processes(s.Name(), true, cgroupProcs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(procs) > 0 {
|
||||
errs = append(errs, fmt.Sprintf("%s (contains running processes)", string(s.Name())))
|
||||
continue
|
||||
}
|
||||
if d, ok := s.(deleter); ok {
|
||||
sp, err := c.path(s.Name())
|
||||
if err != nil {
|
||||
|
|
@ -247,6 +284,7 @@ func (c *cgroup) Delete() error {
|
|||
if err := remove(path); err != nil {
|
||||
errs = append(errs, path)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
|
|
@ -14,12 +14,12 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
|
@ -22,7 +22,7 @@ import (
|
|||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ func (c *cpuController) Create(path string, resources *specs.LinuxResources) err
|
|||
value = []byte(strconv.FormatInt(*t.ivalue, 10))
|
||||
}
|
||||
if value != nil {
|
||||
if err := retryingWriteFile(
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(c.Path(path), "cpu."+t.name),
|
||||
value,
|
||||
defaultFilePerm,
|
||||
|
|
@ -14,16 +14,17 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
)
|
||||
|
||||
const nanosecondsInSecond = 1000000000
|
||||
|
|
@ -70,7 +71,7 @@ func (c *cpuacctController) Stat(path string, stats *v1.Metrics) error {
|
|||
|
||||
func (c *cpuacctController) percpuUsage(path string) ([]uint64, error) {
|
||||
var usage []uint64
|
||||
data, err := ioutil.ReadFile(filepath.Join(c.Path(path), "cpuacct.usage_percpu"))
|
||||
data, err := os.ReadFile(filepath.Join(c.Path(path), "cpuacct.usage_percpu"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -86,36 +87,41 @@ func (c *cpuacctController) percpuUsage(path string) ([]uint64, error) {
|
|||
|
||||
func (c *cpuacctController) getUsage(path string) (user uint64, kernel uint64, err error) {
|
||||
statPath := filepath.Join(c.Path(path), "cpuacct.stat")
|
||||
data, err := ioutil.ReadFile(statPath)
|
||||
f, err := os.Open(statPath)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
fields := strings.Fields(string(data))
|
||||
if len(fields) != 4 {
|
||||
return 0, 0, fmt.Errorf("%q is expected to have 4 fields", statPath)
|
||||
defer f.Close()
|
||||
var (
|
||||
raw = make(map[string]uint64)
|
||||
sc = bufio.NewScanner(f)
|
||||
)
|
||||
for sc.Scan() {
|
||||
key, v, err := parseKV(sc.Text())
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
raw[key] = v
|
||||
}
|
||||
if err := sc.Err(); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
for _, t := range []struct {
|
||||
index int
|
||||
name string
|
||||
value *uint64
|
||||
}{
|
||||
{
|
||||
index: 0,
|
||||
name: "user",
|
||||
value: &user,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
name: "system",
|
||||
value: &kernel,
|
||||
},
|
||||
} {
|
||||
if fields[t.index] != t.name {
|
||||
return 0, 0, fmt.Errorf("expected field %q but found %q in %q", t.name, fields[t.index], statPath)
|
||||
}
|
||||
v, err := strconv.ParseUint(fields[t.index+1], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
v, ok := raw[t.name]
|
||||
if !ok {
|
||||
return 0, 0, fmt.Errorf("expected field %q but not found in %q", t.name, statPath)
|
||||
}
|
||||
*t.value = v
|
||||
}
|
||||
|
|
@ -14,12 +14,11 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
|
|
@ -69,7 +68,7 @@ func (c *cpusetController) Create(path string, resources *specs.LinuxResources)
|
|||
},
|
||||
} {
|
||||
if t.value != "" {
|
||||
if err := retryingWriteFile(
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(c.Path(path), "cpuset."+t.name),
|
||||
[]byte(t.value),
|
||||
defaultFilePerm,
|
||||
|
|
@ -87,10 +86,10 @@ func (c *cpusetController) Update(path string, resources *specs.LinuxResources)
|
|||
}
|
||||
|
||||
func (c *cpusetController) getValues(path string) (cpus []byte, mems []byte, err error) {
|
||||
if cpus, err = ioutil.ReadFile(filepath.Join(path, "cpuset.cpus")); err != nil && !os.IsNotExist(err) {
|
||||
if cpus, err = os.ReadFile(filepath.Join(path, "cpuset.cpus")); err != nil && !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
if mems, err = ioutil.ReadFile(filepath.Join(path, "cpuset.mems")); err != nil && !os.IsNotExist(err) {
|
||||
if mems, err = os.ReadFile(filepath.Join(path, "cpuset.mems")); err != nil && !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
return cpus, mems, nil
|
||||
|
|
@ -134,7 +133,7 @@ func (c *cpusetController) copyIfNeeded(current, parent string) error {
|
|||
return err
|
||||
}
|
||||
if isEmpty(currentCpus) {
|
||||
if err := retryingWriteFile(
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(current, "cpuset.cpus"),
|
||||
parentCpus,
|
||||
defaultFilePerm,
|
||||
|
|
@ -143,7 +142,7 @@ func (c *cpusetController) copyIfNeeded(current, parent string) error {
|
|||
}
|
||||
}
|
||||
if isEmpty(currentMems) {
|
||||
if err := retryingWriteFile(
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(current, "cpuset.mems"),
|
||||
parentMems,
|
||||
defaultFilePerm,
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -60,7 +60,7 @@ func (d *devicesController) Create(path string, resources *specs.LinuxResources)
|
|||
if device.Type == "" {
|
||||
device.Type = "a"
|
||||
}
|
||||
if err := retryingWriteFile(
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(d.Path(path), file),
|
||||
[]byte(deviceString(device)),
|
||||
defaultFilePerm,
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -14,10 +14,10 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -50,7 +50,7 @@ func (f *freezerController) Thaw(path string) error {
|
|||
}
|
||||
|
||||
func (f *freezerController) changeState(path string, state State) error {
|
||||
return retryingWriteFile(
|
||||
return os.WriteFile(
|
||||
filepath.Join(f.root, path, "freezer.state"),
|
||||
[]byte(strings.ToUpper(string(state))),
|
||||
defaultFilePerm,
|
||||
|
|
@ -58,7 +58,7 @@ func (f *freezerController) changeState(path string, state State) error {
|
|||
}
|
||||
|
||||
func (f *freezerController) state(path string) (State, error) {
|
||||
current, err := ioutil.ReadFile(filepath.Join(f.root, path, "freezer.state"))
|
||||
current, err := os.ReadFile(filepath.Join(f.root, path, "freezer.state"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
// Hierarchy enables both unified and split hierarchy for cgroups
|
||||
type Hierarchy func() ([]Subsystem, error)
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
|
@ -22,7 +22,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ func (h *hugetlbController) Create(path string, resources *specs.LinuxResources)
|
|||
return err
|
||||
}
|
||||
for _, limit := range resources.HugepageLimits {
|
||||
if err := retryingWriteFile(
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(h.Path(path), strings.Join([]string{"hugetlb", limit.Pagesize, "limit_in_bytes"}, ".")),
|
||||
[]byte(strconv.FormatUint(limit.Limit, 10)),
|
||||
defaultFilePerm,
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
|
@ -25,7 +25,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
|
@ -43,7 +43,7 @@ type memoryThresholdEvent struct {
|
|||
swap bool
|
||||
}
|
||||
|
||||
// MemoryThresholdEvent returns a new memory threshold event to be used with RegisterMemoryEvent.
|
||||
// MemoryThresholdEvent returns a new [MemoryEvent] representing the memory threshold set.
|
||||
// If swap is true, the event will be registered using memory.memsw.usage_in_bytes
|
||||
func MemoryThresholdEvent(threshold uint64, swap bool) MemoryEvent {
|
||||
return &memoryThresholdEvent{
|
||||
|
|
@ -83,7 +83,7 @@ type memoryPressureEvent struct {
|
|||
hierarchy EventNotificationMode
|
||||
}
|
||||
|
||||
// MemoryPressureEvent returns a new memory pressure event to be used with RegisterMemoryEvent.
|
||||
// MemoryPressureEvent returns a new [MemoryEvent] representing the memory pressure set.
|
||||
func MemoryPressureEvent(pressureLevel MemoryPressureLevel, hierarchy EventNotificationMode) MemoryEvent {
|
||||
return &memoryPressureEvent{
|
||||
pressureLevel,
|
||||
|
|
@ -104,22 +104,22 @@ func (m *memoryPressureEvent) EventFile() string {
|
|||
type MemoryPressureLevel string
|
||||
|
||||
// The three memory pressure levels are as follows.
|
||||
// - The "low" level means that the system is reclaiming memory for new
|
||||
// allocations. Monitoring this reclaiming activity might be useful for
|
||||
// maintaining cache level. Upon notification, the program (typically
|
||||
// "Activity Manager") might analyze vmstat and act in advance (i.e.
|
||||
// prematurely shutdown unimportant services).
|
||||
// - The "medium" level means that the system is experiencing medium memory
|
||||
// pressure, the system might be making swap, paging out active file caches,
|
||||
// etc. Upon this event applications may decide to further analyze
|
||||
// vmstat/zoneinfo/memcg or internal memory usage statistics and free any
|
||||
// resources that can be easily reconstructed or re-read from a disk.
|
||||
// - The "critical" level means that the system is actively thrashing, it is
|
||||
// about to out of memory (OOM) or even the in-kernel OOM killer is on its
|
||||
// way to trigger. Applications should do whatever they can to help the
|
||||
// system. It might be too late to consult with vmstat or any other
|
||||
// statistics, so it is advisable to take an immediate action.
|
||||
// "https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt" Section 11
|
||||
// - The "low" level means that the system is reclaiming memory for new
|
||||
// allocations. Monitoring this reclaiming activity might be useful for
|
||||
// maintaining cache level. Upon notification, the program (typically
|
||||
// "Activity Manager") might analyze vmstat and act in advance (i.e.
|
||||
// prematurely shutdown unimportant services).
|
||||
// - The "medium" level means that the system is experiencing medium memory
|
||||
// pressure, the system might be making swap, paging out active file caches,
|
||||
// etc. Upon this event applications may decide to further analyze
|
||||
// vmstat/zoneinfo/memcg or internal memory usage statistics and free any
|
||||
// resources that can be easily reconstructed or re-read from a disk.
|
||||
// - The "critical" level means that the system is actively thrashing, it is
|
||||
// about to out of memory (OOM) or even the in-kernel OOM killer is on its
|
||||
// way to trigger. Applications should do whatever they can to help the
|
||||
// system. It might be too late to consult with vmstat or any other
|
||||
// statistics, so it is advisable to take an immediate action.
|
||||
// "https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt" Section 11
|
||||
const (
|
||||
LowPressure MemoryPressureLevel = "low"
|
||||
MediumPressure MemoryPressureLevel = "medium"
|
||||
|
|
@ -131,21 +131,21 @@ const (
|
|||
type EventNotificationMode string
|
||||
|
||||
// There are three optional modes that specify different propagation behavior:
|
||||
// - "default": this is the default behavior specified above. This mode is the
|
||||
// same as omitting the optional mode parameter, preserved by backwards
|
||||
// compatibility.
|
||||
// - "hierarchy": events always propagate up to the root, similar to the default
|
||||
// behavior, except that propagation continues regardless of whether there are
|
||||
// event listeners at each level, with the "hierarchy" mode. In the above
|
||||
// example, groups A, B, and C will receive notification of memory pressure.
|
||||
// - "local": events are pass-through, i.e. they only receive notifications when
|
||||
// memory pressure is experienced in the memcg for which the notification is
|
||||
// registered. In the above example, group C will receive notification if
|
||||
// registered for "local" notification and the group experiences memory
|
||||
// pressure. However, group B will never receive notification, regardless if
|
||||
// there is an event listener for group C or not, if group B is registered for
|
||||
// local notification.
|
||||
// "https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt" Section 11
|
||||
// - "default": this is the default behavior specified above. This mode is the
|
||||
// same as omitting the optional mode parameter, preserved by backwards
|
||||
// compatibility.
|
||||
// - "hierarchy": events always propagate up to the root, similar to the default
|
||||
// behavior, except that propagation continues regardless of whether there are
|
||||
// event listeners at each level, with the "hierarchy" mode. In the above
|
||||
// example, groups A, B, and C will receive notification of memory pressure.
|
||||
// - "local": events are pass-through, i.e. they only receive notifications when
|
||||
// memory pressure is experienced in the memcg for which the notification is
|
||||
// registered. In the above example, group C will receive notification if
|
||||
// registered for "local" notification and the group experiences memory
|
||||
// pressure. However, group B will never receive notification, regardless if
|
||||
// there is an event listener for group C or not, if group B is registered for
|
||||
// local notification.
|
||||
// "https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt" Section 11
|
||||
const (
|
||||
DefaultMode EventNotificationMode = "default"
|
||||
LocalMode EventNotificationMode = "local"
|
||||
|
|
@ -394,7 +394,7 @@ func (m *memoryController) parseOomControlStats(r io.Reader, stat *v1.MemoryOomC
|
|||
func (m *memoryController) set(path string, settings []memorySettings) error {
|
||||
for _, t := range settings {
|
||||
if t.value != nil {
|
||||
if err := retryingWriteFile(
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(m.Path(path), "memory."+t.name),
|
||||
[]byte(strconv.FormatInt(*t.value, 10)),
|
||||
defaultFilePerm,
|
||||
|
|
@ -472,7 +472,7 @@ func (m *memoryController) memoryEvent(path string, event MemoryEvent) (uintptr,
|
|||
defer evtFile.Close()
|
||||
data := fmt.Sprintf("%d %d %s", efd, evtFile.Fd(), event.Arg())
|
||||
evctlPath := filepath.Join(root, "cgroup.event_control")
|
||||
if err := retryingWriteFile(evctlPath, []byte(data), 0700); err != nil {
|
||||
if err := os.WriteFile(evctlPath, []byte(data), 0700); err != nil {
|
||||
unix.Close(efd)
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
|
@ -47,7 +47,7 @@ func (n *netclsController) Create(path string, resources *specs.LinuxResources)
|
|||
return err
|
||||
}
|
||||
if resources.Network != nil && resources.Network.ClassID != nil && *resources.Network.ClassID > 0 {
|
||||
return retryingWriteFile(
|
||||
return os.WriteFile(
|
||||
filepath.Join(n.Path(path), "net_cls.classid"),
|
||||
[]byte(strconv.FormatUint(uint64(*resources.Network.ClassID), 10)),
|
||||
defaultFilePerm,
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -48,7 +48,7 @@ func (n *netprioController) Create(path string, resources *specs.LinuxResources)
|
|||
}
|
||||
if resources.Network != nil {
|
||||
for _, prio := range resources.Network.Priorities {
|
||||
if err := retryingWriteFile(
|
||||
if err := os.WriteFile(
|
||||
filepath.Join(n.Path(path), "net_prio.ifpriomap"),
|
||||
formatPrio(prio.Name, prio.Priority),
|
||||
defaultFilePerm,
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -36,11 +36,13 @@ type InitOpts func(*InitConfig) error
|
|||
type InitConfig struct {
|
||||
// InitCheck can be used to check initialization errors from the subsystem
|
||||
InitCheck InitCheck
|
||||
hiearchy Hierarchy
|
||||
}
|
||||
|
||||
func newInitConfig() *InitConfig {
|
||||
return &InitConfig{
|
||||
InitCheck: RequireDevices,
|
||||
hiearchy: Default,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -59,3 +61,12 @@ func RequireDevices(s Subsystem, _ Path, _ error) error {
|
|||
}
|
||||
return ErrIgnoreSubsystem
|
||||
}
|
||||
|
||||
// WithHiearchy sets a list of cgroup subsystems.
|
||||
// The default list is coming from /proc/self/mountinfo.
|
||||
func WithHiearchy(h Hierarchy) InitOpts {
|
||||
return func(c *InitConfig) error {
|
||||
c.hiearchy = h
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
|
|
@ -14,16 +14,15 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
|
@ -50,7 +49,7 @@ func (p *pidsController) Create(path string, resources *specs.LinuxResources) er
|
|||
return err
|
||||
}
|
||||
if resources.Pids != nil && resources.Pids.Limit > 0 {
|
||||
return retryingWriteFile(
|
||||
return os.WriteFile(
|
||||
filepath.Join(p.Path(path), "pids.max"),
|
||||
[]byte(strconv.FormatInt(resources.Pids.Limit, 10)),
|
||||
defaultFilePerm,
|
||||
|
|
@ -69,7 +68,7 @@ func (p *pidsController) Stat(path string, stats *v1.Metrics) error {
|
|||
return err
|
||||
}
|
||||
var max uint64
|
||||
maxData, err := ioutil.ReadFile(filepath.Join(p.Path(path), "pids.max"))
|
||||
maxData, err := os.ReadFile(filepath.Join(p.Path(path), "pids.max"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -14,17 +14,16 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
|
@ -68,7 +67,7 @@ func (p *rdmaController) Create(path string, resources *specs.LinuxResources) er
|
|||
for device, limit := range resources.Rdma {
|
||||
if device != "" && (limit.HcaHandles != nil || limit.HcaObjects != nil) {
|
||||
limit := limit
|
||||
return retryingWriteFile(
|
||||
return os.WriteFile(
|
||||
filepath.Join(p.Path(path), "rdma.max"),
|
||||
[]byte(createCmdString(device, &limit)),
|
||||
defaultFilePerm,
|
||||
|
|
@ -126,13 +125,13 @@ func toRdmaEntry(strEntries []string) []*v1.RdmaEntry {
|
|||
|
||||
func (p *rdmaController) Stat(path string, stats *v1.Metrics) error {
|
||||
|
||||
currentData, err := ioutil.ReadFile(filepath.Join(p.Path(path), "rdma.current"))
|
||||
currentData, err := os.ReadFile(filepath.Join(p.Path(path), "rdma.current"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currentPerDevices := strings.Split(string(currentData), "\n")
|
||||
|
||||
maxData, err := ioutil.ReadFile(filepath.Join(p.Path(path), "rdma.max"))
|
||||
maxData, err := os.ReadFile(filepath.Join(p.Path(path), "rdma.max"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
// State is a type that represents the state of the current cgroup
|
||||
type State string
|
||||
1959
vendor/github.com/containerd/cgroups/v3/cgroup1/stats/metrics.pb.go
generated
vendored
Normal file
1959
vendor/github.com/containerd/cgroups/v3/cgroup1/stats/metrics.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,6 @@
|
|||
file {
|
||||
name: "github.com/containerd/cgroups/stats/v1/metrics.proto"
|
||||
name: "github.com/containerd/cgroups/cgroup1/stats/metrics.proto"
|
||||
package: "io.containerd.cgroups.v1"
|
||||
dependency: "gogoproto/gogo.proto"
|
||||
message_type {
|
||||
name: "Metrics"
|
||||
field {
|
||||
|
|
@ -26,9 +25,6 @@ file {
|
|||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".io.containerd.cgroups.v1.CPUStat"
|
||||
options {
|
||||
65004: "CPU"
|
||||
}
|
||||
json_name: "cpu"
|
||||
}
|
||||
field {
|
||||
|
|
@ -175,9 +171,6 @@ file {
|
|||
number: 4
|
||||
label: LABEL_REPEATED
|
||||
type: TYPE_UINT64
|
||||
options {
|
||||
65004: "PerCPU"
|
||||
}
|
||||
json_name: "perCpu"
|
||||
}
|
||||
}
|
||||
|
|
@ -219,9 +212,6 @@ file {
|
|||
number: 2
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT64
|
||||
options {
|
||||
65004: "RSS"
|
||||
}
|
||||
json_name: "rss"
|
||||
}
|
||||
field {
|
||||
|
|
@ -229,9 +219,6 @@ file {
|
|||
number: 3
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT64
|
||||
options {
|
||||
65004: "RSSHuge"
|
||||
}
|
||||
json_name: "rssHuge"
|
||||
}
|
||||
field {
|
||||
|
|
@ -344,9 +331,6 @@ file {
|
|||
number: 19
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT64
|
||||
options {
|
||||
65004: "TotalRSS"
|
||||
}
|
||||
json_name: "totalRss"
|
||||
}
|
||||
field {
|
||||
|
|
@ -354,9 +338,6 @@ file {
|
|||
number: 20
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT64
|
||||
options {
|
||||
65004: "TotalRSSHuge"
|
||||
}
|
||||
json_name: "totalRssHuge"
|
||||
}
|
||||
field {
|
||||
|
|
@ -473,9 +454,6 @@ file {
|
|||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".io.containerd.cgroups.v1.MemoryEntry"
|
||||
options {
|
||||
65004: "KernelTCP"
|
||||
}
|
||||
json_name: "kernelTcp"
|
||||
}
|
||||
}
|
||||
|
|
@ -786,5 +764,8 @@ file {
|
|||
json_name: "nrIoWait"
|
||||
}
|
||||
}
|
||||
options {
|
||||
go_package: "github.com/containerd/cgroups/cgroup1/stats"
|
||||
}
|
||||
syntax: "proto3"
|
||||
}
|
||||
|
|
@ -2,12 +2,12 @@ syntax = "proto3";
|
|||
|
||||
package io.containerd.cgroups.v1;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
option go_package = "github.com/containerd/cgroups/cgroup1/stats";
|
||||
|
||||
message Metrics {
|
||||
repeated HugetlbStat hugetlb = 1;
|
||||
PidsStat pids = 2;
|
||||
CPUStat cpu = 3 [(gogoproto.customname) = "CPU"];
|
||||
CPUStat cpu = 3;
|
||||
MemoryStat memory = 4;
|
||||
BlkIOStat blkio = 5;
|
||||
RdmaStat rdma = 6;
|
||||
|
|
@ -38,7 +38,7 @@ message CPUUsage {
|
|||
uint64 total = 1;
|
||||
uint64 kernel = 2;
|
||||
uint64 user = 3;
|
||||
repeated uint64 per_cpu = 4 [(gogoproto.customname) = "PerCPU"];
|
||||
repeated uint64 per_cpu = 4;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -50,8 +50,8 @@ message Throttle {
|
|||
|
||||
message MemoryStat {
|
||||
uint64 cache = 1;
|
||||
uint64 rss = 2 [(gogoproto.customname) = "RSS"];
|
||||
uint64 rss_huge = 3 [(gogoproto.customname) = "RSSHuge"];
|
||||
uint64 rss = 2;
|
||||
uint64 rss_huge = 3;
|
||||
uint64 mapped_file = 4;
|
||||
uint64 dirty = 5;
|
||||
uint64 writeback = 6;
|
||||
|
|
@ -67,8 +67,8 @@ message MemoryStat {
|
|||
uint64 hierarchical_memory_limit = 16;
|
||||
uint64 hierarchical_swap_limit = 17;
|
||||
uint64 total_cache = 18;
|
||||
uint64 total_rss = 19 [(gogoproto.customname) = "TotalRSS"];
|
||||
uint64 total_rss_huge = 20 [(gogoproto.customname) = "TotalRSSHuge"];
|
||||
uint64 total_rss = 19;
|
||||
uint64 total_rss_huge = 20;
|
||||
uint64 total_mapped_file = 21;
|
||||
uint64 total_dirty = 22;
|
||||
uint64 total_writeback = 23;
|
||||
|
|
@ -84,7 +84,7 @@ message MemoryStat {
|
|||
MemoryEntry usage = 33;
|
||||
MemoryEntry swap = 34;
|
||||
MemoryEntry kernel = 35;
|
||||
MemoryEntry kernel_tcp = 36 [(gogoproto.customname) = "KernelTCP"];
|
||||
MemoryEntry kernel_tcp = 36;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -14,13 +14,14 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
"github.com/containerd/cgroups/v3"
|
||||
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
|
|
@ -59,7 +60,7 @@ func Subsystems() []Name {
|
|||
Blkio,
|
||||
Rdma,
|
||||
}
|
||||
if !RunningInUserNS() {
|
||||
if !cgroups.RunningInUserNS() {
|
||||
n = append(n, Devices)
|
||||
}
|
||||
if _, err := os.Stat("/sys/kernel/mm/hugepages"); err == nil {
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
func getClockTicks() uint64 {
|
||||
// The value comes from `C.sysconf(C._SC_CLK_TCK)`, and
|
||||
|
|
@ -14,107 +14,22 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/cgroups/v3"
|
||||
units "github.com/docker/go-units"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
nsOnce sync.Once
|
||||
inUserNS bool
|
||||
checkMode sync.Once
|
||||
cgMode CGMode
|
||||
)
|
||||
|
||||
const unifiedMountpoint = "/sys/fs/cgroup"
|
||||
|
||||
// CGMode is the cgroups mode of the host system
|
||||
type CGMode int
|
||||
|
||||
const (
|
||||
// Unavailable cgroup mountpoint
|
||||
Unavailable CGMode = iota
|
||||
// Legacy cgroups v1
|
||||
Legacy
|
||||
// Hybrid with cgroups v1 and v2 controllers mounted
|
||||
Hybrid
|
||||
// Unified with only cgroups v2 mounted
|
||||
Unified
|
||||
)
|
||||
|
||||
// Mode returns the cgroups mode running on the host
|
||||
func Mode() CGMode {
|
||||
checkMode.Do(func() {
|
||||
var st unix.Statfs_t
|
||||
if err := unix.Statfs(unifiedMountpoint, &st); err != nil {
|
||||
cgMode = Unavailable
|
||||
return
|
||||
}
|
||||
switch st.Type {
|
||||
case unix.CGROUP2_SUPER_MAGIC:
|
||||
cgMode = Unified
|
||||
default:
|
||||
cgMode = Legacy
|
||||
if err := unix.Statfs(filepath.Join(unifiedMountpoint, "unified"), &st); err != nil {
|
||||
return
|
||||
}
|
||||
if st.Type == unix.CGROUP2_SUPER_MAGIC {
|
||||
cgMode = Hybrid
|
||||
}
|
||||
}
|
||||
})
|
||||
return cgMode
|
||||
}
|
||||
|
||||
// RunningInUserNS detects whether we are currently running in a user namespace.
|
||||
// Copied from github.com/lxc/lxd/shared/util.go
|
||||
func RunningInUserNS() bool {
|
||||
nsOnce.Do(func() {
|
||||
file, err := os.Open("/proc/self/uid_map")
|
||||
if err != nil {
|
||||
// This kernel-provided file only exists if user namespaces are supported
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
buf := bufio.NewReader(file)
|
||||
l, _, err := buf.ReadLine()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
line := string(l)
|
||||
var a, b, c int64
|
||||
fmt.Sscanf(line, "%d %d %d", &a, &b, &c)
|
||||
|
||||
/*
|
||||
* We assume we are in the initial user namespace if we have a full
|
||||
* range - 4294967295 uids starting at uid 0.
|
||||
*/
|
||||
if a == 0 && b == 0 && c == 4294967295 {
|
||||
return
|
||||
}
|
||||
inUserNS = true
|
||||
})
|
||||
return inUserNS
|
||||
}
|
||||
|
||||
// defaults returns all known groups
|
||||
func defaults(root string) ([]Subsystem, error) {
|
||||
h, err := NewHugetlb(root)
|
||||
|
|
@ -137,7 +52,7 @@ func defaults(root string) ([]Subsystem, error) {
|
|||
}
|
||||
// only add the devices cgroup if we are not in a user namespace
|
||||
// because modifications are not allowed
|
||||
if !RunningInUserNS() {
|
||||
if !cgroups.RunningInUserNS() {
|
||||
s = append(s, NewDevices(root))
|
||||
}
|
||||
// add the hugetlb cgroup if error wasn't due to missing hugetlb
|
||||
|
|
@ -200,7 +115,7 @@ func hugePageSizes() ([]string, error) {
|
|||
pageSizes []string
|
||||
sizeList = []string{"B", "KB", "MB", "GB", "TB", "PB"}
|
||||
)
|
||||
files, err := ioutil.ReadDir("/sys/kernel/mm/hugepages")
|
||||
files, err := os.ReadDir("/sys/kernel/mm/hugepages")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -216,7 +131,7 @@ func hugePageSizes() ([]string, error) {
|
|||
}
|
||||
|
||||
func readUint(path string) (uint64, error) {
|
||||
v, err := ioutil.ReadFile(path)
|
||||
v, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
@ -257,12 +172,14 @@ func parseKV(raw string) (string, uint64, error) {
|
|||
|
||||
// ParseCgroupFile parses the given cgroup file, typically /proc/self/cgroup
|
||||
// or /proc/<pid>/cgroup, into a map of subsystems to cgroup paths, e.g.
|
||||
// "cpu": "/user.slice/user-1000.slice"
|
||||
// "pids": "/user.slice/user-1000.slice"
|
||||
//
|
||||
// "cpu": "/user.slice/user-1000.slice"
|
||||
// "pids": "/user.slice/user-1000.slice"
|
||||
//
|
||||
// etc.
|
||||
//
|
||||
// The resulting map does not have an element for cgroup v2 unified hierarchy.
|
||||
// Use ParseCgroupFileUnified to get the unified path.
|
||||
// Use [cgroups.ParseCgroupFileUnified] to get the unified path.
|
||||
func ParseCgroupFile(path string) (map[string]string, error) {
|
||||
x, _, err := ParseCgroupFileUnified(path)
|
||||
return x, err
|
||||
|
|
@ -270,41 +187,10 @@ func ParseCgroupFile(path string) (map[string]string, error) {
|
|||
|
||||
// ParseCgroupFileUnified returns legacy subsystem paths as the first value,
|
||||
// and returns the unified path as the second value.
|
||||
//
|
||||
// Deprecated: use [cgroups.ParseCgroupFileUnified] instead .
|
||||
func ParseCgroupFileUnified(path string) (map[string]string, string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
defer f.Close()
|
||||
return parseCgroupFromReaderUnified(f)
|
||||
}
|
||||
|
||||
func parseCgroupFromReaderUnified(r io.Reader) (map[string]string, string, error) {
|
||||
var (
|
||||
cgroups = make(map[string]string)
|
||||
unified = ""
|
||||
s = bufio.NewScanner(r)
|
||||
)
|
||||
for s.Scan() {
|
||||
var (
|
||||
text = s.Text()
|
||||
parts = strings.SplitN(text, ":", 3)
|
||||
)
|
||||
if len(parts) < 3 {
|
||||
return nil, unified, fmt.Errorf("invalid cgroup entry: %q", text)
|
||||
}
|
||||
for _, subs := range strings.Split(parts[1], ",") {
|
||||
if subs == "" {
|
||||
unified = parts[2]
|
||||
} else {
|
||||
cgroups[subs] = parts[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, unified, err
|
||||
}
|
||||
return cgroups, unified, nil
|
||||
return cgroups.ParseCgroupFileUnified(path)
|
||||
}
|
||||
|
||||
func getCgroupDestination(subsystem string) (string, error) {
|
||||
|
|
@ -377,16 +263,3 @@ func cleanPath(path string) string {
|
|||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func retryingWriteFile(path string, data []byte, mode os.FileMode) error {
|
||||
// Retry writes on EINTR; see:
|
||||
// https://github.com/golang/go/issues/38033
|
||||
for {
|
||||
err := ioutil.WriteFile(path, data, mode)
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if !errors.Is(err, syscall.EINTR) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cgroups
|
||||
package cgroup1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
|
@ -24,8 +24,8 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// V1 returns all the groups in the default cgroups mountpoint in a single hierarchy
|
||||
func V1() ([]Subsystem, error) {
|
||||
// Default returns all the groups in the default cgroups mountpoint in a single hierarchy
|
||||
func Default() ([]Subsystem, error) {
|
||||
root, err := v1MountPoint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
// This particular Go implementation based on runc version
|
||||
// https://github.com/opencontainers/runc/blob/master/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import "strings"
|
||||
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import "fmt"
|
||||
|
||||
|
|
@ -14,14 +14,14 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -30,7 +30,7 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/cgroups/v2/stats"
|
||||
"github.com/containerd/cgroups/v3/cgroup2/stats"
|
||||
|
||||
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
|
||||
"github.com/godbus/dbus/v5"
|
||||
|
|
@ -42,6 +42,7 @@ import (
|
|||
const (
|
||||
subtreeControl = "cgroup.subtree_control"
|
||||
controllersFile = "cgroup.controllers"
|
||||
killFile = "cgroup.kill"
|
||||
defaultCgroup2Path = "/sys/fs/cgroup"
|
||||
defaultSlice = "system.slice"
|
||||
)
|
||||
|
|
@ -144,20 +145,11 @@ func (c *Value) write(path string, perm os.FileMode) error {
|
|||
return ErrInvalidFormat
|
||||
}
|
||||
|
||||
// Retry writes on EINTR; see:
|
||||
// https://github.com/golang/go/issues/38033
|
||||
for {
|
||||
err := ioutil.WriteFile(
|
||||
filepath.Join(path, c.filename),
|
||||
data,
|
||||
perm,
|
||||
)
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if !errors.Is(err, syscall.EINTR) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return os.WriteFile(
|
||||
filepath.Join(path, c.filename),
|
||||
data,
|
||||
perm,
|
||||
)
|
||||
}
|
||||
|
||||
func writeValues(path string, values []Value) error {
|
||||
|
|
@ -196,13 +188,35 @@ func NewManager(mountpoint string, group string, resources *Resources) (*Manager
|
|||
return &m, nil
|
||||
}
|
||||
|
||||
func LoadManager(mountpoint string, group string) (*Manager, error) {
|
||||
type InitConfig struct {
|
||||
mountpoint string
|
||||
}
|
||||
|
||||
type InitOpts func(c *InitConfig) error
|
||||
|
||||
// WithMountpoint sets the unified mountpoint. The default path is /sys/fs/cgroup.
|
||||
func WithMountpoint(path string) InitOpts {
|
||||
return func(c *InitConfig) error {
|
||||
c.mountpoint = path
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Load a cgroup.
|
||||
func Load(group string, opts ...InitOpts) (*Manager, error) {
|
||||
c := InitConfig{mountpoint: defaultCgroup2Path}
|
||||
for _, opt := range opts {
|
||||
if err := opt(&c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := VerifyGroupPath(group); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := filepath.Join(mountpoint, group)
|
||||
path := filepath.Join(c.mountpoint, group)
|
||||
return &Manager{
|
||||
unifiedMountpoint: mountpoint,
|
||||
unifiedMountpoint: c.mountpoint,
|
||||
path: path,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -225,7 +239,7 @@ func setResources(path string, resources *Resources) error {
|
|||
}
|
||||
|
||||
func (c *Manager) RootControllers() ([]string, error) {
|
||||
b, err := ioutil.ReadFile(filepath.Join(c.unifiedMountpoint, controllersFile))
|
||||
b, err := os.ReadFile(filepath.Join(c.unifiedMountpoint, controllersFile))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -233,7 +247,7 @@ func (c *Manager) RootControllers() ([]string, error) {
|
|||
}
|
||||
|
||||
func (c *Manager) Controllers() ([]string, error) {
|
||||
b, err := ioutil.ReadFile(filepath.Join(c.path, controllersFile))
|
||||
b, err := os.ReadFile(filepath.Join(c.path, controllersFile))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -336,7 +350,103 @@ func (c *Manager) AddProc(pid uint64) error {
|
|||
return writeValues(c.path, []Value{v})
|
||||
}
|
||||
|
||||
func (c *Manager) AddThread(tid uint64) error {
|
||||
v := Value{
|
||||
filename: cgroupThreads,
|
||||
value: tid,
|
||||
}
|
||||
return writeValues(c.path, []Value{v})
|
||||
}
|
||||
|
||||
// Kill will try to forcibly exit all of the processes in the cgroup. This is
|
||||
// equivalent to sending a SIGKILL to every process. On kernels 5.14 and greater
|
||||
// this will use the cgroup.kill file, on anything that doesn't have the cgroup.kill
|
||||
// file, a manual process of freezing -> sending a SIGKILL to every process -> thawing
|
||||
// will be used.
|
||||
func (c *Manager) Kill() error {
|
||||
v := Value{
|
||||
filename: killFile,
|
||||
value: "1",
|
||||
}
|
||||
err := writeValues(c.path, []Value{v})
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
logrus.Warnf("falling back to slower kill implementation: %s", err)
|
||||
// Fallback to slow method.
|
||||
return c.fallbackKill()
|
||||
}
|
||||
|
||||
// fallbackKill is a slower fallback to the more modern (kernels 5.14+)
|
||||
// approach of writing to the cgroup.kill file. This is heavily pulled
|
||||
// from runc's same approach (in signalAllProcesses), with the only differences
|
||||
// being this is just tailored to the API exposed in this library, and we don't
|
||||
// need to care about signals other than SIGKILL.
|
||||
//
|
||||
// https://github.com/opencontainers/runc/blob/8da0a0b5675764feaaaaad466f6567a9983fcd08/libcontainer/init_linux.go#L523-L529
|
||||
func (c *Manager) fallbackKill() error {
|
||||
if err := c.Freeze(); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
pids, err := c.Procs(true)
|
||||
if err != nil {
|
||||
if err := c.Thaw(); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
var procs []*os.Process
|
||||
for _, pid := range pids {
|
||||
p, err := os.FindProcess(int(pid))
|
||||
if err != nil {
|
||||
logrus.Warn(err)
|
||||
continue
|
||||
}
|
||||
procs = append(procs, p)
|
||||
if err := p.Signal(unix.SIGKILL); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
}
|
||||
if err := c.Thaw(); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
|
||||
subreaper, err := getSubreaper()
|
||||
if err != nil {
|
||||
// The error here means that PR_GET_CHILD_SUBREAPER is not
|
||||
// supported because this code might run on a kernel older
|
||||
// than 3.4. We don't want to throw an error in that case,
|
||||
// and we simplify things, considering there is no subreaper
|
||||
// set.
|
||||
subreaper = 0
|
||||
}
|
||||
|
||||
for _, p := range procs {
|
||||
// In case a subreaper has been setup, this code must not
|
||||
// wait for the process. Otherwise, we cannot be sure the
|
||||
// current process will be reaped by the subreaper, while
|
||||
// the subreaper might be waiting for this process in order
|
||||
// to retrieve its exit code.
|
||||
if subreaper == 0 {
|
||||
if _, err := p.Wait(); err != nil {
|
||||
if !errors.Is(err, unix.ECHILD) {
|
||||
logrus.Warnf("wait on pid %d failed: %s", p.Pid, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Manager) Delete() error {
|
||||
// kernel prevents cgroups with running process from being removed, check the tree is empty
|
||||
processes, err := c.Procs(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(processes) > 0 {
|
||||
return fmt.Errorf("cgroups: unable to remove path %q: still contains running processes", c.path)
|
||||
}
|
||||
return remove(c.path)
|
||||
}
|
||||
|
||||
|
|
@ -366,6 +476,22 @@ func (c *Manager) Procs(recursive bool) ([]uint64, error) {
|
|||
return processes, err
|
||||
}
|
||||
|
||||
func (c *Manager) MoveTo(destination *Manager) error {
|
||||
processes, err := c.Procs(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range processes {
|
||||
if err := destination.AddProc(p); err != nil {
|
||||
if strings.Contains(err.Error(), "no such process") {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var singleValueFiles = []string{
|
||||
"pids.current",
|
||||
"pids.max",
|
||||
|
|
@ -506,7 +632,7 @@ func readSingleFile(path string, file string, out map[string]interface{}) error
|
|||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
data, err := ioutil.ReadAll(f)
|
||||
data, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -709,7 +835,8 @@ func setDevices(path string, devices []specs.LinuxDeviceCgroup) error {
|
|||
// the reason this is necessary is because the "-" character has a special meaning in
|
||||
// systemd slice. For example, when creating a slice called "my-group-112233.slice",
|
||||
// systemd will create a hierarchy like this:
|
||||
// /sys/fs/cgroup/my.slice/my-group.slice/my-group-112233.slice
|
||||
//
|
||||
// /sys/fs/cgroup/my.slice/my-group.slice/my-group-112233.slice
|
||||
func getSystemdFullPath(slice, group string) string {
|
||||
return filepath.Join(defaultCgroup2Path, dashesToPath(slice), dashesToPath(group))
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
type Memory struct {
|
||||
Swap *int64
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import "strconv"
|
||||
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
|
@ -14,10 +14,10 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
|
@ -50,7 +50,7 @@ func (s State) Values() []Value {
|
|||
}
|
||||
|
||||
func fetchState(path string) (State, error) {
|
||||
current, err := ioutil.ReadFile(filepath.Join(path, cgroupFreeze))
|
||||
current, err := os.ReadFile(filepath.Join(path, cgroupFreeze))
|
||||
if err != nil {
|
||||
return Unknown, err
|
||||
}
|
||||
|
|
@ -14,4 +14,4 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
package stats
|
||||
1333
vendor/github.com/containerd/cgroups/v3/cgroup2/stats/metrics.pb.go
generated
vendored
Normal file
1333
vendor/github.com/containerd/cgroups/v3/cgroup2/stats/metrics.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,6 @@
|
|||
file {
|
||||
name: "github.com/containerd/cgroups/v2/stats/metrics.proto"
|
||||
name: "github.com/containerd/cgroups/cgroup2/stats/metrics.proto"
|
||||
package: "io.containerd.cgroups.v2"
|
||||
dependency: "gogoproto/gogo.proto"
|
||||
message_type {
|
||||
name: "Metrics"
|
||||
field {
|
||||
|
|
@ -18,9 +17,6 @@ file {
|
|||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: ".io.containerd.cgroups.v2.CPUStat"
|
||||
options {
|
||||
65004: "CPU"
|
||||
}
|
||||
json_name: "cpu"
|
||||
}
|
||||
field {
|
||||
|
|
@ -535,5 +531,8 @@ file {
|
|||
json_name: "pagesize"
|
||||
}
|
||||
}
|
||||
options {
|
||||
go_package: "github.com/containerd/cgroups/cgroup2/stats"
|
||||
}
|
||||
syntax: "proto3"
|
||||
}
|
||||
|
|
@ -2,11 +2,11 @@ syntax = "proto3";
|
|||
|
||||
package io.containerd.cgroups.v2;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
option go_package = "github.com/containerd/cgroups/cgroup2/stats";
|
||||
|
||||
message Metrics {
|
||||
PidsStat pids = 1;
|
||||
CPUStat cpu = 2 [(gogoproto.customname) = "CPU"];
|
||||
CPUStat cpu = 2;
|
||||
MemoryStat memory = 4;
|
||||
RdmaStat rdma = 5;
|
||||
IOStat io = 6;
|
||||
|
|
@ -14,29 +14,31 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v2
|
||||
package cgroup2
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/containerd/cgroups/v2/stats"
|
||||
"github.com/containerd/cgroups/v3/cgroup2/stats"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
cgroupProcs = "cgroup.procs"
|
||||
cgroupThreads = "cgroup.threads"
|
||||
defaultDirPerm = 0755
|
||||
)
|
||||
|
||||
|
|
@ -242,7 +244,7 @@ func ToResources(spec *specs.LinuxResources) *Resources {
|
|||
|
||||
// Gets uint64 parsed content of single value cgroup stat file
|
||||
func getStatFileContentUint64(filePath string) uint64 {
|
||||
contents, err := ioutil.ReadFile(filePath)
|
||||
contents, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
|
@ -264,7 +266,7 @@ func readIoStats(path string) []*stats.IOEntry {
|
|||
// more details on the io.stat file format: https://www.kernel.org/doc/Documentation/cgroup-v2.txt
|
||||
var usage []*stats.IOEntry
|
||||
fpath := filepath.Join(path, "io.stat")
|
||||
currentData, err := ioutil.ReadFile(fpath)
|
||||
currentData, err := os.ReadFile(fpath)
|
||||
if err != nil {
|
||||
return usage
|
||||
}
|
||||
|
|
@ -318,7 +320,7 @@ func readIoStats(path string) []*stats.IOEntry {
|
|||
}
|
||||
|
||||
func rdmaStats(filepath string) []*stats.RdmaEntry {
|
||||
currentData, err := ioutil.ReadFile(filepath)
|
||||
currentData, err := os.ReadFile(filepath)
|
||||
if err != nil {
|
||||
return []*stats.RdmaEntry{}
|
||||
}
|
||||
|
|
@ -406,7 +408,7 @@ func readHugeTlbStats(path string) []*stats.HugeTlbStat {
|
|||
hugeTlb = &stats.HugeTlbStat{}
|
||||
}
|
||||
hugeTlb.Pagesize = pageSize
|
||||
out, err := ioutil.ReadFile(filepath.Join(path, file.Name()))
|
||||
out, err := os.ReadFile(filepath.Join(path, file.Name()))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
|
@ -434,3 +436,11 @@ func readHugeTlbStats(path string) []*stats.HugeTlbStat {
|
|||
}
|
||||
return usage
|
||||
}
|
||||
|
||||
func getSubreaper() (int, error) {
|
||||
var i uintptr
|
||||
if err := unix.Prctl(unix.PR_GET_CHILD_SUBREAPER, uintptr(unsafe.Pointer(&i)), 0, 0, 0); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return int(i), nil
|
||||
}
|
||||
150
vendor/github.com/containerd/cgroups/v3/utils.go
generated
vendored
Normal file
150
vendor/github.com/containerd/cgroups/v3/utils.go
generated
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
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"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
nsOnce sync.Once
|
||||
inUserNS bool
|
||||
checkMode sync.Once
|
||||
cgMode CGMode
|
||||
)
|
||||
|
||||
const unifiedMountpoint = "/sys/fs/cgroup"
|
||||
|
||||
// CGMode is the cgroups mode of the host system
|
||||
type CGMode int
|
||||
|
||||
const (
|
||||
// Unavailable cgroup mountpoint
|
||||
Unavailable CGMode = iota
|
||||
// Legacy cgroups v1
|
||||
Legacy
|
||||
// Hybrid with cgroups v1 and v2 controllers mounted
|
||||
Hybrid
|
||||
// Unified with only cgroups v2 mounted
|
||||
Unified
|
||||
)
|
||||
|
||||
// Mode returns the cgroups mode running on the host
|
||||
func Mode() CGMode {
|
||||
checkMode.Do(func() {
|
||||
var st unix.Statfs_t
|
||||
if err := unix.Statfs(unifiedMountpoint, &st); err != nil {
|
||||
cgMode = Unavailable
|
||||
return
|
||||
}
|
||||
switch st.Type {
|
||||
case unix.CGROUP2_SUPER_MAGIC:
|
||||
cgMode = Unified
|
||||
default:
|
||||
cgMode = Legacy
|
||||
if err := unix.Statfs(filepath.Join(unifiedMountpoint, "unified"), &st); err != nil {
|
||||
return
|
||||
}
|
||||
if st.Type == unix.CGROUP2_SUPER_MAGIC {
|
||||
cgMode = Hybrid
|
||||
}
|
||||
}
|
||||
})
|
||||
return cgMode
|
||||
}
|
||||
|
||||
// RunningInUserNS detects whether we are currently running in a user namespace.
|
||||
// Copied from github.com/lxc/lxd/shared/util.go
|
||||
func RunningInUserNS() bool {
|
||||
nsOnce.Do(func() {
|
||||
file, err := os.Open("/proc/self/uid_map")
|
||||
if err != nil {
|
||||
// This kernel-provided file only exists if user namespaces are supported
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
buf := bufio.NewReader(file)
|
||||
l, _, err := buf.ReadLine()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
line := string(l)
|
||||
var a, b, c int64
|
||||
fmt.Sscanf(line, "%d %d %d", &a, &b, &c)
|
||||
|
||||
/*
|
||||
* We assume we are in the initial user namespace if we have a full
|
||||
* range - 4294967295 uids starting at uid 0.
|
||||
*/
|
||||
if a == 0 && b == 0 && c == 4294967295 {
|
||||
return
|
||||
}
|
||||
inUserNS = true
|
||||
})
|
||||
return inUserNS
|
||||
}
|
||||
|
||||
// ParseCgroupFileUnified returns legacy subsystem paths as the first value,
|
||||
// and returns the unified path as the second value.
|
||||
func ParseCgroupFileUnified(path string) (map[string]string, string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
defer f.Close()
|
||||
return ParseCgroupFromReaderUnified(f)
|
||||
}
|
||||
|
||||
// ParseCgroupFromReaderUnified returns legacy subsystem paths as the first value,
|
||||
// and returns the unified path as the second value.
|
||||
func ParseCgroupFromReaderUnified(r io.Reader) (map[string]string, string, error) {
|
||||
var (
|
||||
cgroups = make(map[string]string)
|
||||
unified = ""
|
||||
s = bufio.NewScanner(r)
|
||||
)
|
||||
for s.Scan() {
|
||||
var (
|
||||
text = s.Text()
|
||||
parts = strings.SplitN(text, ":", 3)
|
||||
)
|
||||
if len(parts) < 3 {
|
||||
return nil, unified, fmt.Errorf("invalid cgroup entry: %q", text)
|
||||
}
|
||||
for _, subs := range strings.Split(parts[1], ",") {
|
||||
if subs == "" {
|
||||
unified = parts[2]
|
||||
} else {
|
||||
cgroups[subs] = parts[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, unified, err
|
||||
}
|
||||
return cgroups, unified, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue