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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
//! This module allows the user to create a control group using the Builder pattern.
//! # Example
//!
//! The following example demonstrates how the control group builder looks like.  The user
//! specifies the name of the control group (here: "hello") and the hierarchy it belongs to (here:
//! a V1 hierarchy). Next, the user selects a subsystem by calling functions like `memory()`,
//! `cpu()` and `devices()`. The user can then add restrictions and details via subsystem-specific
//! calls. To finalize a subsystem, the user may call `done()`. Finally, if the control group build
//! is done and all requirements/restrictions have been specified, the control group can be created
//! by a call to `build()`.
//!
//! ```rust,no_run
//! # use cgroups::*;
//! # use cgroups::devices::*;
//! # use cgroups::cgroup_builder::*;
//! let v1 = cgroups::hierarchies::V1::new();
//! let cgroup: Cgroup = CgroupBuilder::new("hello", &v1)
//!      .memory()
//!          .kernel_memory_limit(1024 * 1024)
//!          .memory_hard_limit(1024 * 1024)
//!          .done()
//!      .cpu()
//!          .shares(100)
//!          .done()
//!      .devices()
//!          .device(1000, 10, DeviceType::Block, true,
//!             vec![DevicePermissions::Read,
//!                  DevicePermissions::Write,
//!                  DevicePermissions::MkNod])
//!          .device(6, 1, DeviceType::Char, false, vec![])
//!          .done()
//!      .network()
//!          .class_id(1337)
//!          .priority("eth0".to_string(), 100)
//!          .priority("wl0".to_string(), 200)
//!          .done()
//!      .hugepages()
//!          .limit("2M".to_string(), 0)
//!          .limit("4M".to_string(), 4 * 1024 * 1024 * 100)
//!          .limit("2G".to_string(), 2 * 1024 * 1024 * 1024)
//!          .done()
//!      .blkio()
//!          .weight(123)
//!          .leaf_weight(99)
//!          .weight_device(6, 1, 100, 55)
//!          .weight_device(6, 1, 100, 55)
//!          .throttle_iops()
//!              .read(6, 1, 10)
//!              .write(11, 1, 100)
//!          .throttle_bps()
//!              .read(6, 1, 10)
//!              .write(11, 1, 100)
//!          .done()
//!      .build();
//! ```
use error::*;

use {pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource,  Cgroup, DeviceResource, Hierarchy, HugePageResource, NetworkPriority, Resources};

macro_rules! gen_setter {
    ($res:ident, $cont:ident, $func:ident, $name:ident, $ty:ty) => {
        /// See the similarly named function in the respective controller.
        pub fn $name(mut self, $name: $ty) -> Self {
            self.cgroup.resources.$res.update_values = true;
            self.cgroup.resources.$res.$name = $name;
            self
        }
    }
}

/// A control group builder instance
pub struct CgroupBuilder<'a> {
    name: String,
    hierarchy: &'a Hierarchy,
    /// Internal, unsupported field: use the associated builders instead.
    resources: Resources,
}

impl<'a> CgroupBuilder<'a> {
    /// Start building a control group with the supplied hierarchy and name pair.
    ///
    /// Note that this does not actually create the control group until `build()` is called.
    pub fn new(name: &'a str, hierarchy: &'a Hierarchy) -> CgroupBuilder<'a> {
        CgroupBuilder {
            name: name.to_owned(),
            hierarchy: hierarchy,
            resources: Resources::default(),
        }
    }

    /// Builds the memory resources of the control group.
    pub fn memory(self) -> MemoryResourceBuilder<'a> {
        MemoryResourceBuilder {
            cgroup: self,
        }
    }

    /// Builds the pid resources of the control group.
    pub fn pid(self) -> PidResourceBuilder<'a> {
        PidResourceBuilder {
            cgroup: self,
        }
    }

    /// Builds the cpu resources of the control group.
    pub fn cpu(self) -> CpuResourceBuilder<'a> {
        CpuResourceBuilder {
            cgroup: self,
        }
    }

    /// Builds the devices resources of the control group, disallowing or
    /// allowing access to certain devices in the system.
    pub fn devices(self) -> DeviceResourceBuilder<'a> {
        DeviceResourceBuilder {
            cgroup: self,
        }
    }

    /// Builds the network resources of the control group, setting class id, or
    /// various priorities on networking interfaces.
    pub fn network(self) -> NetworkResourceBuilder<'a> {
        NetworkResourceBuilder {
            cgroup: self,
        }
    }

    /// Builds the hugepage/hugetlb resources available to the control group.
    pub fn hugepages(self) -> HugepagesResourceBuilder<'a> {
        HugepagesResourceBuilder {
            cgroup: self,
        }
    }

    /// Builds the block I/O resources available for the control group.
    pub fn blkio(self) -> BlkIoResourcesBuilder<'a> {
        BlkIoResourcesBuilder {
            cgroup: self,
            throttling_iops: false,
        }
    }

    /// Finalize the control group, consuming the builder and creating the control group.
    pub fn build(self) -> Cgroup<'a> {
        let cg = Cgroup::new(self.hierarchy, self.name);
        cg.apply(&self.resources);
        cg
    }
}

