@@ -4,8 +4,12 @@ package cgroups
44
55import (
66 "context"
7+ "errors"
78 "fmt"
9+ "math/big"
810 "path/filepath"
11+ "slices"
12+ "strconv"
913 "strings"
1014
1115 systemdDbus "github.com/coreos/go-systemd/v22/dbus"
@@ -53,7 +57,11 @@ func systemdCreate(resources *configs.Resources, path string, c *systemdDbus.Con
5357 properties = append (properties , p )
5458 }
5559
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+ }
5765 for k , v := range uMap {
5866 p := systemdDbus.Property {
5967 Name : k ,
@@ -95,7 +103,7 @@ func systemdCreate(resources *configs.Resources, path string, c *systemdDbus.Con
95103 }
96104
97105 ch := make (chan string )
98- _ , err : = c .StartTransientUnitContext (context .TODO (), name , "replace" , properties , ch )
106+ _ , err = c .StartTransientUnitContext (context .TODO (), name , "replace" , properties , ch )
99107 if err != nil {
100108 lastError = err
101109 continue
@@ -142,7 +150,7 @@ func systemdDestroyConn(path string, c *systemdDbus.Conn) error {
142150 return nil
143151}
144152
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 ) {
146154 bMap := make (map [string ][]byte )
147155 // this array is not used but will be once more resource limits are added
148156 sMap := make (map [string ]string )
@@ -179,11 +187,19 @@ func resourcesToProps(res *configs.Resources, v2 bool) (map[string]uint64, map[s
179187
180188 // CPUSet
181189 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+ }
183195 bMap ["AllowedCPUs" ] = bits
184196 }
185197 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+ }
187203 bMap ["AllowedMemoryNodes" ] = bits
188204 }
189205
@@ -258,5 +274,51 @@ func resourcesToProps(res *configs.Resources, v2 bool) (map[string]uint64, map[s
258274 }
259275 }
260276
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
262324}
0 commit comments