1 package main
2
3 import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "os"
8 "strconv"
9
10 "github.com/opencontainers/runc/libcontainer/cgroups"
11 "github.com/sirupsen/logrus"
12
13 "github.com/docker/go-units"
14 "github.com/opencontainers/runc/libcontainer/configs"
15 "github.com/opencontainers/runc/libcontainer/intelrdt"
16 "github.com/opencontainers/runtime-spec/specs-go"
17 "github.com/urfave/cli"
18 )
19
20 func i64Ptr(i int64) *int64 { return &i }
21 func u64Ptr(i uint64) *uint64 { return &i }
22 func u16Ptr(i uint16) *uint16 { return &i }
23
24 var updateCommand = cli.Command{
25 Name: "update",
26 Usage: "update container resource constraints",
27 ArgsUsage: `<container-id>`,
28 Flags: []cli.Flag{
29 cli.StringFlag{
30 Name: "resources, r",
31 Value: "",
32 Usage: `path to the file containing the resources to update or '-' to read from the standard input
33
34 The accepted format is as follow (unchanged values can be omitted):
35
36 {
37 "memory": {
38 "limit": 0,
39 "reservation": 0,
40 "swap": 0
41 },
42 "cpu": {
43 "shares": 0,
44 "quota": 0,
45 "period": 0,
46 "realtimeRuntime": 0,
47 "realtimePeriod": 0,
48 "cpus": "",
49 "mems": ""
50 },
51 "blockIO": {
52 "weight": 0
53 }
54 }
55
56 Note: if data is to be read from a file or the standard input, all
57 other options are ignored.
58 `,
59 },
60
61 cli.IntFlag{
62 Name: "blkio-weight",
63 Usage: "Specifies per cgroup weight, range is from 10 to 1000",
64 },
65 cli.StringFlag{
66 Name: "cpu-period",
67 Usage: "CPU CFS period to be used for hardcapping (in usecs). 0 to use system default",
68 },
69 cli.StringFlag{
70 Name: "cpu-quota",
71 Usage: "CPU CFS hardcap limit (in usecs). Allowed cpu time in a given period",
72 },
73 cli.StringFlag{
74 Name: "cpu-share",
75 Usage: "CPU shares (relative weight vs. other containers)",
76 },
77 cli.StringFlag{
78 Name: "cpu-rt-period",
79 Usage: "CPU realtime period to be used for hardcapping (in usecs). 0 to use system default",
80 },
81 cli.StringFlag{
82 Name: "cpu-rt-runtime",
83 Usage: "CPU realtime hardcap limit (in usecs). Allowed cpu time in a given period",
84 },
85 cli.StringFlag{
86 Name: "cpuset-cpus",
87 Usage: "CPU(s) to use",
88 },
89 cli.StringFlag{
90 Name: "cpuset-mems",
91 Usage: "Memory node(s) to use",
92 },
93 cli.StringFlag{
94 Name: "kernel-memory",
95 Usage: "(obsoleted; do not use)",
96 Hidden: true,
97 },
98 cli.StringFlag{
99 Name: "kernel-memory-tcp",
100 Usage: "(obsoleted; do not use)",
101 Hidden: true,
102 },
103 cli.StringFlag{
104 Name: "memory",
105 Usage: "Memory limit (in bytes)",
106 },
107 cli.StringFlag{
108 Name: "memory-reservation",
109 Usage: "Memory reservation or soft_limit (in bytes)",
110 },
111 cli.StringFlag{
112 Name: "memory-swap",
113 Usage: "Total memory usage (memory + swap); set '-1' to enable unlimited swap",
114 },
115 cli.IntFlag{
116 Name: "pids-limit",
117 Usage: "Maximum number of pids allowed in the container",
118 },
119 cli.StringFlag{
120 Name: "l3-cache-schema",
121 Usage: "The string of Intel RDT/CAT L3 cache schema",
122 },
123 cli.StringFlag{
124 Name: "mem-bw-schema",
125 Usage: "The string of Intel RDT/MBA memory bandwidth schema",
126 },
127 },
128 Action: func(context *cli.Context) error {
129 if err := checkArgs(context, 1, exactArgs); err != nil {
130 return err
131 }
132 container, err := getContainer(context)
133 if err != nil {
134 return err
135 }
136
137 r := specs.LinuxResources{
138 Memory: &specs.LinuxMemory{
139 Limit: i64Ptr(0),
140 Reservation: i64Ptr(0),
141 Swap: i64Ptr(0),
142 Kernel: i64Ptr(0),
143 KernelTCP: i64Ptr(0),
144 },
145 CPU: &specs.LinuxCPU{
146 Shares: u64Ptr(0),
147 Quota: i64Ptr(0),
148 Period: u64Ptr(0),
149 RealtimeRuntime: i64Ptr(0),
150 RealtimePeriod: u64Ptr(0),
151 Cpus: "",
152 Mems: "",
153 },
154 BlockIO: &specs.LinuxBlockIO{
155 Weight: u16Ptr(0),
156 },
157 Pids: &specs.LinuxPids{
158 Limit: 0,
159 },
160 }
161
162 config := container.Config()
163
164 if in := context.String("resources"); in != "" {
165 var (
166 f *os.File
167 err error
168 )
169 switch in {
170 case "-":
171 f = os.Stdin
172 default:
173 f, err = os.Open(in)
174 if err != nil {
175 return err
176 }
177 defer f.Close()
178 }
179 err = json.NewDecoder(f).Decode(&r)
180 if err != nil {
181 return err
182 }
183 } else {
184 if val := context.Int("blkio-weight"); val != 0 {
185 r.BlockIO.Weight = u16Ptr(uint16(val))
186 }
187 if val := context.String("cpuset-cpus"); val != "" {
188 r.CPU.Cpus = val
189 }
190 if val := context.String("cpuset-mems"); val != "" {
191 r.CPU.Mems = val
192 }
193
194 for _, pair := range []struct {
195 opt string
196 dest *uint64
197 }{
198 {"cpu-period", r.CPU.Period},
199 {"cpu-rt-period", r.CPU.RealtimePeriod},
200 {"cpu-share", r.CPU.Shares},
201 } {
202 if val := context.String(pair.opt); val != "" {
203 var err error
204 *pair.dest, err = strconv.ParseUint(val, 10, 64)
205 if err != nil {
206 return fmt.Errorf("invalid value for %s: %w", pair.opt, err)
207 }
208 }
209 }
210 for _, pair := range []struct {
211 opt string
212 dest *int64
213 }{
214 {"cpu-quota", r.CPU.Quota},
215 {"cpu-rt-runtime", r.CPU.RealtimeRuntime},
216 } {
217 if val := context.String(pair.opt); val != "" {
218 var err error
219 *pair.dest, err = strconv.ParseInt(val, 10, 64)
220 if err != nil {
221 return fmt.Errorf("invalid value for %s: %w", pair.opt, err)
222 }
223 }
224 }
225 for _, pair := range []struct {
226 opt string
227 dest *int64
228 }{
229 {"memory", r.Memory.Limit},
230 {"memory-swap", r.Memory.Swap},
231 {"kernel-memory", r.Memory.Kernel},
232 {"kernel-memory-tcp", r.Memory.KernelTCP},
233 {"memory-reservation", r.Memory.Reservation},
234 } {
235 if val := context.String(pair.opt); val != "" {
236 var v int64
237
238 if val != "-1" {
239 v, err = units.RAMInBytes(val)
240 if err != nil {
241 return fmt.Errorf("invalid value for %s: %w", pair.opt, err)
242 }
243 } else {
244 v = -1
245 }
246 *pair.dest = v
247 }
248 }
249
250 r.Pids.Limit = int64(context.Int("pids-limit"))
251 }
252
253 if *r.Memory.Kernel != 0 || *r.Memory.KernelTCP != 0 {
254 logrus.Warn("Kernel memory settings are ignored and will be removed")
255 }
256
257
258 config.Cgroups.Resources.BlkioWeight = *r.BlockIO.Weight
259
260
261
262
263
264
265
266
267
268
269
270
271 p, q := *r.CPU.Period, *r.CPU.Quota
272 if (p == 0 && q == 0) || (p != 0 && q != 0) {
273
274 config.Cgroups.Resources.CpuPeriod = p
275 config.Cgroups.Resources.CpuQuota = q
276 } else {
277
278 if p != 0 {
279
280 config.Cgroups.Resources.CpuPeriod = p
281 } else if q != 0 {
282
283 config.Cgroups.Resources.CpuQuota = q
284 }
285 }
286
287 config.Cgroups.Resources.CpuShares = *r.CPU.Shares
288
289 config.Cgroups.Resources.CpuWeight = cgroups.ConvertCPUSharesToCgroupV2Value(*r.CPU.Shares)
290 config.Cgroups.Resources.CpuRtPeriod = *r.CPU.RealtimePeriod
291 config.Cgroups.Resources.CpuRtRuntime = *r.CPU.RealtimeRuntime
292 config.Cgroups.Resources.CpusetCpus = r.CPU.Cpus
293 config.Cgroups.Resources.CpusetMems = r.CPU.Mems
294 config.Cgroups.Resources.Memory = *r.Memory.Limit
295 config.Cgroups.Resources.MemoryReservation = *r.Memory.Reservation
296 config.Cgroups.Resources.MemorySwap = *r.Memory.Swap
297 config.Cgroups.Resources.PidsLimit = r.Pids.Limit
298 config.Cgroups.Resources.Unified = r.Unified
299
300
301 l3CacheSchema := context.String("l3-cache-schema")
302 memBwSchema := context.String("mem-bw-schema")
303 if l3CacheSchema != "" && !intelrdt.IsCATEnabled() {
304 return errors.New("Intel RDT/CAT: l3 cache schema is not enabled")
305 }
306
307 if memBwSchema != "" && !intelrdt.IsMBAEnabled() {
308 return errors.New("Intel RDT/MBA: memory bandwidth schema is not enabled")
309 }
310
311 if l3CacheSchema != "" || memBwSchema != "" {
312
313
314
315
316 if config.IntelRdt == nil {
317 state, err := container.State()
318 if err != nil {
319 return err
320 }
321 config.IntelRdt = &configs.IntelRdt{}
322 intelRdtManager := intelrdt.NewManager(&config, container.ID(), state.IntelRdtPath)
323 if err := intelRdtManager.Apply(state.InitProcessPid); err != nil {
324 return err
325 }
326 }
327 config.IntelRdt.L3CacheSchema = l3CacheSchema
328 config.IntelRdt.MemBwSchema = memBwSchema
329 }
330
331
332
333
334
335
336 config.Cgroups.SkipDevices = true
337
338 return container.Set(config)
339 },
340 }
341
View as plain text