/// A builder that configures the memory controller of a control group.
pub struct MemoryResourceBuilder<'a> {
    cgroup: CgroupBuilder<'a>,
}

impl<'a> MemoryResourceBuilder<'a> {

    gen_setter!(memory, MemController, set_kmem_limit, kernel_memory_limit, u64);
    gen_setter!(memory, MemController, set_limit, memory_hard_limit, u64);
    gen_setter!(memory, MemController, set_soft_limit, memory_soft_limit, u64);
    gen_setter!(memory, MemController, set_tcp_limit, kernel_tcp_memory_limit, u64);
    gen_setter!(memory, MemController, set_memswap_limit, memory_swap_limit, u64);
    gen_setter!(memory, MemController, set_swappiness, swappiness, u64);

    /// Finish the construction of the memory resources of a control group.
    pub fn done(self) -> CgroupBuilder<'a> {
        self.cgroup
    }
}

/// A builder that configures the pid controller of a control group.
pub struct PidResourceBuilder<'a> {
    cgroup: CgroupBuilder<'a>,
}

impl<'a> PidResourceBuilder<'a> {

    gen_setter!(pid, PidController, set_pid_max, maximum_number_of_processes, pid::PidMax);

    /// Finish the construction of the pid resources of a control group.
    pub fn done(self) -> CgroupBuilder<'a> {
        self.cgroup
    }
}

/// A builder that configures the cpuset & cpu controllers of a control group.
pub struct CpuResourceBuilder<'a> {
    cgroup: CgroupBuilder<'a>,
}

impl<'a> CpuResourceBuilder<'a> {

    gen_setter!(cpu, CpuSetController, set_cpus, cpus, String);
    gen_setter!(cpu, CpuSetController, set_mems, mems, String);
    gen_setter!(cpu, CpuController, set_shares, shares, u64);
    gen_setter!(cpu, CpuController, set_cfs_quota, quota, i64);
    gen_setter!(cpu, CpuController, set_cfs_period, period, u64);
    gen_setter!(cpu, CpuController, set_rt_runtime, realtime_runtime, i64);
    gen_setter!(cpu, CpuController, set_rt_period, realtime_period, u64);

    /// Finish the construction of the cpu resources of a control group.
    pub fn done(self) -> CgroupBuilder<'a> {
        self.cgroup
    }
}

/// A builder that configures the devices controller of a control group.
pub struct DeviceResourceBuilder<'a> {
    cgroup: CgroupBuilder<'a>,
}

impl<'a> DeviceResourceBuilder<'a> {

    /// Restrict (or allow) a device to the tasks inside the control group.
    pub fn device(mut self,
                  major: i64,
                  minor: i64,
                  devtype: ::devices::DeviceType,
                  allow: bool,
                  access: Vec<::devices::DevicePermissions>)
            -> DeviceResourceBuilder<'a> {
        self.cgroup.resources.devices.update_values = true;
        self.cgroup.resources.devices.devices.push(DeviceResource {
            major,
            minor,
            devtype,
            allow,
            access
        });
        self
    }

    /// Finish the construction of the devices resources of a control group.
    pub fn done(self) -> CgroupBuilder<'a> {
        self.cgroup
    }
}

