Skip to content

Commit 42dfd60

Browse files
authored
Merge pull request #904 from euank/fix-cgroup-parsing-err
cgroups: Fix issue if cgroup path contains :
2 parents c046127 + 394610a commit 42dfd60

File tree

2 files changed

+73
-2
lines changed

2 files changed

+73
-2
lines changed

libcontainer/cgroups/utils.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,14 +262,21 @@ func readProcsFile(dir string) ([]int, error) {
262262
return out, nil
263263
}
264264

265+
// ParseCgroupFile parses the given cgroup file, typically from
266+
// /proc/<pid>/cgroup, into a map of subgroups to cgroup names.
265267
func ParseCgroupFile(path string) (map[string]string, error) {
266268
f, err := os.Open(path)
267269
if err != nil {
268270
return nil, err
269271
}
270272
defer f.Close()
271273

272-
s := bufio.NewScanner(f)
274+
return parseCgroupFromReader(f)
275+
}
276+
277+
// helper function for ParseCgroupFile to make testing easier
278+
func parseCgroupFromReader(r io.Reader) (map[string]string, error) {
279+
s := bufio.NewScanner(r)
273280
cgroups := make(map[string]string)
274281

275282
for s.Scan() {
@@ -278,7 +285,16 @@ func ParseCgroupFile(path string) (map[string]string, error) {
278285
}
279286

280287
text := s.Text()
281-
parts := strings.Split(text, ":")
288+
// from cgroups(7):
289+
// /proc/[pid]/cgroup
290+
// ...
291+
// For each cgroup hierarchy ... there is one entry
292+
// containing three colon-separated fields of the form:
293+
// hierarchy-ID:subsystem-list:cgroup-path
294+
parts := strings.SplitN(text, ":", 3)
295+
if len(parts) < 3 {
296+
return nil, fmt.Errorf("invalid cgroup entry: must contain at least two colons: %v", text)
297+
}
282298

283299
for _, subs := range strings.Split(parts[1], ",") {
284300
cgroups[subs] = parts[2]

libcontainer/cgroups/utils_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ package cgroups
44

55
import (
66
"bytes"
7+
"fmt"
8+
"reflect"
79
"strings"
810
"testing"
911
)
@@ -190,3 +192,56 @@ func BenchmarkGetCgroupMounts(b *testing.B) {
190192
}
191193
}
192194
}
195+
196+
func TestParseCgroupString(t *testing.T) {
197+
testCases := []struct {
198+
input string
199+
expectedError error
200+
expectedOutput map[string]string
201+
}{
202+
{
203+
// Taken from a CoreOS instance running systemd 225 with CPU/Mem
204+
// accounting enabled in systemd
205+
input: `9:blkio:/
206+
8:freezer:/
207+
7:perf_event:/
208+
6:devices:/system.slice/system-sshd.slice
209+
5:cpuset:/
210+
4:cpu,cpuacct:/system.slice/system-sshd.slice/[email protected]:22-xxx.yyy.zzz.aaa:33678.service
211+
3:net_cls,net_prio:/
212+
2:memory:/system.slice/system-sshd.slice/[email protected]:22-xxx.yyy.zzz.aaa:33678.service
213+
1:name=systemd:/system.slice/system-sshd.slice/[email protected]:22-xxx.yyy.zzz.aaa:33678.service`,
214+
expectedOutput: map[string]string{
215+
"name=systemd": "/system.slice/system-sshd.slice/[email protected]:22-xxx.yyy.zzz.aaa:33678.service",
216+
"blkio": "/",
217+
"freezer": "/",
218+
"perf_event": "/",
219+
"devices": "/system.slice/system-sshd.slice",
220+
"cpuset": "/",
221+
"cpu": "/system.slice/system-sshd.slice/[email protected]:22-xxx.yyy.zzz.aaa:33678.service",
222+
"cpuacct": "/system.slice/system-sshd.slice/[email protected]:22-xxx.yyy.zzz.aaa:33678.service",
223+
"net_cls": "/",
224+
"net_prio": "/",
225+
"memory": "/system.slice/system-sshd.slice/[email protected]:22-xxx.yyy.zzz.aaa:33678.service",
226+
},
227+
},
228+
{
229+
input: `malformed input`,
230+
expectedError: fmt.Errorf(`invalid cgroup entry: must contain at least two colons: malformed input`),
231+
},
232+
}
233+
234+
for ndx, testCase := range testCases {
235+
out, err := parseCgroupFromReader(strings.NewReader(testCase.input))
236+
if err != nil {
237+
if testCase.expectedError == nil || testCase.expectedError.Error() != err.Error() {
238+
t.Errorf("%v: expected error %v, got error %v", ndx, testCase.expectedError, err)
239+
}
240+
} else {
241+
if !reflect.DeepEqual(testCase.expectedOutput, out) {
242+
t.Errorf("%v: expected output %v, got error %v", ndx, testCase.expectedOutput, out)
243+
}
244+
}
245+
}
246+
247+
}

0 commit comments

Comments
 (0)