mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 02:08:13 +00:00 
			
		
		
		
	Copy ParseCgroupFileUnified and Drop rest of containerd/cgroups
Signed-off-by: Davanum Srinivas <davanum@gmail.com>
This commit is contained in:
		
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -19,7 +19,6 @@ require ( | ||||
| 	github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 | ||||
| 	github.com/blang/semver/v4 v4.0.0 | ||||
| 	github.com/container-storage-interface/spec v1.9.0 | ||||
| 	github.com/containerd/cgroups v1.1.0 | ||||
| 	github.com/coredns/corefile-migration v1.0.24 | ||||
| 	github.com/coreos/go-oidc v2.2.1+incompatible | ||||
| 	github.com/coreos/go-systemd/v22 v22.5.0 | ||||
|   | ||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @@ -180,8 +180,6 @@ github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD9 | ||||
| github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= | ||||
| github.com/container-storage-interface/spec v1.9.0 h1:zKtX4STsq31Knz3gciCYCi1SXtO2HJDecIjDVboYavY= | ||||
| github.com/container-storage-interface/spec v1.9.0/go.mod h1:ZfDu+3ZRyeVqxZM0Ds19MVLkN2d1XJ5MAfi1L3VjlT0= | ||||
| github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= | ||||
| github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= | ||||
| github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= | ||||
| github.com/containerd/containerd/api v1.7.19 h1:VWbJL+8Ap4Ju2mx9c9qS1uFSB1OVYr5JJrW2yT5vFoA= | ||||
| github.com/containerd/containerd/api v1.7.19/go.mod h1:fwGavl3LNwAV5ilJ0sbrABL44AQxmNjDRcwheXDb6Ig= | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
|       "github.com/PuerkitoBio/urlesc": "unmaintained, archive mode", | ||||
|       "github.com/armon/consul-api": "MPL license not in CNCF allowlist", | ||||
|       "github.com/bketelsen/crypt": "unused, crypto", | ||||
|       "github.com/containerd/cgroups": "standardize on single cgroups library from runc, refer #128157", | ||||
|       "github.com/form3tech-oss/jwt-go": "unmaintained, archive mode", | ||||
|       "github.com/getsentry/raven-go": "unmaintained, archive mode", | ||||
|       "github.com/go-bindata/go-bindata": "refer to #99829", | ||||
| @@ -130,7 +131,6 @@ | ||||
|         "github.com/grpc-ecosystem/go-grpc-middleware" | ||||
|       ], | ||||
|       "github.com/gogo/protobuf": [ | ||||
|         "github.com/containerd/cgroups", | ||||
|         "github.com/containerd/containerd/api", | ||||
|         "github.com/containerd/ttrpc", | ||||
|         "github.com/google/cadvisor", | ||||
|   | ||||
| @@ -29,7 +29,6 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/containerd/cgroups" | ||||
| 	cadvisorv1 "github.com/google/cadvisor/info/v1" | ||||
| 	libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups" | ||||
|  | ||||
| @@ -45,6 +44,7 @@ import ( | ||||
| 	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" | ||||
| 	"k8s.io/kubernetes/pkg/kubelet/qos" | ||||
| 	kubelettypes "k8s.io/kubernetes/pkg/kubelet/types" | ||||
| 	cgroups "k8s.io/kubernetes/third_party/forked/cgroups" | ||||
| ) | ||||
|  | ||||
| var defaultPageSize = int64(os.Getpagesize()) | ||||
|   | ||||
| @@ -1,5 +1,3 @@ | ||||
| = vendor/github.com/containerd/cgroups licensed under: = | ||||
| 
 | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
| @@ -201,5 +199,3 @@ | ||||
|    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. | ||||
| 
 | ||||
| = vendor/github.com/containerd/cgroups/LICENSE 86d3f3a95c324c9479bd8986968f4327 | ||||
							
								
								
									
										64
									
								
								third_party/forked/cgroups/parse.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								third_party/forked/cgroups/parse.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| /* | ||||
| Copyright 2024 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package cgroups | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // ParseCgroupFileUnified returns legacy subsystem paths as the first value, | ||||
| // and returns the unified path as the second value. | ||||
| func ParseCgroupFileUnified(path string) (map[string]string, string, error) { | ||||
| 	f, err := os.Open(path) | ||||
| 	if err != nil { | ||||
| 		return nil, "", err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	return parseCgroupFromReaderUnified(f) | ||||
| } | ||||
|  | ||||
| func parseCgroupFromReaderUnified(r io.Reader) (map[string]string, string, error) { | ||||
| 	var ( | ||||
| 		cgroups = make(map[string]string) | ||||
| 		unified = "" | ||||
| 		s       = bufio.NewScanner(r) | ||||
| 	) | ||||
| 	for s.Scan() { | ||||
| 		var ( | ||||
| 			text  = s.Text() | ||||
| 			parts = strings.SplitN(text, ":", 3) | ||||
| 		) | ||||
| 		if len(parts) < 3 { | ||||
| 			return nil, unified, fmt.Errorf("invalid cgroup entry: %q", text) | ||||
| 		} | ||||
| 		for _, subs := range strings.Split(parts[1], ",") { | ||||
| 			if subs == "" { | ||||
| 				unified = parts[2] | ||||
| 			} else { | ||||
| 				cgroups[subs] = parts[2] | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if err := s.Err(); err != nil { | ||||
| 		return nil, unified, err | ||||
| 	} | ||||
| 	return cgroups, unified, nil | ||||
| } | ||||
							
								
								
									
										50
									
								
								third_party/forked/cgroups/parse_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								third_party/forked/cgroups/parse_test.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestParseCgroupFromReaderUnified(t *testing.T) { | ||||
| 	const data = `10:devices:/user.slice | ||||
| 	9:net_cls,net_prio:/ | ||||
| 	8:blkio:/ | ||||
| 	7:freezer:/ | ||||
| 	6:perf_event:/ | ||||
| 	5:cpuset:/ | ||||
| 	4:memory:/ | ||||
| 	3:pids:/user.slice/user-1000.slice/user@1000.service | ||||
| 	2:cpu,cpuacct:/ | ||||
| 	1:name=systemd:/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service | ||||
| 	0::/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service` | ||||
| 	r := strings.NewReader(data) | ||||
| 	paths, unified, err := parseCgroupFromReaderUnified(r) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	for subsystem, path := range paths { | ||||
| 		if subsystem == "" { | ||||
| 			t.Fatalf("empty subsystem for %q", path) | ||||
| 		} | ||||
| 	} | ||||
| 	unifiedExpected := "/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service" | ||||
| 	if unified != unifiedExpected { | ||||
| 		t.Fatalf("expected %q, got %q", unifiedExpected, unified) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										2
									
								
								vendor/github.com/containerd/cgroups/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/containerd/cgroups/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,2 +0,0 @@ | ||||
| example/example | ||||
| cmd/cgctl/cgctl | ||||
							
								
								
									
										24
									
								
								vendor/github.com/containerd/cgroups/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/containerd/cgroups/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,24 +0,0 @@ | ||||
| #   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. | ||||
|  | ||||
| PACKAGES=$(shell go list ./... | grep -v /vendor/) | ||||
|  | ||||
| all: cgutil | ||||
| 	go build -v | ||||
|  | ||||
| cgutil: | ||||
| 	cd cmd/cgctl && go build -v | ||||
|  | ||||
| proto: | ||||
| 	protobuild --quiet ${PACKAGES} | ||||
							
								
								
									
										46
									
								
								vendor/github.com/containerd/cgroups/Protobuild.toml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								vendor/github.com/containerd/cgroups/Protobuild.toml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,46 +0,0 @@ | ||||
| version = "unstable" | ||||
| generator = "gogoctrd" | ||||
| plugins = ["grpc"] | ||||
|  | ||||
| # Control protoc include paths. Below are usually some good defaults, but feel | ||||
| # free to try it without them if it works for your project. | ||||
| [includes] | ||||
|   # Include paths that will be added before all others. Typically, you want to | ||||
|   # treat the root of the project as an include, but this may not be necessary. | ||||
|   # before = ["."] | ||||
|  | ||||
|   # Paths that should be treated as include roots in relation to the vendor | ||||
|   # directory. These will be calculated with the vendor directory nearest the | ||||
|   # target package. | ||||
|   # vendored = ["github.com/gogo/protobuf"] | ||||
|   packages = ["github.com/gogo/protobuf"] | ||||
|  | ||||
|   # Paths that will be added untouched to the end of the includes. We use | ||||
|   # `/usr/local/include` to pickup the common install location of protobuf. | ||||
|   # This is the default. | ||||
|   after = ["/usr/local/include", "/usr/include"] | ||||
|  | ||||
| # This section maps protobuf imports to Go packages. These will become | ||||
| # `-M` directives in the call to the go protobuf generator. | ||||
| [packages] | ||||
|   "gogoproto/gogo.proto" = "github.com/gogo/protobuf/gogoproto" | ||||
|   "google/protobuf/any.proto" = "github.com/gogo/protobuf/types" | ||||
|   "google/protobuf/descriptor.proto" = "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" | ||||
|   "google/protobuf/field_mask.proto" = "github.com/gogo/protobuf/types" | ||||
|   "google/protobuf/timestamp.proto" = "github.com/gogo/protobuf/types" | ||||
|  | ||||
| # Aggregrate the API descriptors to lock down API changes. | ||||
| [[descriptors]] | ||||
| prefix = "github.com/containerd/cgroups/stats/v1" | ||||
| target = "stats/v1/metrics.pb.txt" | ||||
| ignore_files = [ | ||||
| 	"google/protobuf/descriptor.proto", | ||||
| 	"gogoproto/gogo.proto" | ||||
| ] | ||||
| [[descriptors]] | ||||
| prefix = "github.com/containerd/cgroups/v2/stats" | ||||
| target = "v2/stats/metrics.pb.txt" | ||||
| ignore_files = [ | ||||
| 	"google/protobuf/descriptor.proto", | ||||
| 	"gogoproto/gogo.proto" | ||||
| ] | ||||
							
								
								
									
										204
									
								
								vendor/github.com/containerd/cgroups/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										204
									
								
								vendor/github.com/containerd/cgroups/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,204 +0,0 @@ | ||||
| # cgroups | ||||
|  | ||||
| [](https://github.com/containerd/cgroups/actions?query=workflow%3ACI) | ||||
| [](https://codecov.io/gh/containerd/cgroups) | ||||
| [](https://godoc.org/github.com/containerd/cgroups) | ||||
| [](https://goreportcard.com/report/github.com/containerd/cgroups) | ||||
|  | ||||
| Go package for creating, managing, inspecting, and destroying cgroups. | ||||
| The resources format for settings on the cgroup uses the OCI runtime-spec found | ||||
| [here](https://github.com/opencontainers/runtime-spec). | ||||
|  | ||||
| ## Examples (v1) | ||||
|  | ||||
| ### Create a new cgroup | ||||
|  | ||||
| This creates a new cgroup using a static path for all subsystems under `/test`. | ||||
|  | ||||
| * /sys/fs/cgroup/cpu/test | ||||
| * /sys/fs/cgroup/memory/test | ||||
| * etc.... | ||||
|  | ||||
| It uses a single hierarchy and specifies cpu shares as a resource constraint and | ||||
| uses the v1 implementation of cgroups. | ||||
|  | ||||
|  | ||||
| ```go | ||||
| shares := uint64(100) | ||||
| control, err := cgroups.New(cgroups.V1, cgroups.StaticPath("/test"), &specs.LinuxResources{ | ||||
|     CPU: &specs.LinuxCPU{ | ||||
|         Shares: &shares, | ||||
|     }, | ||||
| }) | ||||
| defer control.Delete() | ||||
| ``` | ||||
|  | ||||
| ### Create with systemd slice support | ||||
|  | ||||
|  | ||||
| ```go | ||||
| control, err := cgroups.New(cgroups.Systemd, cgroups.Slice("system.slice", "runc-test"), &specs.LinuxResources{ | ||||
|     CPU: &specs.CPU{ | ||||
|         Shares: &shares, | ||||
|     }, | ||||
| }) | ||||
|  | ||||
| ``` | ||||
|  | ||||
| ### Load an existing cgroup | ||||
|  | ||||
| ```go | ||||
| control, err = cgroups.Load(cgroups.V1, cgroups.StaticPath("/test")) | ||||
| ``` | ||||
|  | ||||
| ### Add a process to the cgroup | ||||
|  | ||||
| ```go | ||||
| if err := control.Add(cgroups.Process{Pid:1234}); err != nil { | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ###  Update the cgroup | ||||
|  | ||||
| To update the resources applied in the cgroup | ||||
|  | ||||
| ```go | ||||
| shares = uint64(200) | ||||
| if err := control.Update(&specs.LinuxResources{ | ||||
|     CPU: &specs.LinuxCPU{ | ||||
|         Shares: &shares, | ||||
|     }, | ||||
| }); err != nil { | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Freeze and Thaw the cgroup | ||||
|  | ||||
| ```go | ||||
| if err := control.Freeze(); err != nil { | ||||
| } | ||||
| if err := control.Thaw(); err != nil { | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### List all processes in the cgroup or recursively | ||||
|  | ||||
| ```go | ||||
| processes, err := control.Processes(cgroups.Devices, recursive) | ||||
| ``` | ||||
|  | ||||
| ### Get Stats on the cgroup | ||||
|  | ||||
| ```go | ||||
| 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) | ||||
| ``` | ||||
|  | ||||
| ### Move process across cgroups | ||||
|  | ||||
| This allows you to take processes from one cgroup and move them to another. | ||||
|  | ||||
| ```go | ||||
| err := control.MoveTo(destination) | ||||
| ``` | ||||
|  | ||||
| ### Create subcgroup | ||||
|  | ||||
| ```go | ||||
| subCgroup, err := control.New("child", resources) | ||||
| ``` | ||||
|  | ||||
| ### Registering for memory events | ||||
|  | ||||
| This allows you to get notified by an eventfd for v1 memory cgroups events. | ||||
|  | ||||
| ```go | ||||
| event := cgroups.MemoryThresholdEvent(50 * 1024 * 1024, false) | ||||
| efd, err := control.RegisterMemoryEvent(event) | ||||
| ``` | ||||
|  | ||||
| ```go | ||||
| event := cgroups.MemoryPressureEvent(cgroups.MediumPressure, cgroups.DefaultMode) | ||||
| efd, err := control.RegisterMemoryEvent(event) | ||||
| ``` | ||||
|  | ||||
| ```go | ||||
| efd, err := control.OOMEventFD() | ||||
| // or by using RegisterMemoryEvent | ||||
| event := cgroups.OOMEvent() | ||||
| efd, err := control.RegisterMemoryEvent(event) | ||||
| ``` | ||||
|  | ||||
| ## Examples (v2/unified) | ||||
|  | ||||
| ### Check that the current system is running cgroups v2 | ||||
|  | ||||
| ```go | ||||
| var cgroupV2 bool | ||||
| if cgroups.Mode() == cgroups.Unified { | ||||
| 	cgroupV2 = true | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Create a new cgroup | ||||
|  | ||||
| This creates a new systemd v2 cgroup slice. Systemd slices consider ["-" a special character](https://www.freedesktop.org/software/systemd/man/systemd.slice.html), | ||||
| so the resulting slice would be located here on disk: | ||||
|  | ||||
| * /sys/fs/cgroup/my.slice/my-cgroup.slice/my-cgroup-abc.slice | ||||
|  | ||||
| ```go | ||||
| import ( | ||||
|     cgroupsv2 "github.com/containerd/cgroups/v2" | ||||
|     specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| res := cgroupsv2.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) | ||||
| if err != nil { | ||||
| 	return err | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Load an existing cgroup | ||||
|  | ||||
| ```go | ||||
| m, err := cgroupsv2.LoadSystemd("/", "my-cgroup-abc.slice") | ||||
| if err != nil { | ||||
| 	return err | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Delete a cgroup | ||||
|  | ||||
| ```go | ||||
| m, err := cgroupsv2.LoadSystemd("/", "my-cgroup-abc.slice") | ||||
| if err != nil { | ||||
| 	return err | ||||
| } | ||||
| err = m.DeleteSystemd() | ||||
| if err != nil { | ||||
| 	return err | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Attention | ||||
|  | ||||
| All static path should not include `/sys/fs/cgroup/` prefix, it should start with your own cgroups name | ||||
|  | ||||
| ## Project details | ||||
|  | ||||
| Cgroups is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). | ||||
| As a containerd sub-project, you will find the: | ||||
|  | ||||
|  * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md), | ||||
|  * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS), | ||||
|  * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md) | ||||
|  | ||||
| information in our [`containerd/project`](https://github.com/containerd/project) repository. | ||||
							
								
								
									
										361
									
								
								vendor/github.com/containerd/cgroups/blkio.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										361
									
								
								vendor/github.com/containerd/cgroups/blkio.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,361 +0,0 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package cgroups | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| // NewBlkio returns a Blkio controller given the root folder of cgroups. | ||||
| // It may optionally accept other configuration options, such as ProcRoot(path) | ||||
| func NewBlkio(root string, options ...func(controller *blkioController)) *blkioController { | ||||
| 	ctrl := &blkioController{ | ||||
| 		root:     filepath.Join(root, string(Blkio)), | ||||
| 		procRoot: "/proc", | ||||
| 	} | ||||
| 	for _, opt := range options { | ||||
| 		opt(ctrl) | ||||
| 	} | ||||
| 	return ctrl | ||||
| } | ||||
|  | ||||
| // ProcRoot overrides the default location of the "/proc" filesystem | ||||
| func ProcRoot(path string) func(controller *blkioController) { | ||||
| 	return func(c *blkioController) { | ||||
| 		c.procRoot = path | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type blkioController struct { | ||||
| 	root     string | ||||
| 	procRoot string | ||||
| } | ||||
|  | ||||
| func (b *blkioController) Name() Name { | ||||
| 	return Blkio | ||||
| } | ||||
|  | ||||
| func (b *blkioController) Path(path string) string { | ||||
| 	return filepath.Join(b.root, path) | ||||
| } | ||||
|  | ||||
| func (b *blkioController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := os.MkdirAll(b.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if resources.BlockIO == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	for _, t := range createBlkioSettings(resources.BlockIO) { | ||||
| 		if t.value != nil { | ||||
| 			if err := retryingWriteFile( | ||||
| 				filepath.Join(b.Path(path), "blkio."+t.name), | ||||
| 				t.format(t.value), | ||||
| 				defaultFilePerm, | ||||
| 			); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *blkioController) Update(path string, resources *specs.LinuxResources) error { | ||||
| 	return b.Create(path, resources) | ||||
| } | ||||
|  | ||||
| func (b *blkioController) Stat(path string, stats *v1.Metrics) error { | ||||
| 	stats.Blkio = &v1.BlkIOStat{} | ||||
|  | ||||
| 	var settings []blkioStatSettings | ||||
|  | ||||
| 	// Try to read CFQ stats available on all CFQ enabled kernels first | ||||
| 	if _, err := os.Lstat(filepath.Join(b.Path(path), "blkio.io_serviced_recursive")); err == nil { | ||||
| 		settings = []blkioStatSettings{ | ||||
| 			{ | ||||
| 				name:  "sectors_recursive", | ||||
| 				entry: &stats.Blkio.SectorsRecursive, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "io_service_bytes_recursive", | ||||
| 				entry: &stats.Blkio.IoServiceBytesRecursive, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "io_serviced_recursive", | ||||
| 				entry: &stats.Blkio.IoServicedRecursive, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "io_queued_recursive", | ||||
| 				entry: &stats.Blkio.IoQueuedRecursive, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "io_service_time_recursive", | ||||
| 				entry: &stats.Blkio.IoServiceTimeRecursive, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "io_wait_time_recursive", | ||||
| 				entry: &stats.Blkio.IoWaitTimeRecursive, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "io_merged_recursive", | ||||
| 				entry: &stats.Blkio.IoMergedRecursive, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "time_recursive", | ||||
| 				entry: &stats.Blkio.IoTimeRecursive, | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	f, err := os.Open(filepath.Join(b.procRoot, "partitions")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
|  | ||||
| 	devices, err := getDevices(f) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var size int | ||||
| 	for _, t := range settings { | ||||
| 		if err := b.readEntry(devices, path, t.name, t.entry); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		size += len(*t.entry) | ||||
| 	} | ||||
| 	if size > 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// Even the kernel is compiled with the CFQ scheduler, the cgroup may not use | ||||
| 	// block devices with the CFQ scheduler. If so, we should fallback to throttle.* files. | ||||
| 	settings = []blkioStatSettings{ | ||||
| 		{ | ||||
| 			name:  "throttle.io_serviced", | ||||
| 			entry: &stats.Blkio.IoServicedRecursive, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "throttle.io_service_bytes", | ||||
| 			entry: &stats.Blkio.IoServiceBytesRecursive, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, t := range settings { | ||||
| 		if err := b.readEntry(devices, path, t.name, t.entry); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *blkioController) readEntry(devices map[deviceKey]string, path, name string, entry *[]*v1.BlkIOEntry) error { | ||||
| 	f, err := os.Open(filepath.Join(b.Path(path), "blkio."+name)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	sc := bufio.NewScanner(f) | ||||
| 	for sc.Scan() { | ||||
| 		// format: dev type amount | ||||
| 		fields := strings.FieldsFunc(sc.Text(), splitBlkIOStatLine) | ||||
| 		if len(fields) < 3 { | ||||
| 			if len(fields) == 2 && fields[0] == "Total" { | ||||
| 				// skip total line | ||||
| 				continue | ||||
| 			} else { | ||||
| 				return fmt.Errorf("invalid line found while parsing %s: %s", path, sc.Text()) | ||||
| 			} | ||||
| 		} | ||||
| 		major, err := strconv.ParseUint(fields[0], 10, 64) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		minor, err := strconv.ParseUint(fields[1], 10, 64) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		op := "" | ||||
| 		valueField := 2 | ||||
| 		if len(fields) == 4 { | ||||
| 			op = fields[2] | ||||
| 			valueField = 3 | ||||
| 		} | ||||
| 		v, err := strconv.ParseUint(fields[valueField], 10, 64) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		*entry = append(*entry, &v1.BlkIOEntry{ | ||||
| 			Device: devices[deviceKey{major, minor}], | ||||
| 			Major:  major, | ||||
| 			Minor:  minor, | ||||
| 			Op:     op, | ||||
| 			Value:  v, | ||||
| 		}) | ||||
| 	} | ||||
| 	return sc.Err() | ||||
| } | ||||
|  | ||||
| func createBlkioSettings(blkio *specs.LinuxBlockIO) []blkioSettings { | ||||
| 	settings := []blkioSettings{} | ||||
|  | ||||
| 	if blkio.Weight != nil { | ||||
| 		settings = append(settings, | ||||
| 			blkioSettings{ | ||||
| 				name:   "weight", | ||||
| 				value:  blkio.Weight, | ||||
| 				format: uintf, | ||||
| 			}) | ||||
| 	} | ||||
| 	if blkio.LeafWeight != nil { | ||||
| 		settings = append(settings, | ||||
| 			blkioSettings{ | ||||
| 				name:   "leaf_weight", | ||||
| 				value:  blkio.LeafWeight, | ||||
| 				format: uintf, | ||||
| 			}) | ||||
| 	} | ||||
| 	for _, wd := range blkio.WeightDevice { | ||||
| 		if wd.Weight != nil { | ||||
| 			settings = append(settings, | ||||
| 				blkioSettings{ | ||||
| 					name:   "weight_device", | ||||
| 					value:  wd, | ||||
| 					format: weightdev, | ||||
| 				}) | ||||
| 		} | ||||
| 		if wd.LeafWeight != nil { | ||||
| 			settings = append(settings, | ||||
| 				blkioSettings{ | ||||
| 					name:   "leaf_weight_device", | ||||
| 					value:  wd, | ||||
| 					format: weightleafdev, | ||||
| 				}) | ||||
| 		} | ||||
| 	} | ||||
| 	for _, t := range []struct { | ||||
| 		name string | ||||
| 		list []specs.LinuxThrottleDevice | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "throttle.read_bps_device", | ||||
| 			list: blkio.ThrottleReadBpsDevice, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "throttle.read_iops_device", | ||||
| 			list: blkio.ThrottleReadIOPSDevice, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "throttle.write_bps_device", | ||||
| 			list: blkio.ThrottleWriteBpsDevice, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "throttle.write_iops_device", | ||||
| 			list: blkio.ThrottleWriteIOPSDevice, | ||||
| 		}, | ||||
| 	} { | ||||
| 		for _, td := range t.list { | ||||
| 			settings = append(settings, blkioSettings{ | ||||
| 				name:   t.name, | ||||
| 				value:  td, | ||||
| 				format: throttleddev, | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| 	return settings | ||||
| } | ||||
|  | ||||
| type blkioSettings struct { | ||||
| 	name   string | ||||
| 	value  interface{} | ||||
| 	format func(v interface{}) []byte | ||||
| } | ||||
|  | ||||
| type blkioStatSettings struct { | ||||
| 	name  string | ||||
| 	entry *[]*v1.BlkIOEntry | ||||
| } | ||||
|  | ||||
| func uintf(v interface{}) []byte { | ||||
| 	return []byte(strconv.FormatUint(uint64(*v.(*uint16)), 10)) | ||||
| } | ||||
|  | ||||
| func weightdev(v interface{}) []byte { | ||||
| 	wd := v.(specs.LinuxWeightDevice) | ||||
| 	return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.Weight)) | ||||
| } | ||||
|  | ||||
| func weightleafdev(v interface{}) []byte { | ||||
| 	wd := v.(specs.LinuxWeightDevice) | ||||
| 	return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.LeafWeight)) | ||||
| } | ||||
|  | ||||
| func throttleddev(v interface{}) []byte { | ||||
| 	td := v.(specs.LinuxThrottleDevice) | ||||
| 	return []byte(fmt.Sprintf("%d:%d %d", td.Major, td.Minor, td.Rate)) | ||||
| } | ||||
|  | ||||
| func splitBlkIOStatLine(r rune) bool { | ||||
| 	return r == ' ' || r == ':' | ||||
| } | ||||
|  | ||||
| type deviceKey struct { | ||||
| 	major, minor uint64 | ||||
| } | ||||
|  | ||||
| // getDevices makes a best effort attempt to read all the devices into a map | ||||
| // keyed by major and minor number. Since devices may be mapped multiple times, | ||||
| // we err on taking the first occurrence. | ||||
| func getDevices(r io.Reader) (map[deviceKey]string, error) { | ||||
|  | ||||
| 	var ( | ||||
| 		s       = bufio.NewScanner(r) | ||||
| 		devices = make(map[deviceKey]string) | ||||
| 	) | ||||
| 	for i := 0; s.Scan(); i++ { | ||||
| 		if i < 2 { | ||||
| 			continue | ||||
| 		} | ||||
| 		fields := strings.Fields(s.Text()) | ||||
| 		major, err := strconv.Atoi(fields[0]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		minor, err := strconv.Atoi(fields[1]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		key := deviceKey{ | ||||
| 			major: uint64(major), | ||||
| 			minor: uint64(minor), | ||||
| 		} | ||||
| 		if _, ok := devices[key]; ok { | ||||
| 			continue | ||||
| 		} | ||||
| 		devices[key] = filepath.Join("/dev", fields[3]) | ||||
| 	} | ||||
| 	return devices, s.Err() | ||||
| } | ||||
							
								
								
									
										543
									
								
								vendor/github.com/containerd/cgroups/cgroup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										543
									
								
								vendor/github.com/containerd/cgroups/cgroup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,543 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
|  | ||||
| 	"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) { | ||||
| 	config := newInitConfig() | ||||
| 	for _, o := range opts { | ||||
| 		if err := o(config); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	subsystems, err := hierarchy() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var active []Subsystem | ||||
| 	for _, s := range subsystems { | ||||
| 		// check if subsystem exists | ||||
| 		if err := initializeSubsystem(s, path, resources); err != nil { | ||||
| 			if err == ErrControllerNotActive { | ||||
| 				if config.InitCheck != nil { | ||||
| 					if skerr := config.InitCheck(s, path, err); skerr != nil { | ||||
| 						if skerr != ErrIgnoreSubsystem { | ||||
| 							return nil, skerr | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				continue | ||||
| 			} | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		active = append(active, s) | ||||
| 	} | ||||
| 	return &cgroup{ | ||||
| 		path:       path, | ||||
| 		subsystems: active, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	config := newInitConfig() | ||||
| 	for _, o := range opts { | ||||
| 		if err := o(config); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	var activeSubsystems []Subsystem | ||||
| 	subsystems, err := hierarchy() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// check that the subsystems still exist, and keep only those that actually exist | ||||
| 	for _, s := range pathers(subsystems) { | ||||
| 		p, err := path(s.Name()) | ||||
| 		if err != nil { | ||||
| 			if errors.Is(err, os.ErrNotExist) { | ||||
| 				return nil, ErrCgroupDeleted | ||||
| 			} | ||||
| 			if err == ErrControllerNotActive { | ||||
| 				if config.InitCheck != nil { | ||||
| 					if skerr := config.InitCheck(s, path, err); skerr != nil { | ||||
| 						if skerr != ErrIgnoreSubsystem { | ||||
| 							return nil, skerr | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				continue | ||||
| 			} | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if _, err := os.Lstat(s.Path(p)); err != nil { | ||||
| 			if os.IsNotExist(err) { | ||||
| 				continue | ||||
| 			} | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		activeSubsystems = append(activeSubsystems, s) | ||||
| 	} | ||||
| 	// if we do not have any active systems then the cgroup is deleted | ||||
| 	if len(activeSubsystems) == 0 { | ||||
| 		return nil, ErrCgroupDeleted | ||||
| 	} | ||||
| 	return &cgroup{ | ||||
| 		path:       path, | ||||
| 		subsystems: activeSubsystems, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| type cgroup struct { | ||||
| 	path Path | ||||
|  | ||||
| 	subsystems []Subsystem | ||||
| 	mu         sync.Mutex | ||||
| 	err        error | ||||
| } | ||||
|  | ||||
| // New returns a new sub cgroup | ||||
| func (c *cgroup) New(name string, resources *specs.LinuxResources) (Cgroup, error) { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return nil, c.err | ||||
| 	} | ||||
| 	path := subPath(c.path, name) | ||||
| 	for _, s := range c.subsystems { | ||||
| 		if err := initializeSubsystem(s, path, resources); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	return &cgroup{ | ||||
| 		path:       path, | ||||
| 		subsystems: c.subsystems, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // Subsystems returns all the subsystems that are currently being | ||||
| // consumed by the group | ||||
| func (c *cgroup) Subsystems() []Subsystem { | ||||
| 	return c.subsystems | ||||
| } | ||||
|  | ||||
| func (c *cgroup) subsystemsFilter(subsystems ...Name) []Subsystem { | ||||
| 	if len(subsystems) == 0 { | ||||
| 		return c.subsystems | ||||
| 	} | ||||
|  | ||||
| 	var filteredSubsystems = []Subsystem{} | ||||
| 	for _, s := range c.subsystems { | ||||
| 		for _, f := range subsystems { | ||||
| 			if s.Name() == f { | ||||
| 				filteredSubsystems = append(filteredSubsystems, s) | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return filteredSubsystems | ||||
| } | ||||
|  | ||||
| // Add moves the provided process into the new cgroup. | ||||
| // Without additional arguments, the process is added to all the cgroup subsystems. | ||||
| // When giving Add a list of subsystem names, the process is only added to those | ||||
| // subsystems, provided that they are active in the targeted cgroup. | ||||
| func (c *cgroup) Add(process Process, subsystems ...Name) error { | ||||
| 	return c.add(process, cgroupProcs, subsystems...) | ||||
| } | ||||
|  | ||||
| // AddProc moves the provided process id into the new cgroup. | ||||
| // Without additional arguments, the process with the given id is added to all | ||||
| // the cgroup subsystems. When giving AddProc a list of subsystem names, the process | ||||
| // id is only added to those subsystems, provided that they are active in the targeted | ||||
| // cgroup. | ||||
| func (c *cgroup) AddProc(pid uint64, subsystems ...Name) error { | ||||
| 	return c.add(Process{Pid: int(pid)}, cgroupProcs, subsystems...) | ||||
| } | ||||
|  | ||||
| // AddTask moves the provided tasks (threads) into the new cgroup. | ||||
| // Without additional arguments, the task is added to all the cgroup subsystems. | ||||
| // When giving AddTask a list of subsystem names, the task is only added to those | ||||
| // subsystems, provided that they are active in the targeted cgroup. | ||||
| func (c *cgroup) AddTask(process Process, subsystems ...Name) error { | ||||
| 	return c.add(process, cgroupTasks, subsystems...) | ||||
| } | ||||
|  | ||||
| func (c *cgroup) add(process Process, pType procType, subsystems ...Name) error { | ||||
| 	if process.Pid <= 0 { | ||||
| 		return ErrInvalidPid | ||||
| 	} | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return c.err | ||||
| 	} | ||||
| 	for _, s := range pathers(c.subsystemsFilter(subsystems...)) { | ||||
| 		p, err := c.path(s.Name()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		err = retryingWriteFile( | ||||
| 			filepath.Join(s.Path(p), pType), | ||||
| 			[]byte(strconv.Itoa(process.Pid)), | ||||
| 			defaultFilePerm, | ||||
| 		) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Delete will remove the control group from each of the subsystems registered | ||||
| func (c *cgroup) Delete() error { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return c.err | ||||
| 	} | ||||
| 	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 { | ||||
| 				return err | ||||
| 			} | ||||
| 			if err := d.Delete(sp); err != nil { | ||||
| 				errs = append(errs, string(s.Name())) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if p, ok := s.(pather); ok { | ||||
| 			sp, err := c.path(s.Name()) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			path := p.Path(sp) | ||||
| 			if err := remove(path); err != nil { | ||||
| 				errs = append(errs, path) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 	} | ||||
| 	if len(errs) > 0 { | ||||
| 		return fmt.Errorf("cgroups: unable to remove paths %s", strings.Join(errs, ", ")) | ||||
| 	} | ||||
| 	c.err = ErrCgroupDeleted | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Stat returns the current metrics for the cgroup | ||||
| func (c *cgroup) Stat(handlers ...ErrorHandler) (*v1.Metrics, error) { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return nil, c.err | ||||
| 	} | ||||
| 	if len(handlers) == 0 { | ||||
| 		handlers = append(handlers, errPassthrough) | ||||
| 	} | ||||
| 	var ( | ||||
| 		stats = &v1.Metrics{ | ||||
| 			CPU: &v1.CPUStat{ | ||||
| 				Throttling: &v1.Throttle{}, | ||||
| 				Usage:      &v1.CPUUsage{}, | ||||
| 			}, | ||||
| 		} | ||||
| 		wg   = &sync.WaitGroup{} | ||||
| 		errs = make(chan error, len(c.subsystems)) | ||||
| 	) | ||||
| 	for _, s := range c.subsystems { | ||||
| 		if ss, ok := s.(stater); ok { | ||||
| 			sp, err := c.path(s.Name()) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			wg.Add(1) | ||||
| 			go func() { | ||||
| 				defer wg.Done() | ||||
| 				if err := ss.Stat(sp, stats); err != nil { | ||||
| 					for _, eh := range handlers { | ||||
| 						if herr := eh(err); herr != nil { | ||||
| 							errs <- herr | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			}() | ||||
| 		} | ||||
| 	} | ||||
| 	wg.Wait() | ||||
| 	close(errs) | ||||
| 	for err := range errs { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return stats, nil | ||||
| } | ||||
|  | ||||
| // Update updates the cgroup with the new resource values provided | ||||
| // | ||||
| // Be prepared to handle EBUSY when trying to update a cgroup with | ||||
| // live processes and other operations like Stats being performed at the | ||||
| // same time | ||||
| func (c *cgroup) Update(resources *specs.LinuxResources) error { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return c.err | ||||
| 	} | ||||
| 	for _, s := range c.subsystems { | ||||
| 		if u, ok := s.(updater); ok { | ||||
| 			sp, err := c.path(s.Name()) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if err := u.Update(sp, resources); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Processes returns the processes running inside the cgroup along | ||||
| // with the subsystem used, pid, and path | ||||
| func (c *cgroup) Processes(subsystem Name, recursive bool) ([]Process, error) { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return nil, c.err | ||||
| 	} | ||||
| 	return c.processes(subsystem, recursive, cgroupProcs) | ||||
| } | ||||
|  | ||||
| // Tasks returns the tasks running inside the cgroup along | ||||
| // with the subsystem used, pid, and path | ||||
| func (c *cgroup) Tasks(subsystem Name, recursive bool) ([]Task, error) { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return nil, c.err | ||||
| 	} | ||||
| 	return c.processes(subsystem, recursive, cgroupTasks) | ||||
| } | ||||
|  | ||||
| func (c *cgroup) processes(subsystem Name, recursive bool, pType procType) ([]Process, error) { | ||||
| 	s := c.getSubsystem(subsystem) | ||||
| 	sp, err := c.path(subsystem) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if s == nil { | ||||
| 		return nil, fmt.Errorf("cgroups: %s doesn't exist in %s subsystem", sp, subsystem) | ||||
| 	} | ||||
| 	path := s.(pather).Path(sp) | ||||
| 	var processes []Process | ||||
| 	err = filepath.Walk(path, func(p string, info os.FileInfo, err error) error { | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if !recursive && info.IsDir() { | ||||
| 			if p == path { | ||||
| 				return nil | ||||
| 			} | ||||
| 			return filepath.SkipDir | ||||
| 		} | ||||
| 		dir, name := filepath.Split(p) | ||||
| 		if name != pType { | ||||
| 			return nil | ||||
| 		} | ||||
| 		procs, err := readPids(dir, subsystem, pType) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		processes = append(processes, procs...) | ||||
| 		return nil | ||||
| 	}) | ||||
| 	return processes, err | ||||
| } | ||||
|  | ||||
| // Freeze freezes the entire cgroup and all the processes inside it | ||||
| func (c *cgroup) Freeze() error { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return c.err | ||||
| 	} | ||||
| 	s := c.getSubsystem(Freezer) | ||||
| 	if s == nil { | ||||
| 		return ErrFreezerNotSupported | ||||
| 	} | ||||
| 	sp, err := c.path(Freezer) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return s.(*freezerController).Freeze(sp) | ||||
| } | ||||
|  | ||||
| // Thaw thaws out the cgroup and all the processes inside it | ||||
| func (c *cgroup) Thaw() error { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return c.err | ||||
| 	} | ||||
| 	s := c.getSubsystem(Freezer) | ||||
| 	if s == nil { | ||||
| 		return ErrFreezerNotSupported | ||||
| 	} | ||||
| 	sp, err := c.path(Freezer) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return s.(*freezerController).Thaw(sp) | ||||
| } | ||||
|  | ||||
| // OOMEventFD returns the memory cgroup's out of memory event fd that triggers | ||||
| // when processes inside the cgroup receive an oom event. Returns | ||||
| // ErrMemoryNotSupported if memory cgroups is not supported. | ||||
| func (c *cgroup) OOMEventFD() (uintptr, error) { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return 0, c.err | ||||
| 	} | ||||
| 	s := c.getSubsystem(Memory) | ||||
| 	if s == nil { | ||||
| 		return 0, ErrMemoryNotSupported | ||||
| 	} | ||||
| 	sp, err := c.path(Memory) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return s.(*memoryController).memoryEvent(sp, OOMEvent()) | ||||
| } | ||||
|  | ||||
| // RegisterMemoryEvent allows the ability to register for all v1 memory cgroups | ||||
| // notifications. | ||||
| func (c *cgroup) RegisterMemoryEvent(event MemoryEvent) (uintptr, error) { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return 0, c.err | ||||
| 	} | ||||
| 	s := c.getSubsystem(Memory) | ||||
| 	if s == nil { | ||||
| 		return 0, ErrMemoryNotSupported | ||||
| 	} | ||||
| 	sp, err := c.path(Memory) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return s.(*memoryController).memoryEvent(sp, event) | ||||
| } | ||||
|  | ||||
| // State returns the state of the cgroup and its processes | ||||
| func (c *cgroup) State() State { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	c.checkExists() | ||||
| 	if c.err != nil && c.err == ErrCgroupDeleted { | ||||
| 		return Deleted | ||||
| 	} | ||||
| 	s := c.getSubsystem(Freezer) | ||||
| 	if s == nil { | ||||
| 		return Thawed | ||||
| 	} | ||||
| 	sp, err := c.path(Freezer) | ||||
| 	if err != nil { | ||||
| 		return Unknown | ||||
| 	} | ||||
| 	state, err := s.(*freezerController).state(sp) | ||||
| 	if err != nil { | ||||
| 		return Unknown | ||||
| 	} | ||||
| 	return state | ||||
| } | ||||
|  | ||||
| // MoveTo does a recursive move subsystem by subsystem of all the processes | ||||
| // inside the group | ||||
| func (c *cgroup) MoveTo(destination Cgroup) error { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 	if c.err != nil { | ||||
| 		return c.err | ||||
| 	} | ||||
| 	for _, s := range c.subsystems { | ||||
| 		processes, err := c.processes(s.Name(), true, cgroupProcs) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		for _, p := range processes { | ||||
| 			if err := destination.Add(p); err != nil { | ||||
| 				if strings.Contains(err.Error(), "no such process") { | ||||
| 					continue | ||||
| 				} | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *cgroup) getSubsystem(n Name) Subsystem { | ||||
| 	for _, s := range c.subsystems { | ||||
| 		if s.Name() == n { | ||||
| 			return s | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *cgroup) checkExists() { | ||||
| 	for _, s := range pathers(c.subsystems) { | ||||
| 		p, err := c.path(s.Name()) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err := os.Lstat(s.Path(p)); err != nil { | ||||
| 			if os.IsNotExist(err) { | ||||
| 				c.err = ErrCgroupDeleted | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										99
									
								
								vendor/github.com/containerd/cgroups/control.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										99
									
								
								vendor/github.com/containerd/cgroups/control.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,99 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"os" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| type procType = string | ||||
|  | ||||
| const ( | ||||
| 	cgroupProcs    procType = "cgroup.procs" | ||||
| 	cgroupTasks    procType = "tasks" | ||||
| 	defaultDirPerm          = 0755 | ||||
| ) | ||||
|  | ||||
| // defaultFilePerm is a var so that the test framework can change the filemode | ||||
| // of all files created when the tests are running.  The difference between the | ||||
| // tests and real world use is that files like "cgroup.procs" will exist when writing | ||||
| // to a read cgroup filesystem and do not exist prior when running in the tests. | ||||
| // this is set to a non 0 value in the test code | ||||
| var defaultFilePerm = os.FileMode(0) | ||||
|  | ||||
| type Process struct { | ||||
| 	// Subsystem is the name of the subsystem that the process / task is in. | ||||
| 	Subsystem Name | ||||
| 	// Pid is the process id of the process / task. | ||||
| 	Pid int | ||||
| 	// Path is the full path of the subsystem and location that the process / task is in. | ||||
| 	Path string | ||||
| } | ||||
|  | ||||
| type Task = Process | ||||
|  | ||||
| // Cgroup handles interactions with the individual groups to perform | ||||
| // actions on them as them main interface to this cgroup package | ||||
| type Cgroup interface { | ||||
| 	// New creates a new cgroup under the calling cgroup | ||||
| 	New(string, *specs.LinuxResources) (Cgroup, error) | ||||
| 	// Add adds a process to the cgroup (cgroup.procs). Without additional arguments, | ||||
| 	// the process is added to all the cgroup subsystems. When giving Add a list of | ||||
| 	// subsystem names, the process is only added to those subsystems, provided that | ||||
| 	// they are active in the targeted cgroup. | ||||
| 	Add(Process, ...Name) error | ||||
| 	// AddProc adds the process with the given id to the cgroup (cgroup.procs). | ||||
| 	// Without additional arguments, the process with the given id is added to all | ||||
| 	// the cgroup subsystems. When giving AddProc a list of subsystem names, the process | ||||
| 	// id is only added to those subsystems, provided that they are active in the targeted | ||||
| 	// cgroup. | ||||
| 	AddProc(uint64, ...Name) error | ||||
| 	// AddTask adds a process to the cgroup (tasks). Without additional arguments, the | ||||
| 	// task is added to all the cgroup subsystems. When giving AddTask a list of subsystem | ||||
| 	// names, the task is only added to those subsystems, provided that they are active in | ||||
| 	// the targeted cgroup. | ||||
| 	AddTask(Process, ...Name) error | ||||
| 	// Delete removes the cgroup as a whole | ||||
| 	Delete() error | ||||
| 	// MoveTo moves all the processes under the calling cgroup to the provided one | ||||
| 	// subsystems are moved one at a time | ||||
| 	MoveTo(Cgroup) error | ||||
| 	// Stat returns the stats for all subsystems in the cgroup | ||||
| 	Stat(...ErrorHandler) (*v1.Metrics, error) | ||||
| 	// Update updates all the subsystems with the provided resource changes | ||||
| 	Update(resources *specs.LinuxResources) error | ||||
| 	// Processes returns all the processes in a select subsystem for the cgroup | ||||
| 	Processes(Name, bool) ([]Process, error) | ||||
| 	// Tasks returns all the tasks in a select subsystem for the cgroup | ||||
| 	Tasks(Name, bool) ([]Task, error) | ||||
| 	// Freeze freezes or pauses all processes inside the cgroup | ||||
| 	Freeze() error | ||||
| 	// Thaw thaw or resumes all processes inside the cgroup | ||||
| 	Thaw() error | ||||
| 	// OOMEventFD returns the memory subsystem's event fd for OOM events | ||||
| 	OOMEventFD() (uintptr, error) | ||||
| 	// RegisterMemoryEvent returns the memory subsystems event fd for whatever memory event was | ||||
| 	// registered for. Can alternatively register for the oom event with this method. | ||||
| 	RegisterMemoryEvent(MemoryEvent) (uintptr, error) | ||||
| 	// State returns the cgroups current state | ||||
| 	State() State | ||||
| 	// Subsystems returns all the subsystems in the cgroup | ||||
| 	Subsystems() []Subsystem | ||||
| } | ||||
							
								
								
									
										125
									
								
								vendor/github.com/containerd/cgroups/cpu.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										125
									
								
								vendor/github.com/containerd/cgroups/cpu.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,125 +0,0 @@ | ||||
| /* | ||||
|    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" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| func NewCpu(root string) *cpuController { | ||||
| 	return &cpuController{ | ||||
| 		root: filepath.Join(root, string(Cpu)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type cpuController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (c *cpuController) Name() Name { | ||||
| 	return Cpu | ||||
| } | ||||
|  | ||||
| func (c *cpuController) Path(path string) string { | ||||
| 	return filepath.Join(c.root, path) | ||||
| } | ||||
|  | ||||
| func (c *cpuController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := os.MkdirAll(c.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if cpu := resources.CPU; cpu != nil { | ||||
| 		for _, t := range []struct { | ||||
| 			name   string | ||||
| 			ivalue *int64 | ||||
| 			uvalue *uint64 | ||||
| 		}{ | ||||
| 			{ | ||||
| 				name:   "rt_period_us", | ||||
| 				uvalue: cpu.RealtimePeriod, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:   "rt_runtime_us", | ||||
| 				ivalue: cpu.RealtimeRuntime, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:   "shares", | ||||
| 				uvalue: cpu.Shares, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:   "cfs_period_us", | ||||
| 				uvalue: cpu.Period, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:   "cfs_quota_us", | ||||
| 				ivalue: cpu.Quota, | ||||
| 			}, | ||||
| 		} { | ||||
| 			var value []byte | ||||
| 			if t.uvalue != nil { | ||||
| 				value = []byte(strconv.FormatUint(*t.uvalue, 10)) | ||||
| 			} else if t.ivalue != nil { | ||||
| 				value = []byte(strconv.FormatInt(*t.ivalue, 10)) | ||||
| 			} | ||||
| 			if value != nil { | ||||
| 				if err := retryingWriteFile( | ||||
| 					filepath.Join(c.Path(path), "cpu."+t.name), | ||||
| 					value, | ||||
| 					defaultFilePerm, | ||||
| 				); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *cpuController) Update(path string, resources *specs.LinuxResources) error { | ||||
| 	return c.Create(path, resources) | ||||
| } | ||||
|  | ||||
| func (c *cpuController) Stat(path string, stats *v1.Metrics) error { | ||||
| 	f, err := os.Open(filepath.Join(c.Path(path), "cpu.stat")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	// get or create the cpu field because cpuacct can also set values on this struct | ||||
| 	sc := bufio.NewScanner(f) | ||||
| 	for sc.Scan() { | ||||
| 		key, v, err := parseKV(sc.Text()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		switch key { | ||||
| 		case "nr_periods": | ||||
| 			stats.CPU.Throttling.Periods = v | ||||
| 		case "nr_throttled": | ||||
| 			stats.CPU.Throttling.ThrottledPeriods = v | ||||
| 		case "throttled_time": | ||||
| 			stats.CPU.Throttling.ThrottledTime = v | ||||
| 		} | ||||
| 	} | ||||
| 	return sc.Err() | ||||
| } | ||||
							
								
								
									
										129
									
								
								vendor/github.com/containerd/cgroups/cpuacct.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										129
									
								
								vendor/github.com/containerd/cgroups/cpuacct.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,129 +0,0 @@ | ||||
| /* | ||||
|    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" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
| ) | ||||
|  | ||||
| const nanosecondsInSecond = 1000000000 | ||||
|  | ||||
| var clockTicks = getClockTicks() | ||||
|  | ||||
| func NewCpuacct(root string) *cpuacctController { | ||||
| 	return &cpuacctController{ | ||||
| 		root: filepath.Join(root, string(Cpuacct)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type cpuacctController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (c *cpuacctController) Name() Name { | ||||
| 	return Cpuacct | ||||
| } | ||||
|  | ||||
| func (c *cpuacctController) Path(path string) string { | ||||
| 	return filepath.Join(c.root, path) | ||||
| } | ||||
|  | ||||
| func (c *cpuacctController) Stat(path string, stats *v1.Metrics) error { | ||||
| 	user, kernel, err := c.getUsage(path) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	total, err := readUint(filepath.Join(c.Path(path), "cpuacct.usage")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	percpu, err := c.percpuUsage(path) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	stats.CPU.Usage.Total = total | ||||
| 	stats.CPU.Usage.User = user | ||||
| 	stats.CPU.Usage.Kernel = kernel | ||||
| 	stats.CPU.Usage.PerCPU = percpu | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *cpuacctController) percpuUsage(path string) ([]uint64, error) { | ||||
| 	var usage []uint64 | ||||
| 	data, err := os.ReadFile(filepath.Join(c.Path(path), "cpuacct.usage_percpu")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, v := range strings.Fields(string(data)) { | ||||
| 		u, err := strconv.ParseUint(v, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		usage = append(usage, u) | ||||
| 	} | ||||
| 	return usage, nil | ||||
| } | ||||
|  | ||||
| func (c *cpuacctController) getUsage(path string) (user uint64, kernel uint64, err error) { | ||||
| 	statPath := filepath.Join(c.Path(path), "cpuacct.stat") | ||||
| 	f, err := os.Open(statPath) | ||||
| 	if err != nil { | ||||
| 		return 0, 0, err | ||||
| 	} | ||||
| 	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 { | ||||
| 		name  string | ||||
| 		value *uint64 | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:  "user", | ||||
| 			value: &user, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "system", | ||||
| 			value: &kernel, | ||||
| 		}, | ||||
| 	} { | ||||
| 		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 | ||||
| 	} | ||||
| 	return (user * nanosecondsInSecond) / clockTicks, (kernel * nanosecondsInSecond) / clockTicks, nil | ||||
| } | ||||
							
								
								
									
										158
									
								
								vendor/github.com/containerd/cgroups/cpuset.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										158
									
								
								vendor/github.com/containerd/cgroups/cpuset.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,158 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| func NewCpuset(root string) *cpusetController { | ||||
| 	return &cpusetController{ | ||||
| 		root: filepath.Join(root, string(Cpuset)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type cpusetController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (c *cpusetController) Name() Name { | ||||
| 	return Cpuset | ||||
| } | ||||
|  | ||||
| func (c *cpusetController) Path(path string) string { | ||||
| 	return filepath.Join(c.root, path) | ||||
| } | ||||
|  | ||||
| func (c *cpusetController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := c.ensureParent(c.Path(path), c.root); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := os.MkdirAll(c.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := c.copyIfNeeded(c.Path(path), filepath.Dir(c.Path(path))); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if resources.CPU != nil { | ||||
| 		for _, t := range []struct { | ||||
| 			name  string | ||||
| 			value string | ||||
| 		}{ | ||||
| 			{ | ||||
| 				name:  "cpus", | ||||
| 				value: resources.CPU.Cpus, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "mems", | ||||
| 				value: resources.CPU.Mems, | ||||
| 			}, | ||||
| 		} { | ||||
| 			if t.value != "" { | ||||
| 				if err := retryingWriteFile( | ||||
| 					filepath.Join(c.Path(path), "cpuset."+t.name), | ||||
| 					[]byte(t.value), | ||||
| 					defaultFilePerm, | ||||
| 				); err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *cpusetController) Update(path string, resources *specs.LinuxResources) error { | ||||
| 	return c.Create(path, resources) | ||||
| } | ||||
|  | ||||
| func (c *cpusetController) getValues(path string) (cpus []byte, mems []byte, err error) { | ||||
| 	if cpus, err = os.ReadFile(filepath.Join(path, "cpuset.cpus")); err != nil && !os.IsNotExist(err) { | ||||
| 		return | ||||
| 	} | ||||
| 	if mems, err = os.ReadFile(filepath.Join(path, "cpuset.mems")); err != nil && !os.IsNotExist(err) { | ||||
| 		return | ||||
| 	} | ||||
| 	return cpus, mems, nil | ||||
| } | ||||
|  | ||||
| // ensureParent makes sure that the parent directory of current is created | ||||
| // and populated with the proper cpus and mems files copied from | ||||
| // it's parent. | ||||
| func (c *cpusetController) ensureParent(current, root string) error { | ||||
| 	parent := filepath.Dir(current) | ||||
| 	if _, err := filepath.Rel(root, parent); err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	// Avoid infinite recursion. | ||||
| 	if parent == current { | ||||
| 		return fmt.Errorf("cpuset: cgroup parent path outside cgroup root") | ||||
| 	} | ||||
| 	if cleanPath(parent) != root { | ||||
| 		if err := c.ensureParent(parent, root); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if err := os.MkdirAll(current, defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return c.copyIfNeeded(current, parent) | ||||
| } | ||||
|  | ||||
| // copyIfNeeded copies the cpuset.cpus and cpuset.mems from the parent | ||||
| // directory to the current directory if the file's contents are 0 | ||||
| func (c *cpusetController) copyIfNeeded(current, parent string) error { | ||||
| 	var ( | ||||
| 		err                      error | ||||
| 		currentCpus, currentMems []byte | ||||
| 		parentCpus, parentMems   []byte | ||||
| 	) | ||||
| 	if currentCpus, currentMems, err = c.getValues(current); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if parentCpus, parentMems, err = c.getValues(parent); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if isEmpty(currentCpus) { | ||||
| 		if err := retryingWriteFile( | ||||
| 			filepath.Join(current, "cpuset.cpus"), | ||||
| 			parentCpus, | ||||
| 			defaultFilePerm, | ||||
| 		); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if isEmpty(currentMems) { | ||||
| 		if err := retryingWriteFile( | ||||
| 			filepath.Join(current, "cpuset.mems"), | ||||
| 			parentMems, | ||||
| 			defaultFilePerm, | ||||
| 		); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func isEmpty(b []byte) bool { | ||||
| 	return len(bytes.Trim(b, "\n")) == 0 | ||||
| } | ||||
							
								
								
									
										92
									
								
								vendor/github.com/containerd/cgroups/devices.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										92
									
								
								vendor/github.com/containerd/cgroups/devices.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,92 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	allowDeviceFile = "devices.allow" | ||||
| 	denyDeviceFile  = "devices.deny" | ||||
| 	wildcard        = -1 | ||||
| ) | ||||
|  | ||||
| func NewDevices(root string) *devicesController { | ||||
| 	return &devicesController{ | ||||
| 		root: filepath.Join(root, string(Devices)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type devicesController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (d *devicesController) Name() Name { | ||||
| 	return Devices | ||||
| } | ||||
|  | ||||
| func (d *devicesController) Path(path string) string { | ||||
| 	return filepath.Join(d.root, path) | ||||
| } | ||||
|  | ||||
| func (d *devicesController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := os.MkdirAll(d.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, device := range resources.Devices { | ||||
| 		file := denyDeviceFile | ||||
| 		if device.Allow { | ||||
| 			file = allowDeviceFile | ||||
| 		} | ||||
| 		if device.Type == "" { | ||||
| 			device.Type = "a" | ||||
| 		} | ||||
| 		if err := retryingWriteFile( | ||||
| 			filepath.Join(d.Path(path), file), | ||||
| 			[]byte(deviceString(device)), | ||||
| 			defaultFilePerm, | ||||
| 		); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (d *devicesController) Update(path string, resources *specs.LinuxResources) error { | ||||
| 	return d.Create(path, resources) | ||||
| } | ||||
|  | ||||
| func deviceString(device specs.LinuxDeviceCgroup) string { | ||||
| 	return fmt.Sprintf("%s %s:%s %s", | ||||
| 		device.Type, | ||||
| 		deviceNumber(device.Major), | ||||
| 		deviceNumber(device.Minor), | ||||
| 		device.Access, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func deviceNumber(number *int64) string { | ||||
| 	if number == nil || *number == wildcard { | ||||
| 		return "*" | ||||
| 	} | ||||
| 	return fmt.Sprint(*number) | ||||
| } | ||||
							
								
								
									
										47
									
								
								vendor/github.com/containerd/cgroups/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								vendor/github.com/containerd/cgroups/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,47 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"errors" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	ErrInvalidPid               = errors.New("cgroups: pid must be greater than 0") | ||||
| 	ErrMountPointNotExist       = errors.New("cgroups: cgroup mountpoint does not exist") | ||||
| 	ErrInvalidFormat            = errors.New("cgroups: parsing file with invalid format failed") | ||||
| 	ErrFreezerNotSupported      = errors.New("cgroups: freezer cgroup not supported on this system") | ||||
| 	ErrMemoryNotSupported       = errors.New("cgroups: memory cgroup not supported on this system") | ||||
| 	ErrCgroupDeleted            = errors.New("cgroups: cgroup deleted") | ||||
| 	ErrNoCgroupMountDestination = errors.New("cgroups: cannot find cgroup mount destination") | ||||
| ) | ||||
|  | ||||
| // ErrorHandler is a function that handles and acts on errors | ||||
| type ErrorHandler func(err error) error | ||||
|  | ||||
| // IgnoreNotExist ignores any errors that are for not existing files | ||||
| func IgnoreNotExist(err error) error { | ||||
| 	if os.IsNotExist(err) { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func errPassthrough(err error) error { | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										82
									
								
								vendor/github.com/containerd/cgroups/freezer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/containerd/cgroups/freezer.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,82 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func NewFreezer(root string) *freezerController { | ||||
| 	return &freezerController{ | ||||
| 		root: filepath.Join(root, string(Freezer)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type freezerController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (f *freezerController) Name() Name { | ||||
| 	return Freezer | ||||
| } | ||||
|  | ||||
| func (f *freezerController) Path(path string) string { | ||||
| 	return filepath.Join(f.root, path) | ||||
| } | ||||
|  | ||||
| func (f *freezerController) Freeze(path string) error { | ||||
| 	return f.waitState(path, Frozen) | ||||
| } | ||||
|  | ||||
| func (f *freezerController) Thaw(path string) error { | ||||
| 	return f.waitState(path, Thawed) | ||||
| } | ||||
|  | ||||
| func (f *freezerController) changeState(path string, state State) error { | ||||
| 	return retryingWriteFile( | ||||
| 		filepath.Join(f.root, path, "freezer.state"), | ||||
| 		[]byte(strings.ToUpper(string(state))), | ||||
| 		defaultFilePerm, | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func (f *freezerController) state(path string) (State, error) { | ||||
| 	current, err := os.ReadFile(filepath.Join(f.root, path, "freezer.state")) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return State(strings.ToLower(strings.TrimSpace(string(current)))), nil | ||||
| } | ||||
|  | ||||
| func (f *freezerController) waitState(path string, state State) error { | ||||
| 	for { | ||||
| 		if err := f.changeState(path, state); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		current, err := f.state(path) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if current == state { | ||||
| 			return nil | ||||
| 		} | ||||
| 		time.Sleep(1 * time.Millisecond) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										20
									
								
								vendor/github.com/containerd/cgroups/hierarchy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/containerd/cgroups/hierarchy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,20 +0,0 @@ | ||||
| /* | ||||
|    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 | ||||
|  | ||||
| // Hierarchy enables both unified and split hierarchy for cgroups | ||||
| type Hierarchy func() ([]Subsystem, error) | ||||
							
								
								
									
										109
									
								
								vendor/github.com/containerd/cgroups/hugetlb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										109
									
								
								vendor/github.com/containerd/cgroups/hugetlb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,109 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| func NewHugetlb(root string) (*hugetlbController, error) { | ||||
| 	sizes, err := hugePageSizes() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &hugetlbController{ | ||||
| 		root:  filepath.Join(root, string(Hugetlb)), | ||||
| 		sizes: sizes, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| type hugetlbController struct { | ||||
| 	root  string | ||||
| 	sizes []string | ||||
| } | ||||
|  | ||||
| func (h *hugetlbController) Name() Name { | ||||
| 	return Hugetlb | ||||
| } | ||||
|  | ||||
| func (h *hugetlbController) Path(path string) string { | ||||
| 	return filepath.Join(h.root, path) | ||||
| } | ||||
|  | ||||
| func (h *hugetlbController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := os.MkdirAll(h.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, limit := range resources.HugepageLimits { | ||||
| 		if err := retryingWriteFile( | ||||
| 			filepath.Join(h.Path(path), strings.Join([]string{"hugetlb", limit.Pagesize, "limit_in_bytes"}, ".")), | ||||
| 			[]byte(strconv.FormatUint(limit.Limit, 10)), | ||||
| 			defaultFilePerm, | ||||
| 		); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (h *hugetlbController) Stat(path string, stats *v1.Metrics) error { | ||||
| 	for _, size := range h.sizes { | ||||
| 		s, err := h.readSizeStat(path, size) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		stats.Hugetlb = append(stats.Hugetlb, s) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (h *hugetlbController) readSizeStat(path, size string) (*v1.HugetlbStat, error) { | ||||
| 	s := v1.HugetlbStat{ | ||||
| 		Pagesize: size, | ||||
| 	} | ||||
| 	for _, t := range []struct { | ||||
| 		name  string | ||||
| 		value *uint64 | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:  "usage_in_bytes", | ||||
| 			value: &s.Usage, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "max_usage_in_bytes", | ||||
| 			value: &s.Max, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "failcnt", | ||||
| 			value: &s.Failcnt, | ||||
| 		}, | ||||
| 	} { | ||||
| 		v, err := readUint(filepath.Join(h.Path(path), strings.Join([]string{"hugetlb", size, t.name}, "."))) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		*t.value = v | ||||
| 	} | ||||
| 	return &s, nil | ||||
| } | ||||
							
								
								
									
										480
									
								
								vendor/github.com/containerd/cgroups/memory.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										480
									
								
								vendor/github.com/containerd/cgroups/memory.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,480 +0,0 @@ | ||||
| /* | ||||
|    Copyright The containerd Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package cgroups | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| 	"golang.org/x/sys/unix" | ||||
| ) | ||||
|  | ||||
| // MemoryEvent is an interface that V1 memory Cgroup notifications implement. Arg returns the | ||||
| // file name whose fd should be written to "cgroups.event_control". EventFile returns the name of | ||||
| // the file that supports the notification api e.g. "memory.usage_in_bytes". | ||||
| type MemoryEvent interface { | ||||
| 	Arg() string | ||||
| 	EventFile() string | ||||
| } | ||||
|  | ||||
| type memoryThresholdEvent struct { | ||||
| 	threshold uint64 | ||||
| 	swap      bool | ||||
| } | ||||
|  | ||||
| // MemoryThresholdEvent returns a new memory threshold event to be used with RegisterMemoryEvent. | ||||
| // If swap is true, the event will be registered using memory.memsw.usage_in_bytes | ||||
| func MemoryThresholdEvent(threshold uint64, swap bool) MemoryEvent { | ||||
| 	return &memoryThresholdEvent{ | ||||
| 		threshold, | ||||
| 		swap, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *memoryThresholdEvent) Arg() string { | ||||
| 	return strconv.FormatUint(m.threshold, 10) | ||||
| } | ||||
|  | ||||
| func (m *memoryThresholdEvent) EventFile() string { | ||||
| 	if m.swap { | ||||
| 		return "memory.memsw.usage_in_bytes" | ||||
| 	} | ||||
| 	return "memory.usage_in_bytes" | ||||
| } | ||||
|  | ||||
| type oomEvent struct{} | ||||
|  | ||||
| // OOMEvent returns a new oom event to be used with RegisterMemoryEvent. | ||||
| func OOMEvent() MemoryEvent { | ||||
| 	return &oomEvent{} | ||||
| } | ||||
|  | ||||
| func (oom *oomEvent) Arg() string { | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (oom *oomEvent) EventFile() string { | ||||
| 	return "memory.oom_control" | ||||
| } | ||||
|  | ||||
| type memoryPressureEvent struct { | ||||
| 	pressureLevel MemoryPressureLevel | ||||
| 	hierarchy     EventNotificationMode | ||||
| } | ||||
|  | ||||
| // MemoryPressureEvent returns a new memory pressure event to be used with RegisterMemoryEvent. | ||||
| func MemoryPressureEvent(pressureLevel MemoryPressureLevel, hierarchy EventNotificationMode) MemoryEvent { | ||||
| 	return &memoryPressureEvent{ | ||||
| 		pressureLevel, | ||||
| 		hierarchy, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *memoryPressureEvent) Arg() string { | ||||
| 	return string(m.pressureLevel) + "," + string(m.hierarchy) | ||||
| } | ||||
|  | ||||
| func (m *memoryPressureEvent) EventFile() string { | ||||
| 	return "memory.pressure_level" | ||||
| } | ||||
|  | ||||
| // MemoryPressureLevel corresponds to the memory pressure levels defined | ||||
| // for memory cgroups. | ||||
| 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 | ||||
| const ( | ||||
| 	LowPressure      MemoryPressureLevel = "low" | ||||
| 	MediumPressure   MemoryPressureLevel = "medium" | ||||
| 	CriticalPressure MemoryPressureLevel = "critical" | ||||
| ) | ||||
|  | ||||
| // EventNotificationMode corresponds to the notification modes | ||||
| // for the memory cgroups pressure level notifications. | ||||
| 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 | ||||
| const ( | ||||
| 	DefaultMode   EventNotificationMode = "default" | ||||
| 	LocalMode     EventNotificationMode = "local" | ||||
| 	HierarchyMode EventNotificationMode = "hierarchy" | ||||
| ) | ||||
|  | ||||
| // NewMemory returns a Memory controller given the root folder of cgroups. | ||||
| // It may optionally accept other configuration options, such as IgnoreModules(...) | ||||
| func NewMemory(root string, options ...func(*memoryController)) *memoryController { | ||||
| 	mc := &memoryController{ | ||||
| 		root:    filepath.Join(root, string(Memory)), | ||||
| 		ignored: map[string]struct{}{}, | ||||
| 	} | ||||
| 	for _, opt := range options { | ||||
| 		opt(mc) | ||||
| 	} | ||||
| 	return mc | ||||
| } | ||||
|  | ||||
| // IgnoreModules configure the memory controller to not read memory metrics for some | ||||
| // module names (e.g. passing "memsw" would avoid all the memory.memsw.* entries) | ||||
| func IgnoreModules(names ...string) func(*memoryController) { | ||||
| 	return func(mc *memoryController) { | ||||
| 		for _, name := range names { | ||||
| 			mc.ignored[name] = struct{}{} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // OptionalSwap allows the memory controller to not fail if cgroups is not accounting | ||||
| // Swap memory (there are no memory.memsw.* entries) | ||||
| func OptionalSwap() func(*memoryController) { | ||||
| 	return func(mc *memoryController) { | ||||
| 		_, err := os.Stat(filepath.Join(mc.root, "memory.memsw.usage_in_bytes")) | ||||
| 		if os.IsNotExist(err) { | ||||
| 			mc.ignored["memsw"] = struct{}{} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type memoryController struct { | ||||
| 	root    string | ||||
| 	ignored map[string]struct{} | ||||
| } | ||||
|  | ||||
| func (m *memoryController) Name() Name { | ||||
| 	return Memory | ||||
| } | ||||
|  | ||||
| func (m *memoryController) Path(path string) string { | ||||
| 	return filepath.Join(m.root, path) | ||||
| } | ||||
|  | ||||
| func (m *memoryController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := os.MkdirAll(m.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if resources.Memory == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return m.set(path, getMemorySettings(resources)) | ||||
| } | ||||
|  | ||||
| func (m *memoryController) Update(path string, resources *specs.LinuxResources) error { | ||||
| 	if resources.Memory == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	g := func(v *int64) bool { | ||||
| 		return v != nil && *v > 0 | ||||
| 	} | ||||
| 	settings := getMemorySettings(resources) | ||||
| 	if g(resources.Memory.Limit) && g(resources.Memory.Swap) { | ||||
| 		// if the updated swap value is larger than the current memory limit set the swap changes first | ||||
| 		// then set the memory limit as swap must always be larger than the current limit | ||||
| 		current, err := readUint(filepath.Join(m.Path(path), "memory.limit_in_bytes")) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if current < uint64(*resources.Memory.Swap) { | ||||
| 			settings[0], settings[1] = settings[1], settings[0] | ||||
| 		} | ||||
| 	} | ||||
| 	return m.set(path, settings) | ||||
| } | ||||
|  | ||||
| func (m *memoryController) Stat(path string, stats *v1.Metrics) error { | ||||
| 	fMemStat, err := os.Open(filepath.Join(m.Path(path), "memory.stat")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer fMemStat.Close() | ||||
| 	stats.Memory = &v1.MemoryStat{ | ||||
| 		Usage:     &v1.MemoryEntry{}, | ||||
| 		Swap:      &v1.MemoryEntry{}, | ||||
| 		Kernel:    &v1.MemoryEntry{}, | ||||
| 		KernelTCP: &v1.MemoryEntry{}, | ||||
| 	} | ||||
| 	if err := m.parseStats(fMemStat, stats.Memory); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	fMemOomControl, err := os.Open(filepath.Join(m.Path(path), "memory.oom_control")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer fMemOomControl.Close() | ||||
| 	stats.MemoryOomControl = &v1.MemoryOomControl{} | ||||
| 	if err := m.parseOomControlStats(fMemOomControl, stats.MemoryOomControl); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for _, t := range []struct { | ||||
| 		module string | ||||
| 		entry  *v1.MemoryEntry | ||||
| 	}{ | ||||
| 		{ | ||||
| 			module: "", | ||||
| 			entry:  stats.Memory.Usage, | ||||
| 		}, | ||||
| 		{ | ||||
| 			module: "memsw", | ||||
| 			entry:  stats.Memory.Swap, | ||||
| 		}, | ||||
| 		{ | ||||
| 			module: "kmem", | ||||
| 			entry:  stats.Memory.Kernel, | ||||
| 		}, | ||||
| 		{ | ||||
| 			module: "kmem.tcp", | ||||
| 			entry:  stats.Memory.KernelTCP, | ||||
| 		}, | ||||
| 	} { | ||||
| 		if _, ok := m.ignored[t.module]; ok { | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, tt := range []struct { | ||||
| 			name  string | ||||
| 			value *uint64 | ||||
| 		}{ | ||||
| 			{ | ||||
| 				name:  "usage_in_bytes", | ||||
| 				value: &t.entry.Usage, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "max_usage_in_bytes", | ||||
| 				value: &t.entry.Max, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "failcnt", | ||||
| 				value: &t.entry.Failcnt, | ||||
| 			}, | ||||
| 			{ | ||||
| 				name:  "limit_in_bytes", | ||||
| 				value: &t.entry.Limit, | ||||
| 			}, | ||||
| 		} { | ||||
| 			parts := []string{"memory"} | ||||
| 			if t.module != "" { | ||||
| 				parts = append(parts, t.module) | ||||
| 			} | ||||
| 			parts = append(parts, tt.name) | ||||
| 			v, err := readUint(filepath.Join(m.Path(path), strings.Join(parts, "."))) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			*tt.value = v | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *memoryController) parseStats(r io.Reader, stat *v1.MemoryStat) error { | ||||
| 	var ( | ||||
| 		raw  = make(map[string]uint64) | ||||
| 		sc   = bufio.NewScanner(r) | ||||
| 		line int | ||||
| 	) | ||||
| 	for sc.Scan() { | ||||
| 		key, v, err := parseKV(sc.Text()) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("%d: %v", line, err) | ||||
| 		} | ||||
| 		raw[key] = v | ||||
| 		line++ | ||||
| 	} | ||||
| 	if err := sc.Err(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	stat.Cache = raw["cache"] | ||||
| 	stat.RSS = raw["rss"] | ||||
| 	stat.RSSHuge = raw["rss_huge"] | ||||
| 	stat.MappedFile = raw["mapped_file"] | ||||
| 	stat.Dirty = raw["dirty"] | ||||
| 	stat.Writeback = raw["writeback"] | ||||
| 	stat.PgPgIn = raw["pgpgin"] | ||||
| 	stat.PgPgOut = raw["pgpgout"] | ||||
| 	stat.PgFault = raw["pgfault"] | ||||
| 	stat.PgMajFault = raw["pgmajfault"] | ||||
| 	stat.InactiveAnon = raw["inactive_anon"] | ||||
| 	stat.ActiveAnon = raw["active_anon"] | ||||
| 	stat.InactiveFile = raw["inactive_file"] | ||||
| 	stat.ActiveFile = raw["active_file"] | ||||
| 	stat.Unevictable = raw["unevictable"] | ||||
| 	stat.HierarchicalMemoryLimit = raw["hierarchical_memory_limit"] | ||||
| 	stat.HierarchicalSwapLimit = raw["hierarchical_memsw_limit"] | ||||
| 	stat.TotalCache = raw["total_cache"] | ||||
| 	stat.TotalRSS = raw["total_rss"] | ||||
| 	stat.TotalRSSHuge = raw["total_rss_huge"] | ||||
| 	stat.TotalMappedFile = raw["total_mapped_file"] | ||||
| 	stat.TotalDirty = raw["total_dirty"] | ||||
| 	stat.TotalWriteback = raw["total_writeback"] | ||||
| 	stat.TotalPgPgIn = raw["total_pgpgin"] | ||||
| 	stat.TotalPgPgOut = raw["total_pgpgout"] | ||||
| 	stat.TotalPgFault = raw["total_pgfault"] | ||||
| 	stat.TotalPgMajFault = raw["total_pgmajfault"] | ||||
| 	stat.TotalInactiveAnon = raw["total_inactive_anon"] | ||||
| 	stat.TotalActiveAnon = raw["total_active_anon"] | ||||
| 	stat.TotalInactiveFile = raw["total_inactive_file"] | ||||
| 	stat.TotalActiveFile = raw["total_active_file"] | ||||
| 	stat.TotalUnevictable = raw["total_unevictable"] | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *memoryController) parseOomControlStats(r io.Reader, stat *v1.MemoryOomControl) error { | ||||
| 	var ( | ||||
| 		raw  = make(map[string]uint64) | ||||
| 		sc   = bufio.NewScanner(r) | ||||
| 		line int | ||||
| 	) | ||||
| 	for sc.Scan() { | ||||
| 		key, v, err := parseKV(sc.Text()) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("%d: %v", line, err) | ||||
| 		} | ||||
| 		raw[key] = v | ||||
| 		line++ | ||||
| 	} | ||||
| 	if err := sc.Err(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	stat.OomKillDisable = raw["oom_kill_disable"] | ||||
| 	stat.UnderOom = raw["under_oom"] | ||||
| 	stat.OomKill = raw["oom_kill"] | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *memoryController) set(path string, settings []memorySettings) error { | ||||
| 	for _, t := range settings { | ||||
| 		if t.value != nil { | ||||
| 			if err := retryingWriteFile( | ||||
| 				filepath.Join(m.Path(path), "memory."+t.name), | ||||
| 				[]byte(strconv.FormatInt(*t.value, 10)), | ||||
| 				defaultFilePerm, | ||||
| 			); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type memorySettings struct { | ||||
| 	name  string | ||||
| 	value *int64 | ||||
| } | ||||
|  | ||||
| func getMemorySettings(resources *specs.LinuxResources) []memorySettings { | ||||
| 	mem := resources.Memory | ||||
| 	var swappiness *int64 | ||||
| 	if mem.Swappiness != nil { | ||||
| 		v := int64(*mem.Swappiness) | ||||
| 		swappiness = &v | ||||
| 	} | ||||
| 	return []memorySettings{ | ||||
| 		{ | ||||
| 			name:  "limit_in_bytes", | ||||
| 			value: mem.Limit, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "soft_limit_in_bytes", | ||||
| 			value: mem.Reservation, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "memsw.limit_in_bytes", | ||||
| 			value: mem.Swap, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "kmem.limit_in_bytes", | ||||
| 			value: mem.Kernel, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "kmem.tcp.limit_in_bytes", | ||||
| 			value: mem.KernelTCP, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "oom_control", | ||||
| 			value: getOomControlValue(mem), | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:  "swappiness", | ||||
| 			value: swappiness, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getOomControlValue(mem *specs.LinuxMemory) *int64 { | ||||
| 	if mem.DisableOOMKiller != nil && *mem.DisableOOMKiller { | ||||
| 		i := int64(1) | ||||
| 		return &i | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *memoryController) memoryEvent(path string, event MemoryEvent) (uintptr, error) { | ||||
| 	root := m.Path(path) | ||||
| 	efd, err := unix.Eventfd(0, unix.EFD_CLOEXEC) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	evtFile, err := os.Open(filepath.Join(root, event.EventFile())) | ||||
| 	if err != nil { | ||||
| 		unix.Close(efd) | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	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 { | ||||
| 		unix.Close(efd) | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return uintptr(efd), nil | ||||
| } | ||||
							
								
								
									
										39
									
								
								vendor/github.com/containerd/cgroups/named.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/containerd/cgroups/named.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,39 +0,0 @@ | ||||
| /* | ||||
|    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 "path/filepath" | ||||
|  | ||||
| func NewNamed(root string, name Name) *namedController { | ||||
| 	return &namedController{ | ||||
| 		root: root, | ||||
| 		name: name, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type namedController struct { | ||||
| 	root string | ||||
| 	name Name | ||||
| } | ||||
|  | ||||
| func (n *namedController) Name() Name { | ||||
| 	return n.name | ||||
| } | ||||
|  | ||||
| func (n *namedController) Path(path string) string { | ||||
| 	return filepath.Join(n.root, string(n.name), path) | ||||
| } | ||||
							
								
								
									
										61
									
								
								vendor/github.com/containerd/cgroups/net_cls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										61
									
								
								vendor/github.com/containerd/cgroups/net_cls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,61 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
|  | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| func NewNetCls(root string) *netclsController { | ||||
| 	return &netclsController{ | ||||
| 		root: filepath.Join(root, string(NetCLS)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type netclsController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (n *netclsController) Name() Name { | ||||
| 	return NetCLS | ||||
| } | ||||
|  | ||||
| func (n *netclsController) Path(path string) string { | ||||
| 	return filepath.Join(n.root, path) | ||||
| } | ||||
|  | ||||
| func (n *netclsController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := os.MkdirAll(n.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if resources.Network != nil && resources.Network.ClassID != nil && *resources.Network.ClassID > 0 { | ||||
| 		return retryingWriteFile( | ||||
| 			filepath.Join(n.Path(path), "net_cls.classid"), | ||||
| 			[]byte(strconv.FormatUint(uint64(*resources.Network.ClassID), 10)), | ||||
| 			defaultFilePerm, | ||||
| 		) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (n *netclsController) Update(path string, resources *specs.LinuxResources) error { | ||||
| 	return n.Create(path, resources) | ||||
| } | ||||
							
								
								
									
										65
									
								
								vendor/github.com/containerd/cgroups/net_prio.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/containerd/cgroups/net_prio.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,65 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| func NewNetPrio(root string) *netprioController { | ||||
| 	return &netprioController{ | ||||
| 		root: filepath.Join(root, string(NetPrio)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type netprioController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (n *netprioController) Name() Name { | ||||
| 	return NetPrio | ||||
| } | ||||
|  | ||||
| func (n *netprioController) Path(path string) string { | ||||
| 	return filepath.Join(n.root, path) | ||||
| } | ||||
|  | ||||
| func (n *netprioController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := os.MkdirAll(n.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if resources.Network != nil { | ||||
| 		for _, prio := range resources.Network.Priorities { | ||||
| 			if err := retryingWriteFile( | ||||
| 				filepath.Join(n.Path(path), "net_prio.ifpriomap"), | ||||
| 				formatPrio(prio.Name, prio.Priority), | ||||
| 				defaultFilePerm, | ||||
| 			); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func formatPrio(name string, prio uint32) []byte { | ||||
| 	return []byte(fmt.Sprintf("%s %d", name, prio)) | ||||
| } | ||||
							
								
								
									
										61
									
								
								vendor/github.com/containerd/cgroups/opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										61
									
								
								vendor/github.com/containerd/cgroups/opts.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,61 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"errors" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// ErrIgnoreSubsystem allows the specific subsystem to be skipped | ||||
| 	ErrIgnoreSubsystem = errors.New("skip subsystem") | ||||
| 	// ErrDevicesRequired is returned when the devices subsystem is required but | ||||
| 	// does not exist or is not active | ||||
| 	ErrDevicesRequired = errors.New("devices subsystem is required") | ||||
| ) | ||||
|  | ||||
| // InitOpts allows configuration for the creation or loading of a cgroup | ||||
| type InitOpts func(*InitConfig) error | ||||
|  | ||||
| // InitConfig provides configuration options for the creation | ||||
| // or loading of a cgroup and its subsystems | ||||
| type InitConfig struct { | ||||
| 	// InitCheck can be used to check initialization errors from the subsystem | ||||
| 	InitCheck InitCheck | ||||
| } | ||||
|  | ||||
| func newInitConfig() *InitConfig { | ||||
| 	return &InitConfig{ | ||||
| 		InitCheck: RequireDevices, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // InitCheck allows subsystems errors to be checked when initialized or loaded | ||||
| type InitCheck func(Subsystem, Path, error) error | ||||
|  | ||||
| // AllowAny allows any subsystem errors to be skipped | ||||
| func AllowAny(_ Subsystem, _ Path, _ error) error { | ||||
| 	return ErrIgnoreSubsystem | ||||
| } | ||||
|  | ||||
| // RequireDevices requires the device subsystem but no others | ||||
| func RequireDevices(s Subsystem, _ Path, _ error) error { | ||||
| 	if s.Name() == Devices { | ||||
| 		return ErrDevicesRequired | ||||
| 	} | ||||
| 	return ErrIgnoreSubsystem | ||||
| } | ||||
							
								
								
									
										106
									
								
								vendor/github.com/containerd/cgroups/paths.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										106
									
								
								vendor/github.com/containerd/cgroups/paths.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,106 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| ) | ||||
|  | ||||
| type Path func(subsystem Name) (string, error) | ||||
|  | ||||
| func RootPath(subsystem Name) (string, error) { | ||||
| 	return "/", nil | ||||
| } | ||||
|  | ||||
| // StaticPath returns a static path to use for all cgroups | ||||
| func StaticPath(path string) Path { | ||||
| 	return func(_ Name) (string, error) { | ||||
| 		return path, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NestedPath will nest the cgroups based on the calling processes cgroup | ||||
| // placing its child processes inside its own path | ||||
| func NestedPath(suffix string) Path { | ||||
| 	paths, err := ParseCgroupFile("/proc/self/cgroup") | ||||
| 	if err != nil { | ||||
| 		return errorPath(err) | ||||
| 	} | ||||
| 	return existingPath(paths, suffix) | ||||
| } | ||||
|  | ||||
| // PidPath will return the correct cgroup paths for an existing process running inside a cgroup | ||||
| // This is commonly used for the Load function to restore an existing container | ||||
| func PidPath(pid int) Path { | ||||
| 	p := fmt.Sprintf("/proc/%d/cgroup", pid) | ||||
| 	paths, err := ParseCgroupFile(p) | ||||
| 	if err != nil { | ||||
| 		return errorPath(fmt.Errorf("parse cgroup file %s: %w", p, err)) | ||||
| 	} | ||||
| 	return existingPath(paths, "") | ||||
| } | ||||
|  | ||||
| // ErrControllerNotActive is returned when a controller is not supported or enabled | ||||
| var ErrControllerNotActive = errors.New("controller is not supported") | ||||
|  | ||||
| func existingPath(paths map[string]string, suffix string) Path { | ||||
| 	// localize the paths based on the root mount dest for nested cgroups | ||||
| 	for n, p := range paths { | ||||
| 		dest, err := getCgroupDestination(n) | ||||
| 		if err != nil { | ||||
| 			return errorPath(err) | ||||
| 		} | ||||
| 		rel, err := filepath.Rel(dest, p) | ||||
| 		if err != nil { | ||||
| 			return errorPath(err) | ||||
| 		} | ||||
| 		if rel == "." { | ||||
| 			rel = dest | ||||
| 		} | ||||
| 		paths[n] = filepath.Join("/", rel) | ||||
| 	} | ||||
| 	return func(name Name) (string, error) { | ||||
| 		root, ok := paths[string(name)] | ||||
| 		if !ok { | ||||
| 			if root, ok = paths["name="+string(name)]; !ok { | ||||
| 				return "", ErrControllerNotActive | ||||
| 			} | ||||
| 		} | ||||
| 		if suffix != "" { | ||||
| 			return filepath.Join(root, suffix), nil | ||||
| 		} | ||||
| 		return root, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func subPath(path Path, subName string) Path { | ||||
| 	return func(name Name) (string, error) { | ||||
| 		p, err := path(name) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return filepath.Join(p, subName), nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func errorPath(err error) Path { | ||||
| 	return func(_ Name) (string, error) { | ||||
| 		return "", err | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										37
									
								
								vendor/github.com/containerd/cgroups/perf_event.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										37
									
								
								vendor/github.com/containerd/cgroups/perf_event.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,37 +0,0 @@ | ||||
| /* | ||||
|    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 "path/filepath" | ||||
|  | ||||
| func NewPerfEvent(root string) *PerfEventController { | ||||
| 	return &PerfEventController{ | ||||
| 		root: filepath.Join(root, string(PerfEvent)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type PerfEventController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (p *PerfEventController) Name() Name { | ||||
| 	return PerfEvent | ||||
| } | ||||
|  | ||||
| func (p *PerfEventController) Path(path string) string { | ||||
| 	return filepath.Join(p.root, path) | ||||
| } | ||||
							
								
								
									
										85
									
								
								vendor/github.com/containerd/cgroups/pids.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										85
									
								
								vendor/github.com/containerd/cgroups/pids.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,85 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| func NewPids(root string) *pidsController { | ||||
| 	return &pidsController{ | ||||
| 		root: filepath.Join(root, string(Pids)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type pidsController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (p *pidsController) Name() Name { | ||||
| 	return Pids | ||||
| } | ||||
|  | ||||
| func (p *pidsController) Path(path string) string { | ||||
| 	return filepath.Join(p.root, path) | ||||
| } | ||||
|  | ||||
| func (p *pidsController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := os.MkdirAll(p.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if resources.Pids != nil && resources.Pids.Limit > 0 { | ||||
| 		return retryingWriteFile( | ||||
| 			filepath.Join(p.Path(path), "pids.max"), | ||||
| 			[]byte(strconv.FormatInt(resources.Pids.Limit, 10)), | ||||
| 			defaultFilePerm, | ||||
| 		) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *pidsController) Update(path string, resources *specs.LinuxResources) error { | ||||
| 	return p.Create(path, resources) | ||||
| } | ||||
|  | ||||
| func (p *pidsController) Stat(path string, stats *v1.Metrics) error { | ||||
| 	current, err := readUint(filepath.Join(p.Path(path), "pids.current")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	var max uint64 | ||||
| 	maxData, err := os.ReadFile(filepath.Join(p.Path(path), "pids.max")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if maxS := strings.TrimSpace(string(maxData)); maxS != "max" { | ||||
| 		if max, err = parseUint(maxS, 10, 64); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	stats.Pids = &v1.PidsStat{ | ||||
| 		Current: current, | ||||
| 		Limit:   max, | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										154
									
								
								vendor/github.com/containerd/cgroups/rdma.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										154
									
								
								vendor/github.com/containerd/cgroups/rdma.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,154 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"math" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| type rdmaController struct { | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (p *rdmaController) Name() Name { | ||||
| 	return Rdma | ||||
| } | ||||
|  | ||||
| func (p *rdmaController) Path(path string) string { | ||||
| 	return filepath.Join(p.root, path) | ||||
| } | ||||
|  | ||||
| func NewRdma(root string) *rdmaController { | ||||
| 	return &rdmaController{ | ||||
| 		root: filepath.Join(root, string(Rdma)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func createCmdString(device string, limits *specs.LinuxRdma) string { | ||||
| 	var cmdString string | ||||
|  | ||||
| 	cmdString = device | ||||
| 	if limits.HcaHandles != nil { | ||||
| 		cmdString = cmdString + " " + "hca_handle=" + strconv.FormatUint(uint64(*limits.HcaHandles), 10) | ||||
| 	} | ||||
|  | ||||
| 	if limits.HcaObjects != nil { | ||||
| 		cmdString = cmdString + " " + "hca_object=" + strconv.FormatUint(uint64(*limits.HcaObjects), 10) | ||||
| 	} | ||||
| 	return cmdString | ||||
| } | ||||
|  | ||||
| func (p *rdmaController) Create(path string, resources *specs.LinuxResources) error { | ||||
| 	if err := os.MkdirAll(p.Path(path), defaultDirPerm); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	for device, limit := range resources.Rdma { | ||||
| 		if device != "" && (limit.HcaHandles != nil || limit.HcaObjects != nil) { | ||||
| 			limit := limit | ||||
| 			return retryingWriteFile( | ||||
| 				filepath.Join(p.Path(path), "rdma.max"), | ||||
| 				[]byte(createCmdString(device, &limit)), | ||||
| 				defaultFilePerm, | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *rdmaController) Update(path string, resources *specs.LinuxResources) error { | ||||
| 	return p.Create(path, resources) | ||||
| } | ||||
|  | ||||
| func parseRdmaKV(raw string, entry *v1.RdmaEntry) { | ||||
| 	var value uint64 | ||||
| 	var err error | ||||
|  | ||||
| 	parts := strings.Split(raw, "=") | ||||
| 	switch len(parts) { | ||||
| 	case 2: | ||||
| 		if parts[1] == "max" { | ||||
| 			value = math.MaxUint32 | ||||
| 		} else { | ||||
| 			value, err = parseUint(parts[1], 10, 32) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 		if parts[0] == "hca_handle" { | ||||
| 			entry.HcaHandles = uint32(value) | ||||
| 		} else if parts[0] == "hca_object" { | ||||
| 			entry.HcaObjects = uint32(value) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func toRdmaEntry(strEntries []string) []*v1.RdmaEntry { | ||||
| 	var rdmaEntries []*v1.RdmaEntry | ||||
| 	for i := range strEntries { | ||||
| 		parts := strings.Fields(strEntries[i]) | ||||
| 		switch len(parts) { | ||||
| 		case 3: | ||||
| 			entry := new(v1.RdmaEntry) | ||||
| 			entry.Device = parts[0] | ||||
| 			parseRdmaKV(parts[1], entry) | ||||
| 			parseRdmaKV(parts[2], entry) | ||||
|  | ||||
| 			rdmaEntries = append(rdmaEntries, entry) | ||||
| 		default: | ||||
| 			continue | ||||
| 		} | ||||
| 	} | ||||
| 	return rdmaEntries | ||||
| } | ||||
|  | ||||
| func (p *rdmaController) Stat(path string, stats *v1.Metrics) error { | ||||
|  | ||||
| 	currentData, err := os.ReadFile(filepath.Join(p.Path(path), "rdma.current")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	currentPerDevices := strings.Split(string(currentData), "\n") | ||||
|  | ||||
| 	maxData, err := os.ReadFile(filepath.Join(p.Path(path), "rdma.max")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	maxPerDevices := strings.Split(string(maxData), "\n") | ||||
|  | ||||
| 	// If device got removed between reading two files, ignore returning | ||||
| 	// stats. | ||||
| 	if len(currentPerDevices) != len(maxPerDevices) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	currentEntries := toRdmaEntry(currentPerDevices) | ||||
| 	maxEntries := toRdmaEntry(maxPerDevices) | ||||
|  | ||||
| 	stats.Rdma = &v1.RdmaStat{ | ||||
| 		Current: currentEntries, | ||||
| 		Limit:   maxEntries, | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										28
									
								
								vendor/github.com/containerd/cgroups/state.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/containerd/cgroups/state.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,28 +0,0 @@ | ||||
| /* | ||||
|    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 | ||||
|  | ||||
| // State is a type that represents the state of the current cgroup | ||||
| type State string | ||||
|  | ||||
| const ( | ||||
| 	Unknown  State = "" | ||||
| 	Thawed   State = "thawed" | ||||
| 	Frozen   State = "frozen" | ||||
| 	Freezing State = "freezing" | ||||
| 	Deleted  State = "deleted" | ||||
| ) | ||||
							
								
								
									
										17
									
								
								vendor/github.com/containerd/cgroups/stats/v1/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/containerd/cgroups/stats/v1/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,17 +0,0 @@ | ||||
| /* | ||||
|    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 v1 | ||||
							
								
								
									
										6125
									
								
								vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6125
									
								
								vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										790
									
								
								vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										790
									
								
								vendor/github.com/containerd/cgroups/stats/v1/metrics.pb.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,790 +0,0 @@ | ||||
| file { | ||||
|   name: "github.com/containerd/cgroups/stats/v1/metrics.proto" | ||||
|   package: "io.containerd.cgroups.v1" | ||||
|   dependency: "gogoproto/gogo.proto" | ||||
|   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" | ||||
|       options { | ||||
|         65004: "CPU" | ||||
|       } | ||||
|       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 | ||||
|       options { | ||||
|         65004: "PerCPU" | ||||
|       } | ||||
|       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 | ||||
|       options { | ||||
|         65004: "RSS" | ||||
|       } | ||||
|       json_name: "rss" | ||||
|     } | ||||
|     field { | ||||
|       name: "rss_huge" | ||||
|       number: 3 | ||||
|       label: LABEL_OPTIONAL | ||||
|       type: TYPE_UINT64 | ||||
|       options { | ||||
|         65004: "RSSHuge" | ||||
|       } | ||||
|       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 | ||||
|       options { | ||||
|         65004: "TotalRSS" | ||||
|       } | ||||
|       json_name: "totalRss" | ||||
|     } | ||||
|     field { | ||||
|       name: "total_rss_huge" | ||||
|       number: 20 | ||||
|       label: LABEL_OPTIONAL | ||||
|       type: TYPE_UINT64 | ||||
|       options { | ||||
|         65004: "TotalRSSHuge" | ||||
|       } | ||||
|       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" | ||||
|       options { | ||||
|         65004: "KernelTCP" | ||||
|       } | ||||
|       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" | ||||
|     } | ||||
|   } | ||||
|   syntax: "proto3" | ||||
| } | ||||
							
								
								
									
										158
									
								
								vendor/github.com/containerd/cgroups/stats/v1/metrics.proto
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										158
									
								
								vendor/github.com/containerd/cgroups/stats/v1/metrics.proto
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,158 +0,0 @@ | ||||
| syntax = "proto3"; | ||||
|  | ||||
| package io.containerd.cgroups.v1; | ||||
|  | ||||
| import "gogoproto/gogo.proto"; | ||||
|  | ||||
| message Metrics { | ||||
| 	repeated HugetlbStat hugetlb = 1; | ||||
| 	PidsStat pids = 2; | ||||
| 	CPUStat cpu = 3 [(gogoproto.customname) = "CPU"]; | ||||
| 	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 [(gogoproto.customname) = "PerCPU"]; | ||||
|  | ||||
| } | ||||
|  | ||||
| message Throttle { | ||||
| 	uint64 periods = 1; | ||||
| 	uint64 throttled_periods = 2; | ||||
| 	uint64 throttled_time = 3; | ||||
| } | ||||
|  | ||||
| message MemoryStat { | ||||
| 	uint64 cache = 1; | ||||
| 	uint64 rss = 2 [(gogoproto.customname) = "RSS"]; | ||||
| 	uint64 rss_huge = 3 [(gogoproto.customname) = "RSSHuge"]; | ||||
| 	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 [(gogoproto.customname) = "TotalRSS"]; | ||||
| 	uint64 total_rss_huge = 20 [(gogoproto.customname) = "TotalRSSHuge"]; | ||||
| 	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 [(gogoproto.customname) = "KernelTCP"]; | ||||
|  | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
							
								
								
									
										116
									
								
								vendor/github.com/containerd/cgroups/subsystem.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										116
									
								
								vendor/github.com/containerd/cgroups/subsystem.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,116 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
|  | ||||
| 	v1 "github.com/containerd/cgroups/stats/v1" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| // Name is a typed name for a cgroup subsystem | ||||
| type Name string | ||||
|  | ||||
| const ( | ||||
| 	Devices   Name = "devices" | ||||
| 	Hugetlb   Name = "hugetlb" | ||||
| 	Freezer   Name = "freezer" | ||||
| 	Pids      Name = "pids" | ||||
| 	NetCLS    Name = "net_cls" | ||||
| 	NetPrio   Name = "net_prio" | ||||
| 	PerfEvent Name = "perf_event" | ||||
| 	Cpuset    Name = "cpuset" | ||||
| 	Cpu       Name = "cpu" | ||||
| 	Cpuacct   Name = "cpuacct" | ||||
| 	Memory    Name = "memory" | ||||
| 	Blkio     Name = "blkio" | ||||
| 	Rdma      Name = "rdma" | ||||
| ) | ||||
|  | ||||
| // Subsystems returns a complete list of the default cgroups | ||||
| // available on most linux systems | ||||
| func Subsystems() []Name { | ||||
| 	n := []Name{ | ||||
| 		Freezer, | ||||
| 		Pids, | ||||
| 		NetCLS, | ||||
| 		NetPrio, | ||||
| 		PerfEvent, | ||||
| 		Cpuset, | ||||
| 		Cpu, | ||||
| 		Cpuacct, | ||||
| 		Memory, | ||||
| 		Blkio, | ||||
| 		Rdma, | ||||
| 	} | ||||
| 	if !RunningInUserNS() { | ||||
| 		n = append(n, Devices) | ||||
| 	} | ||||
| 	if _, err := os.Stat("/sys/kernel/mm/hugepages"); err == nil { | ||||
| 		n = append(n, Hugetlb) | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| type Subsystem interface { | ||||
| 	Name() Name | ||||
| } | ||||
|  | ||||
| type pather interface { | ||||
| 	Subsystem | ||||
| 	Path(path string) string | ||||
| } | ||||
|  | ||||
| type creator interface { | ||||
| 	Subsystem | ||||
| 	Create(path string, resources *specs.LinuxResources) error | ||||
| } | ||||
|  | ||||
| type deleter interface { | ||||
| 	Subsystem | ||||
| 	Delete(path string) error | ||||
| } | ||||
|  | ||||
| type stater interface { | ||||
| 	Subsystem | ||||
| 	Stat(path string, stats *v1.Metrics) error | ||||
| } | ||||
|  | ||||
| type updater interface { | ||||
| 	Subsystem | ||||
| 	Update(path string, resources *specs.LinuxResources) error | ||||
| } | ||||
|  | ||||
| // SingleSubsystem returns a single cgroup subsystem within the base Hierarchy | ||||
| func SingleSubsystem(baseHierarchy Hierarchy, subsystem Name) Hierarchy { | ||||
| 	return func() ([]Subsystem, error) { | ||||
| 		subsystems, err := baseHierarchy() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		for _, s := range subsystems { | ||||
| 			if s.Name() == subsystem { | ||||
| 				return []Subsystem{ | ||||
| 					s, | ||||
| 				}, nil | ||||
| 			} | ||||
| 		} | ||||
| 		return nil, fmt.Errorf("unable to find subsystem %s", subsystem) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										158
									
								
								vendor/github.com/containerd/cgroups/systemd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										158
									
								
								vendor/github.com/containerd/cgroups/systemd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,158 +0,0 @@ | ||||
| /* | ||||
|    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 ( | ||||
| 	"context" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	systemdDbus "github.com/coreos/go-systemd/v22/dbus" | ||||
| 	"github.com/godbus/dbus/v5" | ||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	SystemdDbus  Name = "systemd" | ||||
| 	defaultSlice      = "system.slice" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	canDelegate bool | ||||
| 	once        sync.Once | ||||
| ) | ||||
|  | ||||
| func Systemd() ([]Subsystem, error) { | ||||
| 	root, err := v1MountPoint() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defaultSubsystems, err := defaults(root) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	s, err := NewSystemd(root) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// make sure the systemd controller is added first | ||||
| 	return append([]Subsystem{s}, defaultSubsystems...), nil | ||||
| } | ||||
|  | ||||
| func Slice(slice, name string) Path { | ||||
| 	if slice == "" { | ||||
| 		slice = defaultSlice | ||||
| 	} | ||||
| 	return func(subsystem Name) (string, error) { | ||||
| 		return filepath.Join(slice, name), nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func NewSystemd(root string) (*SystemdController, error) { | ||||
| 	return &SystemdController{ | ||||
| 		root: root, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| type SystemdController struct { | ||||
| 	mu   sync.Mutex | ||||
| 	root string | ||||
| } | ||||
|  | ||||
| func (s *SystemdController) Name() Name { | ||||
| 	return SystemdDbus | ||||
| } | ||||
|  | ||||
| func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error { | ||||
| 	ctx := context.TODO() | ||||
| 	conn, err := systemdDbus.NewWithContext(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer conn.Close() | ||||
| 	slice, name := splitName(path) | ||||
| 	// We need to see if systemd can handle the delegate property | ||||
| 	// Systemd will return an error if it cannot handle delegate regardless | ||||
| 	// of its bool setting. | ||||
| 	checkDelegate := func() { | ||||
| 		canDelegate = true | ||||
| 		dlSlice := newProperty("Delegate", true) | ||||
| 		if _, err := conn.StartTransientUnitContext(ctx, slice, "testdelegate", []systemdDbus.Property{dlSlice}, nil); err != nil { | ||||
| 			if dbusError, ok := err.(dbus.Error); ok { | ||||
| 				// Starting with systemd v237, Delegate is not even a property of slices anymore, | ||||
| 				// so the D-Bus call fails with "InvalidArgs" error. | ||||
| 				if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") { | ||||
| 					canDelegate = false | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		_, _ = conn.StopUnitContext(ctx, slice, "testDelegate", nil) | ||||
| 	} | ||||
| 	once.Do(checkDelegate) | ||||
| 	properties := []systemdDbus.Property{ | ||||
| 		systemdDbus.PropDescription("cgroup " + name), | ||||
| 		systemdDbus.PropWants(slice), | ||||
| 		newProperty("DefaultDependencies", false), | ||||
| 		newProperty("MemoryAccounting", true), | ||||
| 		newProperty("CPUAccounting", true), | ||||
| 		newProperty("BlockIOAccounting", true), | ||||
| 	} | ||||
|  | ||||
| 	// If we can delegate, we add the property back in | ||||
| 	if canDelegate { | ||||
| 		properties = append(properties, newProperty("Delegate", true)) | ||||
| 	} | ||||
|  | ||||
| 	ch := make(chan string) | ||||
| 	_, err = conn.StartTransientUnitContext(ctx, name, "replace", properties, ch) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	<-ch | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (s *SystemdController) Delete(path string) error { | ||||
| 	ctx := context.TODO() | ||||
| 	conn, err := systemdDbus.NewWithContext(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer conn.Close() | ||||
| 	_, name := splitName(path) | ||||
| 	ch := make(chan string) | ||||
| 	_, err = conn.StopUnitContext(ctx, name, "replace", ch) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	<-ch | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func newProperty(name string, units interface{}) systemdDbus.Property { | ||||
| 	return systemdDbus.Property{ | ||||
| 		Name:  name, | ||||
| 		Value: dbus.MakeVariant(units), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func splitName(path string) (slice string, unit string) { | ||||
| 	slice, unit = filepath.Split(path) | ||||
| 	return strings.TrimSuffix(slice, "/"), unit | ||||
| } | ||||
							
								
								
									
										26
									
								
								vendor/github.com/containerd/cgroups/ticks.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/containerd/cgroups/ticks.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,26 +0,0 @@ | ||||
| /* | ||||
|    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 | ||||
|  | ||||
| func getClockTicks() uint64 { | ||||
| 	// The value comes from `C.sysconf(C._SC_CLK_TCK)`, and | ||||
| 	// on Linux it's a constant which is safe to be hard coded, | ||||
| 	// so we can avoid using cgo here. | ||||
| 	// See https://github.com/containerd/cgroups/pull/12 for | ||||
| 	// more details. | ||||
| 	return 100 | ||||
| } | ||||
							
								
								
									
										391
									
								
								vendor/github.com/containerd/cgroups/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										391
									
								
								vendor/github.com/containerd/cgroups/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,391 +0,0 @@ | ||||
| /* | ||||
|    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" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
|  | ||||
| 	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) | ||||
| 	if err != nil && !os.IsNotExist(err) { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	s := []Subsystem{ | ||||
| 		NewNamed(root, "systemd"), | ||||
| 		NewFreezer(root), | ||||
| 		NewPids(root), | ||||
| 		NewNetCls(root), | ||||
| 		NewNetPrio(root), | ||||
| 		NewPerfEvent(root), | ||||
| 		NewCpuset(root), | ||||
| 		NewCpu(root), | ||||
| 		NewCpuacct(root), | ||||
| 		NewMemory(root), | ||||
| 		NewBlkio(root), | ||||
| 		NewRdma(root), | ||||
| 	} | ||||
| 	// only add the devices cgroup if we are not in a user namespace | ||||
| 	// because modifications are not allowed | ||||
| 	if !RunningInUserNS() { | ||||
| 		s = append(s, NewDevices(root)) | ||||
| 	} | ||||
| 	// add the hugetlb cgroup if error wasn't due to missing hugetlb | ||||
| 	// cgroup support on the host | ||||
| 	if err == nil { | ||||
| 		s = append(s, h) | ||||
| 	} | ||||
| 	return s, nil | ||||
| } | ||||
|  | ||||
| // remove will remove a cgroup path handling EAGAIN and EBUSY errors and | ||||
| // retrying the remove after a exp timeout | ||||
| func remove(path string) error { | ||||
| 	delay := 10 * time.Millisecond | ||||
| 	for i := 0; i < 5; i++ { | ||||
| 		if i != 0 { | ||||
| 			time.Sleep(delay) | ||||
| 			delay *= 2 | ||||
| 		} | ||||
| 		if err := os.RemoveAll(path); err == nil { | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 	return fmt.Errorf("cgroups: unable to remove path %q", path) | ||||
| } | ||||
|  | ||||
| // readPids will read all the pids of processes or tasks in a cgroup by the provided path | ||||
| func readPids(path string, subsystem Name, pType procType) ([]Process, error) { | ||||
| 	f, err := os.Open(filepath.Join(path, pType)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	var ( | ||||
| 		out []Process | ||||
| 		s   = bufio.NewScanner(f) | ||||
| 	) | ||||
| 	for s.Scan() { | ||||
| 		if t := s.Text(); t != "" { | ||||
| 			pid, err := strconv.Atoi(t) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			out = append(out, Process{ | ||||
| 				Pid:       pid, | ||||
| 				Subsystem: subsystem, | ||||
| 				Path:      path, | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| 	if err := s.Err(); err != nil { | ||||
| 		// failed to read all pids? | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return out, nil | ||||
| } | ||||
|  | ||||
| func hugePageSizes() ([]string, error) { | ||||
| 	var ( | ||||
| 		pageSizes []string | ||||
| 		sizeList  = []string{"B", "KB", "MB", "GB", "TB", "PB"} | ||||
| 	) | ||||
| 	files, err := os.ReadDir("/sys/kernel/mm/hugepages") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, st := range files { | ||||
| 		nameArray := strings.Split(st.Name(), "-") | ||||
| 		pageSize, err := units.RAMInBytes(nameArray[1]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		pageSizes = append(pageSizes, units.CustomSize("%g%s", float64(pageSize), 1024.0, sizeList)) | ||||
| 	} | ||||
| 	return pageSizes, nil | ||||
| } | ||||
|  | ||||
| func readUint(path string) (uint64, error) { | ||||
| 	v, err := os.ReadFile(path) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return parseUint(strings.TrimSpace(string(v)), 10, 64) | ||||
| } | ||||
|  | ||||
| func parseUint(s string, base, bitSize int) (uint64, error) { | ||||
| 	v, err := strconv.ParseUint(s, base, bitSize) | ||||
| 	if err != nil { | ||||
| 		intValue, intErr := strconv.ParseInt(s, base, bitSize) | ||||
| 		// 1. Handle negative values greater than MinInt64 (and) | ||||
| 		// 2. Handle negative values lesser than MinInt64 | ||||
| 		if intErr == nil && intValue < 0 { | ||||
| 			return 0, nil | ||||
| 		} else if intErr != nil && | ||||
| 			intErr.(*strconv.NumError).Err == strconv.ErrRange && | ||||
| 			intValue < 0 { | ||||
| 			return 0, nil | ||||
| 		} | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return v, nil | ||||
| } | ||||
|  | ||||
| func parseKV(raw string) (string, uint64, error) { | ||||
| 	parts := strings.Fields(raw) | ||||
| 	switch len(parts) { | ||||
| 	case 2: | ||||
| 		v, err := parseUint(parts[1], 10, 64) | ||||
| 		if err != nil { | ||||
| 			return "", 0, err | ||||
| 		} | ||||
| 		return parts[0], v, nil | ||||
| 	default: | ||||
| 		return "", 0, ErrInvalidFormat | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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" | ||||
| // etc. | ||||
| // | ||||
| // The resulting map does not have an element for cgroup v2 unified hierarchy. | ||||
| // Use ParseCgroupFileUnified to get the unified path. | ||||
| func ParseCgroupFile(path string) (map[string]string, error) { | ||||
| 	x, _, err := ParseCgroupFileUnified(path) | ||||
| 	return x, err | ||||
| } | ||||
|  | ||||
| // ParseCgroupFileUnified returns legacy subsystem paths as the first value, | ||||
| // and returns the unified path as the second value. | ||||
| func ParseCgroupFileUnified(path string) (map[string]string, string, error) { | ||||
| 	f, err := os.Open(path) | ||||
| 	if err != nil { | ||||
| 		return nil, "", err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	return parseCgroupFromReaderUnified(f) | ||||
| } | ||||
|  | ||||
| func parseCgroupFromReaderUnified(r io.Reader) (map[string]string, string, error) { | ||||
| 	var ( | ||||
| 		cgroups = make(map[string]string) | ||||
| 		unified = "" | ||||
| 		s       = bufio.NewScanner(r) | ||||
| 	) | ||||
| 	for s.Scan() { | ||||
| 		var ( | ||||
| 			text  = s.Text() | ||||
| 			parts = strings.SplitN(text, ":", 3) | ||||
| 		) | ||||
| 		if len(parts) < 3 { | ||||
| 			return nil, unified, fmt.Errorf("invalid cgroup entry: %q", text) | ||||
| 		} | ||||
| 		for _, subs := range strings.Split(parts[1], ",") { | ||||
| 			if subs == "" { | ||||
| 				unified = parts[2] | ||||
| 			} else { | ||||
| 				cgroups[subs] = parts[2] | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if err := s.Err(); err != nil { | ||||
| 		return nil, unified, err | ||||
| 	} | ||||
| 	return cgroups, unified, nil | ||||
| } | ||||
|  | ||||
| func getCgroupDestination(subsystem string) (string, error) { | ||||
| 	f, err := os.Open("/proc/self/mountinfo") | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	s := bufio.NewScanner(f) | ||||
| 	for s.Scan() { | ||||
| 		fields := strings.Split(s.Text(), " ") | ||||
| 		if len(fields) < 10 { | ||||
| 			// broken mountinfo? | ||||
| 			continue | ||||
| 		} | ||||
| 		if fields[len(fields)-3] != "cgroup" { | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, opt := range strings.Split(fields[len(fields)-1], ",") { | ||||
| 			if opt == subsystem { | ||||
| 				return fields[3], nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if err := s.Err(); err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return "", ErrNoCgroupMountDestination | ||||
| } | ||||
|  | ||||
| func pathers(subystems []Subsystem) []pather { | ||||
| 	var out []pather | ||||
| 	for _, s := range subystems { | ||||
| 		if p, ok := s.(pather); ok { | ||||
| 			out = append(out, p) | ||||
| 		} | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| func initializeSubsystem(s Subsystem, path Path, resources *specs.LinuxResources) error { | ||||
| 	if c, ok := s.(creator); ok { | ||||
| 		p, err := path(s.Name()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if err := c.Create(p, resources); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} else if c, ok := s.(pather); ok { | ||||
| 		p, err := path(s.Name()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		// do the default create if the group does not have a custom one | ||||
| 		if err := os.MkdirAll(c.Path(p), defaultDirPerm); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func cleanPath(path string) string { | ||||
| 	if path == "" { | ||||
| 		return "" | ||||
| 	} | ||||
| 	path = filepath.Clean(path) | ||||
| 	if !filepath.IsAbs(path) { | ||||
| 		path, _ = filepath.Rel(string(os.PathSeparator), filepath.Clean(string(os.PathSeparator)+path)) | ||||
| 	} | ||||
| 	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 := os.WriteFile(path, data, mode) | ||||
| 		if err == nil { | ||||
| 			return nil | ||||
| 		} else if !errors.Is(err, syscall.EINTR) { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										73
									
								
								vendor/github.com/containerd/cgroups/v1.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/containerd/cgroups/v1.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,73 +0,0 @@ | ||||
| /* | ||||
|    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" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // V1 returns all the groups in the default cgroups mountpoint in a single hierarchy | ||||
| func V1() ([]Subsystem, error) { | ||||
| 	root, err := v1MountPoint() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	subsystems, err := defaults(root) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var enabled []Subsystem | ||||
| 	for _, s := range pathers(subsystems) { | ||||
| 		// check and remove the default groups that do not exist | ||||
| 		if _, err := os.Lstat(s.Path("/")); err == nil { | ||||
| 			enabled = append(enabled, s) | ||||
| 		} | ||||
| 	} | ||||
| 	return enabled, nil | ||||
| } | ||||
|  | ||||
| // v1MountPoint returns the mount point where the cgroup | ||||
| // mountpoints are mounted in a single hiearchy | ||||
| func v1MountPoint() (string, error) { | ||||
| 	f, err := os.Open("/proc/self/mountinfo") | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	defer f.Close() | ||||
| 	scanner := bufio.NewScanner(f) | ||||
| 	for scanner.Scan() { | ||||
| 		var ( | ||||
| 			text      = scanner.Text() | ||||
| 			fields    = strings.Split(text, " ") | ||||
| 			numFields = len(fields) | ||||
| 		) | ||||
| 		if numFields < 10 { | ||||
| 			return "", fmt.Errorf("mountinfo: bad entry %q", text) | ||||
| 		} | ||||
| 		if fields[numFields-3] == "cgroup" { | ||||
| 			return filepath.Dir(fields[4]), nil | ||||
| 		} | ||||
| 	} | ||||
| 	if err := scanner.Err(); err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return "", ErrMountPointNotExist | ||||
| } | ||||
							
								
								
									
										4
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							| @@ -77,10 +77,6 @@ github.com/cilium/ebpf/link | ||||
| # github.com/container-storage-interface/spec v1.9.0 | ||||
| ## explicit; go 1.18 | ||||
| github.com/container-storage-interface/spec/lib/go/csi | ||||
| # github.com/containerd/cgroups v1.1.0 | ||||
| ## explicit; go 1.17 | ||||
| github.com/containerd/cgroups | ||||
| github.com/containerd/cgroups/stats/v1 | ||||
| # github.com/containerd/containerd/api v1.7.19 | ||||
| ## explicit; go 1.21 | ||||
| github.com/containerd/containerd/api/services/containers/v1 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Davanum Srinivas
					Davanum Srinivas