/// A builder that configures the net_cls & net_prio controllers of a control group.
pub struct NetworkResourceBuilder<'a> {
    cgroup: CgroupBuilder<'a>,
}

impl<'a> NetworkResourceBuilder<'a> {

    gen_setter!(network, NetclsController, set_class, class_id, u64);

    /// Set the priority of the tasks when operating on a networking device defined by `name` to be
    /// `priority`.
    pub fn priority(mut self, name: String, priority: u64)
        -> NetworkResourceBuilder<'a> {
        self.cgroup.resources.network.update_values = true;
        self.cgroup.resources.network.priorities.push(NetworkPriority {
            name,
            priority,
        });
        self
    }

    /// Finish the construction of the network resources of a control group.
    pub fn done(self) -> CgroupBuilder<'a> {
        self.cgroup
    }
}

/// A builder that configures the hugepages controller of a control group.
pub struct HugepagesResourceBuilder<'a> {
    cgroup: CgroupBuilder<'a>,
}

impl<'a> HugepagesResourceBuilder<'a> {

    /// Limit the usage of certain hugepages (determined by `size`) to be at most `limit` bytes.
    pub fn limit(mut self, size: String, limit: u64)
        -> HugepagesResourceBuilder<'a> {
        self.cgroup.resources.hugepages.update_values = true;
        self.cgroup.resources.hugepages.limits.push(HugePageResource {
            size,
            limit,
        });
        self
    }

    /// Finish the construction of the network resources of a control group.
    pub fn done(self) -> CgroupBuilder<'a> {
        self.cgroup
    }
}

/// A builder that configures the blkio controller of a control group.
pub struct BlkIoResourcesBuilder<'a> {
    cgroup: CgroupBuilder<'a>,
    throttling_iops: bool,
}

impl<'a> BlkIoResourcesBuilder<'a> {

    gen_setter!(blkio, BlkIoController, set_weight, weight, u16);
    gen_setter!(blkio, BlkIoController, set_leaf_weight, leaf_weight, u16);

    /// Set the weight of a certain device.
    pub fn weight_device(mut self,
                         major: u64,
                         minor: u64,
                         weight: u16,
                         leaf_weight: u16)
        -> BlkIoResourcesBuilder<'a> {
        self.cgroup.resources.blkio.update_values = true;
        self.cgroup.resources.blkio.weight_device.push(BlkIoDeviceResource {
            major,
            minor,
            weight,
            leaf_weight,
        });
        self
    }

    /// Start configuring the I/O operations per second metric.
    pub fn throttle_iops(mut self) -> BlkIoResourcesBuilder<'a> {
        self.throttling_iops = true;
        self
    }

    /// Start configuring the bytes per second metric.
    pub fn throttle_bps(mut self) -> BlkIoResourcesBuilder<'a> {
        self.throttling_iops = false;
        self
    }

    /// Limit the read rate of the current metric for a certain device.
    pub fn read(mut self, major: u64, minor: u64, rate: u64)
        -> BlkIoResourcesBuilder<'a> {
        self.cgroup.resources.blkio.update_values = true;
        let throttle = BlkIoDeviceThrottleResource {
            major,
            minor,
            rate,
        };
        if self.throttling_iops {
            self.cgroup.resources.blkio.throttle_read_iops_device.push(throttle);
        } else {
            self.cgroup.resources.blkio.throttle_read_bps_device.push(throttle);
        }
        self
    }

    /// Limit the write rate of the current metric for a certain device.
    pub fn write(mut self, major: u64, minor: u64, rate: u64)
        -> BlkIoResourcesBuilder<'a> {
        self.cgroup.resources.blkio.update_values = true;
        let throttle = BlkIoDeviceThrottleResource {
            major,
            minor,
            rate,
        };
        if self.throttling_iops {
            self.cgroup.resources.blkio.throttle_write_iops_device.push(throttle);
        } else {
            self.cgroup.resources.blkio.throttle_write_bps_device.push(throttle);
        }
        self
    }

    /// Finish the construction of the blkio resources of a control group.
    pub fn done(self) -> CgroupBuilder<'a> {
        self.cgroup
    }
}