-
Notifications
You must be signed in to change notification settings - Fork 1k
/
utils_linux.go
143 lines (119 loc) · 4.48 KB
/
utils_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright (c) 2020 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package resourcecontrol
import (
"context"
"fmt"
"path/filepath"
"strings"
"github.com/containerd/cgroups"
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
"github.com/godbus/dbus/v5"
"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
)
// DefaultResourceControllerID runtime-determined location in the cgroups hierarchy.
const DefaultResourceControllerID = "/vc"
// ValidCgroupPathV1 returns a valid cgroup path for cgroup v1.
// see https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#cgroups-path
func ValidCgroupPathV1(path string, systemdCgroup bool) (string, error) {
if IsSystemdCgroup(path) {
return path, nil
}
if systemdCgroup {
return "", fmt.Errorf("malformed systemd path '%v': expected to be of form 'slice:prefix:name'", path)
}
// In the case of an absolute path (starting with /), the runtime MUST
// take the path to be relative to the cgroups mount point.
if filepath.IsAbs(path) {
return filepath.Clean(path), nil
}
// In the case of a relative path (not starting with /), the runtime MAY
// interpret the path relative to a runtime-determined location in the cgroups hierarchy.
// clean up path and return a new path relative to DefaultResourceControllerID
return filepath.Join(DefaultResourceControllerID, filepath.Clean("/"+path)), nil
}
// ValidCgroupPathV2 returns a valid cgroup path for cgroup v2.
// see https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#cgroups-path
func ValidCgroupPathV2(path string, systemdCgroup bool) (string, error) {
// In cgroup v2,path must be a "clean" absolute path starts with "/".
if IsSystemdCgroup(path) {
return filepath.Join("/", path), nil
}
if systemdCgroup {
return "", fmt.Errorf("malformed systemd path '%v': expected to be of form 'slice:prefix:name'", path)
}
// In the case of an absolute path (starting with /), the runtime MUST
// take the path to be relative to the cgroups mount point.
if filepath.IsAbs(path) {
return filepath.Clean(path), nil
}
// In the case of a relative path (not starting with /), the runtime MAY
// interpret the path relative to a runtime-determined location in the cgroups hierarchy.
// clean up path and return a new path relative to DefaultResourceControllerID
return filepath.Join(DefaultResourceControllerID, filepath.Clean("/"+path)), nil
}
func newProperty(name string, units interface{}) systemdDbus.Property {
return systemdDbus.Property{
Name: name,
Value: dbus.MakeVariant(units),
}
}
func cgroupHierarchy(path string) (cgroups.Hierarchy, cgroups.Path, error) {
if !IsSystemdCgroup(path) {
return cgroups.V1, cgroups.StaticPath(path), nil
} else {
slice, unit, err := getSliceAndUnit(path)
if err != nil {
return nil, nil, err
}
cgroupSlicePath, _ := systemd.ExpandSlice(slice)
if err != nil {
return nil, nil, err
}
return cgroups.Systemd, cgroups.Slice(cgroupSlicePath, unit), nil
}
}
func createCgroupsSystemd(slice string, unit string, pid int) error {
ctx := context.TODO()
conn, err := systemdDbus.NewWithContext(ctx)
if err != nil {
return err
}
defer conn.Close()
properties := []systemdDbus.Property{
systemdDbus.PropDescription("cgroup " + unit),
newProperty("DefaultDependencies", false),
newProperty("MemoryAccounting", true),
newProperty("CPUAccounting", true),
newProperty("IOAccounting", true),
}
if strings.HasSuffix(unit, ".slice") {
// If we create a slice, the parent is defined via a Wants=.
properties = append(properties, systemdDbus.PropWants(slice))
} else {
// Otherwise it's a scope, which we put into a Slice=.
properties = append(properties, systemdDbus.PropSlice(slice))
}
// Assume scopes always support delegation (supported since systemd v218).
properties = append(properties, newProperty("Delegate", true))
if pid != -1 {
properties = append(properties, systemdDbus.PropPids(uint32(pid)))
}
ch := make(chan string)
// https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/
_, err = conn.StartTransientUnitContext(ctx, unit, "replace", properties, ch)
if err != nil {
return err
}
<-ch
return nil
}
func getSliceAndUnit(cgroupPath string) (string, string, error) {
parts := strings.Split(cgroupPath, ":")
if len(parts) == 3 && strings.HasSuffix(parts[0], ".slice") {
return parts[0], fmt.Sprintf("%s-%s.scope", parts[1], parts[2]), nil
}
return "", "", fmt.Errorf("Path: %s is not valid systemd's cgroups path", cgroupPath)
}