Use github.com/containerd/cgroups/v3 to remove gogo

Signed-off-by: Kazuyoshi Kato <katokazu@amazon.com>
This commit is contained in:
Kazuyoshi Kato 2022-11-11 17:54:24 +00:00
parent 135af6d9ab
commit 6596a70861
86 changed files with 4957 additions and 4399 deletions

3
go.mod
View File

@ -10,7 +10,7 @@ require (
github.com/container-orchestrated-devices/container-device-interface v0.5.1
github.com/containerd/aufs v1.0.0
github.com/containerd/btrfs v1.0.0
github.com/containerd/cgroups v1.0.5-0.20220816231112-7083cd60b721
github.com/containerd/cgroups/v3 v3.0.0-20221112182753-e8802a182774
github.com/containerd/console v1.0.3
github.com/containerd/continuity v0.3.0
github.com/containerd/fifo v1.0.0
@ -86,6 +86,7 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cilium/ebpf v0.9.1 // indirect
github.com/containerd/cgroups v1.0.5-0.20220816231112-7083cd60b721 // indirect
github.com/containers/ocicrypt v1.1.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.3 // indirect

2
go.sum
View File

@ -200,6 +200,8 @@ github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f2
github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
github.com/containerd/cgroups v1.0.5-0.20220816231112-7083cd60b721 h1:qWq0iv560E8jXZKwWipx3Xot0dYPyfKBeDNfRwYth/U=
github.com/containerd/cgroups v1.0.5-0.20220816231112-7083cd60b721/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/containerd/cgroups/v3 v3.0.0-20221112182753-e8802a182774 h1:Tej/o6wjJ3icV9qkPopNXJxk2oeVAmRc7JL0q5JeUq8=
github.com/containerd/cgroups/v3 v3.0.0-20221112182753-e8802a182774/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=

View File

@ -30,8 +30,9 @@ import (
"testing"
"time"
"github.com/containerd/cgroups"
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3"
"github.com/containerd/cgroups/v3/cgroup1"
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
. "github.com/containerd/containerd"
"github.com/containerd/containerd/cio"
"github.com/containerd/containerd/containers"
@ -93,7 +94,7 @@ func TestTaskUpdate(t *testing.T) {
}
var (
cgroup cgroups.Cgroup
cgroup cgroup1.Cgroup
cgroup2 *cgroupsv2.Manager
)
// check that the task has a limit of 32mb
@ -102,7 +103,7 @@ func TestTaskUpdate(t *testing.T) {
if err != nil {
t.Fatal(err)
}
cgroup2, err = cgroupsv2.LoadManager("/sys/fs/cgroup", groupPath)
cgroup2, err = cgroupsv2.Load(groupPath)
if err != nil {
t.Fatal(err)
}
@ -114,11 +115,11 @@ func TestTaskUpdate(t *testing.T) {
t.Fatalf("expected memory limit to be set to %d but received %d", limit, stat.Memory.UsageLimit)
}
} else {
cgroup, err = cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid())))
cgroup, err = cgroup1.Load(cgroup1.PidPath(int(task.Pid())))
if err != nil {
t.Fatal(err)
}
stat, err := cgroup.Stat(cgroups.IgnoreNotExist)
stat, err := cgroup.Stat(cgroup1.IgnoreNotExist)
if err != nil {
t.Fatal(err)
}
@ -144,7 +145,7 @@ func TestTaskUpdate(t *testing.T) {
t.Errorf("expected memory limit to be set to %d but received %d", limit, stat.Memory.UsageLimit)
}
} else {
stat, err := cgroup.Stat(cgroups.IgnoreNotExist)
stat, err := cgroup.Stat(cgroup1.IgnoreNotExist)
if err != nil {
t.Fatal(err)
}
@ -189,7 +190,7 @@ func TestShimInCgroup(t *testing.T) {
// create a cgroup for the shim to use
path := "/containerd/shim"
var (
cg cgroups.Cgroup
cg cgroup1.Cgroup
cg2 *cgroupsv2.Manager
)
if cgroups.Mode() == cgroups.Unified {
@ -199,7 +200,7 @@ func TestShimInCgroup(t *testing.T) {
}
defer cg2.Delete()
} else {
cg, err = cgroups.New(cgroups.V1, cgroups.StaticPath(path), &specs.LinuxResources{})
cg, err = cgroup1.New(cgroup1.StaticPath(path), &specs.LinuxResources{})
if err != nil {
t.Fatal(err)
}
@ -227,7 +228,7 @@ func TestShimInCgroup(t *testing.T) {
t.Errorf("created cgroup should have at least one process inside: %d", len(processes))
}
} else {
processes, err := cg.Processes(cgroups.Devices, false)
processes, err := cg.Processes(cgroup1.Devices, false)
if err != nil {
t.Fatal(err)
}
@ -1412,7 +1413,7 @@ func TestShimOOMScore(t *testing.T) {
path := "/containerd/oomshim"
var (
cg cgroups.Cgroup
cg cgroup1.Cgroup
cg2 *cgroupsv2.Manager
)
if cgroups.Mode() == cgroups.Unified {
@ -1422,7 +1423,7 @@ func TestShimOOMScore(t *testing.T) {
}
defer cg2.Delete()
} else {
cg, err = cgroups.New(cgroups.V1, cgroups.StaticPath(path), &specs.LinuxResources{})
cg, err = cgroup1.New(cgroup1.StaticPath(path), &specs.LinuxResources{})
if err != nil {
t.Fatal(err)
}
@ -1472,7 +1473,7 @@ func TestShimOOMScore(t *testing.T) {
}
}
} else {
processes, err := cg.Processes(cgroups.Devices, false)
processes, err := cg.Processes(cgroup1.Devices, false)
if err != nil {
t.Fatal(err)
}

View File

@ -26,7 +26,7 @@ import (
"testing"
"time"
"github.com/containerd/cgroups"
"github.com/containerd/cgroups/v3"
. "github.com/containerd/containerd"
"github.com/containerd/containerd/oci"
"github.com/containerd/containerd/plugin"

View File

@ -5,7 +5,7 @@ go 1.18
require (
github.com/Microsoft/hcsshim v0.10.0-rc.1
github.com/Microsoft/hcsshim/test v0.0.0-20210408205431-da33ecd607e1
github.com/containerd/cgroups v1.0.5-0.20220816231112-7083cd60b721
github.com/containerd/cgroups v1.0.5-0.20220816231112-7083cd60b721 // indirect
github.com/containerd/containerd v1.6.2 // see replace; the actual version of containerd is replaced with the code at the root of this repository
github.com/containerd/go-runc v1.0.0
github.com/containerd/ttrpc v1.1.1-0.20220420014843-944ef4a40df3
@ -19,7 +19,10 @@ require (
golang.org/x/sys v0.1.0
)
require github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8
require (
github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8
github.com/containerd/cgroups/v3 v3.0.0-20221112182753-e8802a182774
)
require (
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20220912195655-e1f97a00006b // indirect

View File

@ -466,6 +466,8 @@ github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f2
github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
github.com/containerd/cgroups v1.0.5-0.20220816231112-7083cd60b721 h1:qWq0iv560E8jXZKwWipx3Xot0dYPyfKBeDNfRwYth/U=
github.com/containerd/cgroups v1.0.5-0.20220816231112-7083cd60b721/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/containerd/cgroups/v3 v3.0.0-20221112182753-e8802a182774 h1:Tej/o6wjJ3icV9qkPopNXJxk2oeVAmRc7JL0q5JeUq8=
github.com/containerd/cgroups/v3 v3.0.0-20221112182753-e8802a182774/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw=
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=

View File

@ -26,8 +26,9 @@ import (
"strings"
"testing"
"github.com/containerd/cgroups"
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3"
"github.com/containerd/cgroups/v3/cgroup1"
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
"github.com/containerd/containerd"
"github.com/containerd/containerd/integration/images"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
@ -73,7 +74,7 @@ func getCgroupSwapLimitForTask(t *testing.T, task containerd.Task) uint64 {
if err != nil {
t.Fatal(err)
}
cgroup2, err := cgroupsv2.LoadManager("/sys/fs/cgroup", groupPath)
cgroup2, err := cgroupsv2.Load(groupPath)
if err != nil {
t.Fatal(err)
}
@ -83,11 +84,11 @@ func getCgroupSwapLimitForTask(t *testing.T, task containerd.Task) uint64 {
}
return stat.Memory.SwapLimit
}
cgroup, err := cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid())))
cgroup, err := cgroup1.Load(cgroup1.PidPath(int(task.Pid())))
if err != nil {
t.Fatal(err)
}
stat, err := cgroup.Stat(cgroups.IgnoreNotExist)
stat, err := cgroup.Stat(cgroup1.IgnoreNotExist)
if err != nil {
t.Fatal(err)
}
@ -100,7 +101,7 @@ func getCgroupMemoryLimitForTask(t *testing.T, task containerd.Task) uint64 {
if err != nil {
t.Fatal(err)
}
cgroup2, err := cgroupsv2.LoadManager("/sys/fs/cgroup", groupPath)
cgroup2, err := cgroupsv2.Load(groupPath)
if err != nil {
t.Fatal(err)
}
@ -111,11 +112,11 @@ func getCgroupMemoryLimitForTask(t *testing.T, task containerd.Task) uint64 {
return stat.Memory.UsageLimit
}
cgroup, err := cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid())))
cgroup, err := cgroup1.Load(cgroup1.PidPath(int(task.Pid())))
if err != nil {
t.Fatal(err)
}
stat, err := cgroup.Stat(cgroups.IgnoreNotExist)
stat, err := cgroup.Stat(cgroup1.IgnoreNotExist)
if err != nil {
t.Fatal(err)
}

View File

@ -20,7 +20,7 @@
package cgroups
import (
"github.com/containerd/cgroups"
"github.com/containerd/cgroups/v3"
"github.com/containerd/containerd/events"
v1 "github.com/containerd/containerd/metrics/cgroups/v1"
v2 "github.com/containerd/containerd/metrics/cgroups/v2"

View File

@ -26,7 +26,7 @@ import (
"testing"
"time"
"github.com/containerd/cgroups"
"github.com/containerd/cgroups/v3"
"github.com/containerd/containerd/metrics/cgroups/common"
v1 "github.com/containerd/containerd/metrics/cgroups/v1"
v2 "github.com/containerd/containerd/metrics/cgroups/v2"

View File

@ -22,7 +22,7 @@ package v1
import (
"context"
"github.com/containerd/cgroups"
cgroups "github.com/containerd/cgroups/v3/cgroup1"
eventstypes "github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/events"

View File

@ -24,7 +24,7 @@ import (
"fmt"
"sync"
"github.com/containerd/cgroups"
cgroups "github.com/containerd/cgroups/v3/cgroup1"
"github.com/containerd/containerd/log"
cmetrics "github.com/containerd/containerd/metrics"
"github.com/containerd/containerd/metrics/cgroups/common"

View File

@ -25,7 +25,7 @@ import (
"golang.org/x/sys/unix"
"github.com/containerd/cgroups"
cgroups "github.com/containerd/cgroups/v3/cgroup1"
metrics "github.com/docker/go-metrics"
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"

View File

@ -20,7 +20,7 @@
package v1
import (
v1 "github.com/containerd/cgroups/stats/v1"
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
)
type (

View File

@ -20,7 +20,7 @@
package v2
import (
v2 "github.com/containerd/cgroups/v2/stats"
v2 "github.com/containerd/cgroups/v3/cgroup2/stats"
)
type (

View File

@ -25,7 +25,7 @@ import (
"strconv"
"strings"
"github.com/containerd/cgroups"
"github.com/containerd/cgroups/v3"
"github.com/containerd/containerd/contrib/apparmor"
"github.com/containerd/containerd/contrib/seccomp"
"github.com/containerd/containerd/oci"

View File

@ -21,8 +21,8 @@ import (
"testing"
"time"
v1 "github.com/containerd/cgroups/stats/v1"
v2 "github.com/containerd/cgroups/v2/stats"
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
v2 "github.com/containerd/cgroups/v3/cgroup2/stats"
containerstore "github.com/containerd/containerd/pkg/cri/store/container"
"github.com/stretchr/testify/assert"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"

View File

@ -24,8 +24,9 @@ import (
"github.com/containernetworking/plugins/pkg/ns"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
"github.com/containerd/cgroups"
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3"
"github.com/containerd/cgroups/v3/cgroup1"
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
"github.com/vishvananda/netlink"
@ -151,7 +152,7 @@ func metricsForSandbox(sandbox sandboxstore.Sandbox) (interface{}, error) {
var statsx interface{}
if cgroups.Mode() == cgroups.Unified {
cg, err := cgroupsv2.LoadManager("/sys/fs/cgroup", cgroupPath)
cg, err := cgroupsv2.Load(cgroupPath)
if err != nil {
return nil, fmt.Errorf("failed to load sandbox cgroup: %v: %w", cgroupPath, err)
}
@ -162,11 +163,11 @@ func metricsForSandbox(sandbox sandboxstore.Sandbox) (interface{}, error) {
statsx = stats
} else {
control, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(cgroupPath))
control, err := cgroup1.Load(cgroup1.StaticPath(cgroupPath))
if err != nil {
return nil, fmt.Errorf("failed to load sandbox cgroup %v: %w", cgroupPath, err)
}
stats, err := control.Stat(cgroups.IgnoreNotExist)
stats, err := control.Stat(cgroup1.IgnoreNotExist)
if err != nil {
return nil, fmt.Errorf("failed to get stats for cgroup %v: %w", cgroupPath, err)
}

View File

@ -25,7 +25,7 @@ import (
"strconv"
"strings"
"github.com/containerd/cgroups"
"github.com/containerd/cgroups/v3"
"github.com/containerd/containerd/contrib/apparmor"
"github.com/containerd/containerd/contrib/seccomp"
"github.com/containerd/containerd/oci"

View File

@ -21,8 +21,8 @@ import (
"testing"
"time"
v1 "github.com/containerd/cgroups/stats/v1"
v2 "github.com/containerd/cgroups/v2/stats"
v1 "github.com/containerd/cgroups/v3/cgroup1/stats"
v2 "github.com/containerd/cgroups/v3/cgroup2/stats"
"github.com/stretchr/testify/assert"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
)

View File

@ -24,8 +24,9 @@ import (
"github.com/containernetworking/plugins/pkg/ns"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
"github.com/containerd/cgroups"
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3"
"github.com/containerd/cgroups/v3/cgroup1"
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
"github.com/vishvananda/netlink"
@ -151,7 +152,7 @@ func metricsForSandbox(sandbox sandboxstore.Sandbox) (interface{}, error) {
var statsx interface{}
if cgroups.Mode() == cgroups.Unified {
cg, err := cgroupsv2.LoadManager("/sys/fs/cgroup", cgroupPath)
cg, err := cgroupsv2.Load(cgroupPath)
if err != nil {
return nil, fmt.Errorf("failed to load sandbox cgroup: %v: %w", cgroupPath, err)
}
@ -162,11 +163,11 @@ func metricsForSandbox(sandbox sandboxstore.Sandbox) (interface{}, error) {
statsx = stats
} else {
control, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(cgroupPath))
control, err := cgroup1.Load(cgroup1.StaticPath(cgroupPath))
if err != nil {
return nil, fmt.Errorf("failed to load sandbox cgroup %v: %w", cgroupPath, err)
}
stats, err := control.Stat(cgroups.IgnoreNotExist)
stats, err := control.Stat(cgroup1.IgnoreNotExist)
if err != nil {
return nil, fmt.Errorf("failed to get stats for cgroup %v: %w", cgroupPath, err)
}

View File

@ -24,7 +24,7 @@ import (
"fmt"
"sync"
"github.com/containerd/cgroups"
"github.com/containerd/cgroups/v3/cgroup1"
eventstypes "github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/pkg/oom"
"github.com/containerd/containerd/runtime"
@ -58,7 +58,7 @@ type epoller struct {
type item struct {
id string
cg cgroups.Cgroup
cg cgroup1.Cgroup
}
// Close the epoll fd
@ -91,7 +91,7 @@ func (e *epoller) Run(ctx context.Context) {
// Add cgroups.Cgroup to the epoll monitor
func (e *epoller) Add(id string, cgx interface{}) error {
cg, ok := cgx.(cgroups.Cgroup)
cg, ok := cgx.(cgroup1.Cgroup)
if !ok {
return fmt.Errorf("expected cgroups.Cgroup, got: %T", cgx)
}
@ -121,7 +121,7 @@ func (e *epoller) process(ctx context.Context, fd uintptr) {
return
}
e.mu.Unlock()
if i.cg.State() == cgroups.Deleted {
if i.cg.State() == cgroup1.Deleted {
e.mu.Lock()
delete(e.set, fd)
e.mu.Unlock()

View File

@ -23,7 +23,7 @@ import (
"context"
"fmt"
cgroupsv2 "github.com/containerd/cgroups/v2"
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
eventstypes "github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/pkg/oom"
"github.com/containerd/containerd/runtime"

View File

@ -19,23 +19,24 @@ package opts
import (
"context"
"github.com/containerd/cgroups"
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3"
cgroup1 "github.com/containerd/cgroups/v3/cgroup1"
cgroup2 "github.com/containerd/cgroups/v3/cgroup2"
"github.com/containerd/containerd/namespaces"
)
// WithNamespaceCgroupDeletion removes the cgroup directory that was created for the namespace
func WithNamespaceCgroupDeletion(ctx context.Context, i *namespaces.DeleteInfo) error {
if cgroups.Mode() == cgroups.Unified {
cg, err := cgroupsv2.LoadManager("/sys/fs/cgroup", i.Name)
cg, err := cgroup2.Load(i.Name)
if err != nil {
return err
}
return cg.Delete()
}
cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(i.Name))
cg, err := cgroup1.Load(cgroup1.StaticPath(i.Name))
if err != nil {
if err == cgroups.ErrCgroupDeleted {
if err == cgroup1.ErrCgroupDeleted {
return nil
}
return err

View File

@ -25,7 +25,7 @@ import (
"fmt"
"sync"
"github.com/containerd/cgroups"
cgroups "github.com/containerd/cgroups/v3/cgroup1"
eventstypes "github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/events/exchange"
@ -58,7 +58,7 @@ func newTask(id, namespace string, pid int, shim *client.Client, events *exchang
cg cgroups.Cgroup
)
if pid > 0 {
cg, err = cgroups.Load(cgroups.V1, cgroups.PidPath(pid))
cg, err = cgroups.Load(cgroups.PidPath(pid))
if err != nil && err != cgroups.ErrCgroupDeleted {
return nil, err
}
@ -135,7 +135,7 @@ func (t *Task) Start(ctx context.Context) error {
}
t.pid = int(r.Pid)
if !hasCgroup {
cg, err := cgroups.Load(cgroups.V1, cgroups.PidPath(t.pid))
cg, err := cgroups.Load(cgroups.PidPath(t.pid))
if err != nil && err != cgroups.ErrCgroupDeleted {
return err
}

View File

@ -20,7 +20,7 @@ import (
"fmt"
"syscall"
"github.com/containerd/cgroups"
"github.com/containerd/cgroups/v3/cgroup1"
exec "golang.org/x/sys/execabs"
)
@ -31,7 +31,7 @@ func getSysProcAttr() *syscall.SysProcAttr {
}
func setCgroup(cgroupPath string, cmd *exec.Cmd) error {
cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(cgroupPath))
cg, err := cgroup1.Load(cgroup1.StaticPath(cgroupPath))
if err != nil {
return fmt.Errorf("failed to load cgroup %s: %w", cgroupPath, err)
}

View File

@ -27,8 +27,9 @@ import (
"path/filepath"
"sync"
"github.com/containerd/cgroups"
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3"
"github.com/containerd/cgroups/v3/cgroup1"
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
"github.com/containerd/console"
"github.com/containerd/containerd/api/runtime/task/v2"
"github.com/containerd/containerd/errdefs"
@ -148,12 +149,12 @@ func NewContainer(ctx context.Context, platform stdio.Platform, r *task.CreateTa
logrus.WithError(err).Errorf("loading cgroup2 for %d", pid)
return container, nil
}
cg, err = cgroupsv2.LoadManager("/sys/fs/cgroup", g)
cg, err = cgroupsv2.Load(g)
if err != nil {
logrus.WithError(err).Errorf("loading cgroup2 for %d", pid)
}
} else {
cg, err = cgroups.Load(cgroups.V1, cgroups.PidPath(pid))
cg, err = cgroup1.Load(cgroup1.PidPath(pid))
if err != nil {
logrus.WithError(err).Errorf("loading cgroup for %d", pid)
}
@ -368,12 +369,12 @@ func (c *Container) Start(ctx context.Context, r *task.StartRequest) (process.Pr
if err != nil {
logrus.WithError(err).Errorf("loading cgroup2 for %d", p.Pid())
}
cg, err = cgroupsv2.LoadManager("/sys/fs/cgroup", g)
cg, err = cgroupsv2.Load(g)
if err != nil {
logrus.WithError(err).Errorf("loading cgroup2 for %d", p.Pid())
}
} else {
cg, err = cgroups.Load(cgroups.V1, cgroups.PidPath(p.Pid()))
cg, err = cgroup1.Load(cgroup1.PidPath(p.Pid()))
if err != nil {
logrus.WithError(err).Errorf("loading cgroup for %d", p.Pid())
}

View File

@ -27,8 +27,9 @@ import (
"syscall"
"time"
"github.com/containerd/cgroups"
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3"
"github.com/containerd/cgroups/v3/cgroup1"
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/namespaces"
@ -212,7 +213,7 @@ func (manager) Start(ctx context.Context, id string, opts shim.StartOpts) (_ str
if opts, ok := v.(*options.Options); ok {
if opts.ShimCgroup != "" {
if cgroups.Mode() == cgroups.Unified {
cg, err := cgroupsv2.LoadManager("/sys/fs/cgroup", opts.ShimCgroup)
cg, err := cgroupsv2.Load(opts.ShimCgroup)
if err != nil {
return "", fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err)
}
@ -220,7 +221,7 @@ func (manager) Start(ctx context.Context, id string, opts shim.StartOpts) (_ str
return "", fmt.Errorf("failed to join cgroup %s: %w", opts.ShimCgroup, err)
}
} else {
cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(opts.ShimCgroup))
cg, err := cgroup1.Load(cgroup1.StaticPath(opts.ShimCgroup))
if err != nil {
return "", fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err)
}

View File

@ -25,8 +25,9 @@ import (
"os"
"sync"
"github.com/containerd/cgroups"
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3"
"github.com/containerd/cgroups/v3/cgroup1"
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
eventstypes "github.com/containerd/containerd/api/events"
taskAPI "github.com/containerd/containerd/api/runtime/task/v2"
"github.com/containerd/containerd/api/types/task"
@ -168,7 +169,7 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.
switch r.ExecID {
case "":
switch cg := container.Cgroup().(type) {
case cgroups.Cgroup:
case cgroup1.Cgroup:
if err := s.ep.Add(container.ID, cg); err != nil {
logrus.WithError(err).Error("add cg to OOM monitor")
}
@ -483,8 +484,8 @@ func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.
}
var statsx interface{}
switch cg := cgx.(type) {
case cgroups.Cgroup:
stats, err := cg.Stat(cgroups.IgnoreNotExist)
case cgroup1.Cgroup:
stats, err := cg.Stat(cgroup1.IgnoreNotExist)
if err != nil {
return nil, err
}

View File

@ -30,7 +30,7 @@ import (
"syscall"
"time"
"github.com/containerd/cgroups"
"github.com/containerd/cgroups/v3/cgroup1"
eventstypes "github.com/containerd/containerd/api/events"
taskAPI "github.com/containerd/containerd/api/runtime/task/v2"
"github.com/containerd/containerd/api/types/task"
@ -204,7 +204,7 @@ func (s *service) StartShim(ctx context.Context, opts shim.StartOpts) (_ string,
}
if opts, ok := v.(*options.Options); ok {
if opts.ShimCgroup != "" {
cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(opts.ShimCgroup))
cg, err := cgroup1.Load(cgroup1.StaticPath(opts.ShimCgroup))
if err != nil {
return "", fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err)
}
@ -318,7 +318,7 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.
}
switch r.ExecID {
case "":
if cg, ok := container.Cgroup().(cgroups.Cgroup); ok {
if cg, ok := container.Cgroup().(cgroup1.Cgroup); ok {
if err := s.ep.Add(container.ID, cg); err != nil {
logrus.WithError(err).Error("add cg to OOM monitor")
}
@ -604,14 +604,14 @@ func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.
if cgx == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "cgroup does not exist")
}
cg, ok := cgx.(cgroups.Cgroup)
cg, ok := cgx.(cgroup1.Cgroup)
if !ok {
return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "cgroup v2 not implemented for Stats")
}
if cg == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "cgroup does not exist")
}
stats, err := cg.Stat(cgroups.IgnoreNotExist)
stats, err := cg.Stat(cgroup1.IgnoreNotExist)
if err != nil {
return nil, err
}

View File

@ -20,8 +20,9 @@ import (
"context"
"os"
"github.com/containerd/cgroups"
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3"
cgroup1 "github.com/containerd/cgroups/v3/cgroup1"
cgroupsv2 "github.com/containerd/cgroups/v3/cgroup2"
"github.com/containerd/containerd/log"
srvconfig "github.com/containerd/containerd/services/server/config"
"github.com/containerd/containerd/sys"
@ -39,7 +40,7 @@ func apply(ctx context.Context, config *srvconfig.Config) error {
}
if config.Cgroup.Path != "" {
if cgroups.Mode() == cgroups.Unified {
cg, err := cgroupsv2.LoadManager("/sys/fs/cgroup", config.Cgroup.Path)
cg, err := cgroupsv2.Load(config.Cgroup.Path)
if err != nil {
return err
}
@ -47,12 +48,12 @@ func apply(ctx context.Context, config *srvconfig.Config) error {
return err
}
} else {
cg, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(config.Cgroup.Path))
cg, err := cgroup1.Load(cgroup1.StaticPath(config.Cgroup.Path))
if err != nil {
if err != cgroups.ErrCgroupDeleted {
if err != cgroup1.ErrCgroupDeleted {
return err
}
if cg, err = cgroups.New(cgroups.V1, cgroups.StaticPath(config.Cgroup.Path), &specs.LinuxResources{}); err != nil {
if cg, err = cgroup1.New(cgroup1.StaticPath(config.Cgroup.Path), &specs.LinuxResources{}); err != nil {
return err
}
}

View File

@ -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"
]

File diff suppressed because it is too large Load Diff

201
vendor/github.com/containerd/cgroups/v3/LICENSE generated vendored Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -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')

View 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"

View File

@ -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,13 +48,13 @@ 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 {
}
```
@ -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,19 +117,19 @@ 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)
```
@ -153,14 +153,14 @@ so the resulting slice would be located here on disk:
```go
import (
cgroupsv2 "github.com/containerd/cgroups/v2"
"github.com/containerd/cgroups/v3/cgroup2"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
res := cgroupsv2.Resources{}
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 := cgroupsv2.NewSystemd("/", "my-cgroup-abc.slice", -1, &res)
m, err := cgroup2.NewSystemd("/", "my-cgroup-abc.slice", -1, &res)
if err != nil {
return err
}
@ -169,7 +169,7 @@ if err != nil {
### Load an existing cgroup
```go
m, err := cgroupsv2.LoadSystemd("/", "my-cgroup-abc.slice")
m, err := cgroup2.LoadSystemd("/", "my-cgroup-abc.slice")
if err != nil {
return err
}
@ -178,7 +178,7 @@ if err != nil {
### Delete a cgroup
```go
m, err := cgroupsv2.LoadSystemd("/", "my-cgroup-abc.slice")
m, err := cgroup2.LoadSystemd("/", "my-cgroup-abc.slice")
if err != nil {
return err
}

View File

@ -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,

View File

@ -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 {

View File

@ -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"
)

View File

@ -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,

View File

@ -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
}

View File

@ -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,

View File

@ -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,

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package cgroups
package cgroup1
import (
"errors"

View File

@ -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
}

View File

@ -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)

View File

@ -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,

View File

@ -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"
)
@ -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
}

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package cgroups
package cgroup1
import "path/filepath"

View File

@ -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,

View File

@ -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,

View File

@ -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
}
}

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package cgroups
package cgroup1
import (
"errors"

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package cgroups
package cgroup1
import "path/filepath"

View File

@ -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
}

View File

@ -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
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,771 @@
file {
name: "github.com/containerd/cgroups/cgroup1/stats/metrics.proto"
package: "io.containerd.cgroups.v1"
message_type {
name: "Metrics"
field {
name: "hugetlb"
number: 1
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.HugetlbStat"
json_name: "hugetlb"
}
field {
name: "pids"
number: 2
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.PidsStat"
json_name: "pids"
}
field {
name: "cpu"
number: 3
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.CPUStat"
json_name: "cpu"
}
field {
name: "memory"
number: 4
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.MemoryStat"
json_name: "memory"
}
field {
name: "blkio"
number: 5
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.BlkIOStat"
json_name: "blkio"
}
field {
name: "rdma"
number: 6
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.RdmaStat"
json_name: "rdma"
}
field {
name: "network"
number: 7
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.NetworkStat"
json_name: "network"
}
field {
name: "cgroup_stats"
number: 8
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.CgroupStats"
json_name: "cgroupStats"
}
field {
name: "memory_oom_control"
number: 9
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.MemoryOomControl"
json_name: "memoryOomControl"
}
}
message_type {
name: "HugetlbStat"
field {
name: "usage"
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "usage"
}
field {
name: "max"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "max"
}
field {
name: "failcnt"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "failcnt"
}
field {
name: "pagesize"
number: 4
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "pagesize"
}
}
message_type {
name: "PidsStat"
field {
name: "current"
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "current"
}
field {
name: "limit"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "limit"
}
}
message_type {
name: "CPUStat"
field {
name: "usage"
number: 1
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.CPUUsage"
json_name: "usage"
}
field {
name: "throttling"
number: 2
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.Throttle"
json_name: "throttling"
}
}
message_type {
name: "CPUUsage"
field {
name: "total"
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "total"
}
field {
name: "kernel"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "kernel"
}
field {
name: "user"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "user"
}
field {
name: "per_cpu"
number: 4
label: LABEL_REPEATED
type: TYPE_UINT64
json_name: "perCpu"
}
}
message_type {
name: "Throttle"
field {
name: "periods"
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "periods"
}
field {
name: "throttled_periods"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "throttledPeriods"
}
field {
name: "throttled_time"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "throttledTime"
}
}
message_type {
name: "MemoryStat"
field {
name: "cache"
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "cache"
}
field {
name: "rss"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "rss"
}
field {
name: "rss_huge"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "rssHuge"
}
field {
name: "mapped_file"
number: 4
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "mappedFile"
}
field {
name: "dirty"
number: 5
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "dirty"
}
field {
name: "writeback"
number: 6
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "writeback"
}
field {
name: "pg_pg_in"
number: 7
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "pgPgIn"
}
field {
name: "pg_pg_out"
number: 8
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "pgPgOut"
}
field {
name: "pg_fault"
number: 9
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "pgFault"
}
field {
name: "pg_maj_fault"
number: 10
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "pgMajFault"
}
field {
name: "inactive_anon"
number: 11
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "inactiveAnon"
}
field {
name: "active_anon"
number: 12
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "activeAnon"
}
field {
name: "inactive_file"
number: 13
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "inactiveFile"
}
field {
name: "active_file"
number: 14
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "activeFile"
}
field {
name: "unevictable"
number: 15
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "unevictable"
}
field {
name: "hierarchical_memory_limit"
number: 16
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "hierarchicalMemoryLimit"
}
field {
name: "hierarchical_swap_limit"
number: 17
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "hierarchicalSwapLimit"
}
field {
name: "total_cache"
number: 18
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalCache"
}
field {
name: "total_rss"
number: 19
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalRss"
}
field {
name: "total_rss_huge"
number: 20
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalRssHuge"
}
field {
name: "total_mapped_file"
number: 21
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalMappedFile"
}
field {
name: "total_dirty"
number: 22
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalDirty"
}
field {
name: "total_writeback"
number: 23
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalWriteback"
}
field {
name: "total_pg_pg_in"
number: 24
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalPgPgIn"
}
field {
name: "total_pg_pg_out"
number: 25
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalPgPgOut"
}
field {
name: "total_pg_fault"
number: 26
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalPgFault"
}
field {
name: "total_pg_maj_fault"
number: 27
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalPgMajFault"
}
field {
name: "total_inactive_anon"
number: 28
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalInactiveAnon"
}
field {
name: "total_active_anon"
number: 29
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalActiveAnon"
}
field {
name: "total_inactive_file"
number: 30
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalInactiveFile"
}
field {
name: "total_active_file"
number: 31
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalActiveFile"
}
field {
name: "total_unevictable"
number: 32
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "totalUnevictable"
}
field {
name: "usage"
number: 33
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.MemoryEntry"
json_name: "usage"
}
field {
name: "swap"
number: 34
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.MemoryEntry"
json_name: "swap"
}
field {
name: "kernel"
number: 35
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.MemoryEntry"
json_name: "kernel"
}
field {
name: "kernel_tcp"
number: 36
label: LABEL_OPTIONAL
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.MemoryEntry"
json_name: "kernelTcp"
}
}
message_type {
name: "MemoryEntry"
field {
name: "limit"
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "limit"
}
field {
name: "usage"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "usage"
}
field {
name: "max"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "max"
}
field {
name: "failcnt"
number: 4
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "failcnt"
}
}
message_type {
name: "MemoryOomControl"
field {
name: "oom_kill_disable"
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "oomKillDisable"
}
field {
name: "under_oom"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "underOom"
}
field {
name: "oom_kill"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "oomKill"
}
}
message_type {
name: "BlkIOStat"
field {
name: "io_service_bytes_recursive"
number: 1
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.BlkIOEntry"
json_name: "ioServiceBytesRecursive"
}
field {
name: "io_serviced_recursive"
number: 2
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.BlkIOEntry"
json_name: "ioServicedRecursive"
}
field {
name: "io_queued_recursive"
number: 3
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.BlkIOEntry"
json_name: "ioQueuedRecursive"
}
field {
name: "io_service_time_recursive"
number: 4
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.BlkIOEntry"
json_name: "ioServiceTimeRecursive"
}
field {
name: "io_wait_time_recursive"
number: 5
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.BlkIOEntry"
json_name: "ioWaitTimeRecursive"
}
field {
name: "io_merged_recursive"
number: 6
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.BlkIOEntry"
json_name: "ioMergedRecursive"
}
field {
name: "io_time_recursive"
number: 7
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.BlkIOEntry"
json_name: "ioTimeRecursive"
}
field {
name: "sectors_recursive"
number: 8
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.BlkIOEntry"
json_name: "sectorsRecursive"
}
}
message_type {
name: "BlkIOEntry"
field {
name: "op"
number: 1
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "op"
}
field {
name: "device"
number: 2
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "device"
}
field {
name: "major"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "major"
}
field {
name: "minor"
number: 4
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "minor"
}
field {
name: "value"
number: 5
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "value"
}
}
message_type {
name: "RdmaStat"
field {
name: "current"
number: 1
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.RdmaEntry"
json_name: "current"
}
field {
name: "limit"
number: 2
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".io.containerd.cgroups.v1.RdmaEntry"
json_name: "limit"
}
}
message_type {
name: "RdmaEntry"
field {
name: "device"
number: 1
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "device"
}
field {
name: "hca_handles"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT32
json_name: "hcaHandles"
}
field {
name: "hca_objects"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT32
json_name: "hcaObjects"
}
}
message_type {
name: "NetworkStat"
field {
name: "name"
number: 1
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "name"
}
field {
name: "rx_bytes"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "rxBytes"
}
field {
name: "rx_packets"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "rxPackets"
}
field {
name: "rx_errors"
number: 4
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "rxErrors"
}
field {
name: "rx_dropped"
number: 5
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "rxDropped"
}
field {
name: "tx_bytes"
number: 6
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "txBytes"
}
field {
name: "tx_packets"
number: 7
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "txPackets"
}
field {
name: "tx_errors"
number: 8
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "txErrors"
}
field {
name: "tx_dropped"
number: 9
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "txDropped"
}
}
message_type {
name: "CgroupStats"
field {
name: "nr_sleeping"
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "nrSleeping"
}
field {
name: "nr_running"
number: 2
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "nrRunning"
}
field {
name: "nr_stopped"
number: 3
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "nrStopped"
}
field {
name: "nr_uninterruptible"
number: 4
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "nrUninterruptible"
}
field {
name: "nr_io_wait"
number: 5
label: LABEL_OPTIONAL
type: TYPE_UINT64
json_name: "nrIoWait"
}
}
options {
go_package: "github.com/containerd/cgroups/cgroup1/stats"
}
syntax: "proto3"
}

View File

@ -0,0 +1,158 @@
syntax = "proto3";
package io.containerd.cgroups.v1;
option go_package = "github.com/containerd/cgroups/cgroup1/stats";
message Metrics {
repeated HugetlbStat hugetlb = 1;
PidsStat pids = 2;
CPUStat cpu = 3;
MemoryStat memory = 4;
BlkIOStat blkio = 5;
RdmaStat rdma = 6;
repeated NetworkStat network = 7;
CgroupStats cgroup_stats = 8;
MemoryOomControl memory_oom_control = 9;
}
message HugetlbStat {
uint64 usage = 1;
uint64 max = 2;
uint64 failcnt = 3;
string pagesize = 4;
}
message PidsStat {
uint64 current = 1;
uint64 limit = 2;
}
message CPUStat {
CPUUsage usage = 1;
Throttle throttling = 2;
}
message CPUUsage {
// values in nanoseconds
uint64 total = 1;
uint64 kernel = 2;
uint64 user = 3;
repeated uint64 per_cpu = 4;
}
message Throttle {
uint64 periods = 1;
uint64 throttled_periods = 2;
uint64 throttled_time = 3;
}
message MemoryStat {
uint64 cache = 1;
uint64 rss = 2;
uint64 rss_huge = 3;
uint64 mapped_file = 4;
uint64 dirty = 5;
uint64 writeback = 6;
uint64 pg_pg_in = 7;
uint64 pg_pg_out = 8;
uint64 pg_fault = 9;
uint64 pg_maj_fault = 10;
uint64 inactive_anon = 11;
uint64 active_anon = 12;
uint64 inactive_file = 13;
uint64 active_file = 14;
uint64 unevictable = 15;
uint64 hierarchical_memory_limit = 16;
uint64 hierarchical_swap_limit = 17;
uint64 total_cache = 18;
uint64 total_rss = 19;
uint64 total_rss_huge = 20;
uint64 total_mapped_file = 21;
uint64 total_dirty = 22;
uint64 total_writeback = 23;
uint64 total_pg_pg_in = 24;
uint64 total_pg_pg_out = 25;
uint64 total_pg_fault = 26;
uint64 total_pg_maj_fault = 27;
uint64 total_inactive_anon = 28;
uint64 total_active_anon = 29;
uint64 total_inactive_file = 30;
uint64 total_active_file = 31;
uint64 total_unevictable = 32;
MemoryEntry usage = 33;
MemoryEntry swap = 34;
MemoryEntry kernel = 35;
MemoryEntry kernel_tcp = 36;
}
message MemoryEntry {
uint64 limit = 1;
uint64 usage = 2;
uint64 max = 3;
uint64 failcnt = 4;
}
message MemoryOomControl {
uint64 oom_kill_disable = 1;
uint64 under_oom = 2;
uint64 oom_kill = 3;
}
message BlkIOStat {
repeated BlkIOEntry io_service_bytes_recursive = 1;
repeated BlkIOEntry io_serviced_recursive = 2;
repeated BlkIOEntry io_queued_recursive = 3;
repeated BlkIOEntry io_service_time_recursive = 4;
repeated BlkIOEntry io_wait_time_recursive = 5;
repeated BlkIOEntry io_merged_recursive = 6;
repeated BlkIOEntry io_time_recursive = 7;
repeated BlkIOEntry sectors_recursive = 8;
}
message BlkIOEntry {
string op = 1;
string device = 2;
uint64 major = 3;
uint64 minor = 4;
uint64 value = 5;
}
message RdmaStat {
repeated RdmaEntry current = 1;
repeated RdmaEntry limit = 2;
}
message RdmaEntry {
string device = 1;
uint32 hca_handles = 2;
uint32 hca_objects = 3;
}
message NetworkStat {
string name = 1;
uint64 rx_bytes = 2;
uint64 rx_packets = 3;
uint64 rx_errors = 4;
uint64 rx_dropped = 5;
uint64 tx_bytes = 6;
uint64 tx_packets = 7;
uint64 tx_errors = 8;
uint64 tx_dropped = 9;
}
// CgroupStats exports per-cgroup statistics.
message CgroupStats {
// number of tasks sleeping
uint64 nr_sleeping = 1;
// number of tasks running
uint64 nr_running = 2;
// number of tasks in stopped state
uint64 nr_stopped = 3;
// number of tasks in uninterruptible state
uint64 nr_uninterruptible = 4;
// number of tasks waiting on IO
uint64 nr_io_wait = 5;
}

View File

@ -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 {

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package cgroups
package cgroup1
import (
"context"

View File

@ -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

View File

@ -14,107 +14,23 @@
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 +53,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 +116,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 +132,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,8 +173,10 @@ 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.
@ -377,16 +295,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
}
}
}

View File

@ -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

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package v2
package cgroup2
import (
"math"

View File

@ -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"

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package v2
package cgroup2
import (
"fmt"

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package v2
package cgroup2
import (
"errors"

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package v2
package cgroup2
import "strings"

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package v2
package cgroup2
import "fmt"

View File

@ -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"
@ -147,7 +147,7 @@ func (c *Value) write(path string, perm os.FileMode) error {
// Retry writes on EINTR; see:
// https://github.com/golang/go/issues/38033
for {
err := ioutil.WriteFile(
err := os.WriteFile(
filepath.Join(path, c.filename),
data,
perm,
@ -196,13 +196,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 deault 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 +247,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 +255,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 +358,23 @@ 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})
}
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)
}
@ -522,7 +560,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
}

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package v2
package cgroup2
type Memory struct {
Swap *int64

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package v2
package cgroup2
import (
"fmt"

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package v2
package cgroup2
import "strconv"

View File

@ -14,7 +14,7 @@
limitations under the License.
*/
package v2
package cgroup2
import (
"fmt"

View File

@ -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
}

View File

@ -0,0 +1,17 @@
/*
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 stats

File diff suppressed because it is too large Load Diff

View File

@ -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"
}

View File

@ -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;

View File

@ -14,13 +14,12 @@
limitations under the License.
*/
package v2
package cgroup2
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"math"
"os"
"path/filepath"
@ -28,7 +27,7 @@ import (
"strings"
"time"
"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"
@ -37,6 +36,7 @@ import (
const (
cgroupProcs = "cgroup.procs"
cgroupThreads = "cgroup.threads"
defaultDirPerm = 0755
)
@ -242,7 +242,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 +264,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 +318,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 +406,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
}

107
vendor/github.com/containerd/cgroups/v3/utils.go generated vendored Normal file
View File

@ -0,0 +1,107 @@
/*
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"
"os"
"path/filepath"
"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
}

10
vendor/modules.txt vendored
View File

@ -93,10 +93,14 @@ github.com/containerd/aufs/plugin
github.com/containerd/btrfs
# github.com/containerd/cgroups v1.0.5-0.20220816231112-7083cd60b721
## explicit; go 1.17
github.com/containerd/cgroups
github.com/containerd/cgroups/stats/v1
github.com/containerd/cgroups/v2
github.com/containerd/cgroups/v2/stats
# github.com/containerd/cgroups/v3 v3.0.0-20221112182753-e8802a182774
## explicit; go 1.17
github.com/containerd/cgroups/v3
github.com/containerd/cgroups/v3/cgroup1
github.com/containerd/cgroups/v3/cgroup1/stats
github.com/containerd/cgroups/v3/cgroup2
github.com/containerd/cgroups/v3/cgroup2/stats
# github.com/containerd/console v1.0.3
## explicit; go 1.13
github.com/containerd/console