@@ -4,8 +4,12 @@ package cgroups
4
4
5
5
import (
6
6
"context"
7
+ "errors"
7
8
"fmt"
9
+ "math/big"
8
10
"path/filepath"
11
+ "slices"
12
+ "strconv"
9
13
"strings"
10
14
11
15
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
@@ -53,7 +57,11 @@ func systemdCreate(resources *configs.Resources, path string, c *systemdDbus.Con
53
57
properties = append (properties , p )
54
58
}
55
59
56
- uMap , sMap , bMap , iMap , structMap := resourcesToProps (resources , v2 )
60
+ uMap , sMap , bMap , iMap , structMap , err := resourcesToProps (resources , v2 )
61
+ if err != nil {
62
+ lastError = err
63
+ continue
64
+ }
57
65
for k , v := range uMap {
58
66
p := systemdDbus.Property {
59
67
Name : k ,
@@ -95,7 +103,7 @@ func systemdCreate(resources *configs.Resources, path string, c *systemdDbus.Con
95
103
}
96
104
97
105
ch := make (chan string )
98
- _ , err : = c .StartTransientUnitContext (context .TODO (), name , "replace" , properties , ch )
106
+ _ , err = c .StartTransientUnitContext (context .TODO (), name , "replace" , properties , ch )
99
107
if err != nil {
100
108
lastError = err
101
109
continue
@@ -142,7 +150,7 @@ func systemdDestroyConn(path string, c *systemdDbus.Conn) error {
142
150
return nil
143
151
}
144
152
145
- func resourcesToProps (res * configs.Resources , v2 bool ) (map [string ]uint64 , map [string ]string , map [string ][]byte , map [string ]int64 , map [string ][]BlkioDev ) {
153
+ func resourcesToProps (res * configs.Resources , v2 bool ) (map [string ]uint64 , map [string ]string , map [string ][]byte , map [string ]int64 , map [string ][]BlkioDev , error ) {
146
154
bMap := make (map [string ][]byte )
147
155
// this array is not used but will be once more resource limits are added
148
156
sMap := make (map [string ]string )
@@ -179,11 +187,19 @@ func resourcesToProps(res *configs.Resources, v2 bool) (map[string]uint64, map[s
179
187
180
188
// CPUSet
181
189
if res .CpusetCpus != "" {
182
- bits := []byte (res .CpusetCpus )
190
+ bits , err := rangeToBits (res .CpusetCpus )
191
+ if err != nil {
192
+ return nil , nil , nil , nil , nil , fmt .Errorf ("resources.CpusetCpus=%q conversion error: %w" ,
193
+ res .CpusetCpus , err )
194
+ }
183
195
bMap ["AllowedCPUs" ] = bits
184
196
}
185
197
if res .CpusetMems != "" {
186
- bits := []byte (res .CpusetMems )
198
+ bits , err := rangeToBits (res .CpusetMems )
199
+ if err != nil {
200
+ return nil , nil , nil , nil , nil , fmt .Errorf ("resources.CpusetMems=%q conversion error: %w" ,
201
+ res .CpusetMems , err )
202
+ }
187
203
bMap ["AllowedMemoryNodes" ] = bits
188
204
}
189
205
@@ -258,5 +274,51 @@ func resourcesToProps(res *configs.Resources, v2 bool) (map[string]uint64, map[s
258
274
}
259
275
}
260
276
261
- return uMap , sMap , bMap , iMap , structMap
277
+ return uMap , sMap , bMap , iMap , structMap , nil
278
+ }
279
+
280
+ func rangeToBits (str string ) ([]byte , error ) {
281
+ bits := new (big.Int )
282
+
283
+ for _ , r := range strings .Split (str , "," ) {
284
+ // allow extra spaces around
285
+ r = strings .TrimSpace (r )
286
+ // allow empty elements (extra commas)
287
+ if r == "" {
288
+ continue
289
+ }
290
+ startr , endr , ok := strings .Cut (r , "-" )
291
+ if ok {
292
+ start , err := strconv .ParseUint (startr , 10 , 32 )
293
+ if err != nil {
294
+ return nil , err
295
+ }
296
+ end , err := strconv .ParseUint (endr , 10 , 32 )
297
+ if err != nil {
298
+ return nil , err
299
+ }
300
+ if start > end {
301
+ return nil , errors .New ("invalid range: " + r )
302
+ }
303
+ for i := start ; i <= end ; i ++ {
304
+ bits .SetBit (bits , int (i ), 1 )
305
+ }
306
+ } else {
307
+ val , err := strconv .ParseUint (startr , 10 , 32 )
308
+ if err != nil {
309
+ return nil , err
310
+ }
311
+ bits .SetBit (bits , int (val ), 1 )
312
+ }
313
+ }
314
+
315
+ ret := bits .Bytes ()
316
+ if len (ret ) == 0 {
317
+ // do not allow empty values
318
+ return nil , errors .New ("empty value" )
319
+ }
320
+
321
+ // fit cpuset parsing order in systemd
322
+ slices .Reverse (ret )
323
+ return ret , nil
262
324
}
0 commit comments