mirror of
https://github.com/kata-containers/cgroups-rs.git
synced 2026-08-05 02:13:23 +00:00
Builder pattern for control groups
Signed-off-by: Levente Kurusa <lkurusa@acm.org>
This commit is contained in:
17
src/blkio.rs
17
src/blkio.rs
@@ -279,6 +279,7 @@ impl ControllerInternal for BlkIoController {
|
||||
|
||||
for dev in &res.weight_device {
|
||||
let _ = self.set_weight_for_device(dev.major, dev.minor, dev.weight as u64);
|
||||
let _ = self.set_leaf_weight_for_device(dev.major, dev.minor, dev.leaf_weight as u64);
|
||||
}
|
||||
|
||||
for dev in &res.throttle_read_bps_device {
|
||||
@@ -587,14 +588,22 @@ impl BlkIoController {
|
||||
}
|
||||
|
||||
/// Same as `set_leaf_weight()`, but settable per each block device.
|
||||
pub fn set_leaf_weight_for_device(&self, d: String) -> Result<()> {
|
||||
pub fn set_leaf_weight_for_device(
|
||||
&self,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
weight: u64,
|
||||
) -> Result<()> {
|
||||
self.open_path("blkio.leaf_weight_device", true)
|
||||
.and_then(|mut file| file.write_all(d.as_ref()).map_err(|e| Error::with_cause(WriteFailed, e)))
|
||||
.and_then(|mut file| {
|
||||
file.write_all(format!("{}:{} {}", major, minor, weight).as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
/// Reset the statistics the kernel has gathered so far and start fresh.
|
||||
pub fn reset_stats(&self) -> Result<()> {
|
||||
self.open_path("blkio.leaf_weight_device", true)
|
||||
self.open_path("blkio.reset_stats", true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all("1".to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
@@ -662,7 +671,7 @@ impl BlkIoController {
|
||||
|
||||
/// Set the weight of the control group's tasks.
|
||||
pub fn set_weight(&self, w: u64) -> Result<()> {
|
||||
self.open_path("blkio.leaf_weight", true)
|
||||
self.open_path("blkio.weight", true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(w.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
|
||||
322
src/cgroup_builder.rs
Normal file
322
src/cgroup_builder.rs
Normal file
@@ -0,0 +1,322 @@
|
||||
//! This module allows the user to create a control group using the Builder pattern.
|
||||
use error::*;
|
||||
|
||||
use {pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy, HugePageResource, NetworkPriority, Resources};
|
||||
|
||||
// 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![Read, Write, MkNod]
|
||||
// .device(6, 1, DeviceType::Char, false, vec![])
|
||||
// .done()
|
||||
// .network()
|
||||
// .class_id(1337)
|
||||
// .priority("eth0", 100)
|
||||
// .priority("wl0", 200)
|
||||
// .done()
|
||||
// .hugepages()
|
||||
// .limit("2M", 0)
|
||||
// .limit("4M", 4 * 1024 * 1024 * 100)
|
||||
// .limit("2G", 2 * 1024 * 1024 * 1024)
|
||||
// .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();
|
||||
//
|
||||
|
||||
|
||||
macro_rules! gen_setter {
|
||||
($res:ident, $name:ident, $ty:ty) => {
|
||||
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:
|
||||
///
|
||||
/// # Example
|
||||
/// Bla bla. TODO.
|
||||
pub struct CgroupBuilder<'a> {
|
||||
name: String,
|
||||
hierarchy: &'a Hierarchy,
|
||||
/// Internal, unsupported field: use the associated builders instead.
|
||||
resources: Resources, // XXX: this should not be public.
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn memory(self) -> MemoryResourceBuilder<'a> {
|
||||
MemoryResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pid(self) -> PidResourceBuilder<'a> {
|
||||
PidResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cpu(self) -> CpuResourceBuilder<'a> {
|
||||
CpuResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn devices(self) -> DeviceResourceBuilder<'a> {
|
||||
DeviceResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn network(self) -> NetworkResourceBuilder<'a> {
|
||||
NetworkResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hugepages(self) -> HugepagesResourceBuilder<'a> {
|
||||
HugepagesResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MemoryResourceBuilder<'a> {
|
||||
cgroup: CgroupBuilder<'a>,
|
||||
}
|
||||
|
||||
impl<'a> MemoryResourceBuilder<'a> {
|
||||
|
||||
gen_setter!(memory, kernel_memory_limit, u64);
|
||||
gen_setter!(memory, memory_hard_limit, u64);
|
||||
gen_setter!(memory, memory_soft_limit, u64);
|
||||
gen_setter!(memory, kernel_tcp_memory_limit, u64);
|
||||
gen_setter!(memory, memory_swap_limit, u64);
|
||||
gen_setter!(memory, swappiness, u64);
|
||||
|
||||
pub fn done(self) -> CgroupBuilder<'a> {
|
||||
self.cgroup
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PidResourceBuilder<'a> {
|
||||
cgroup: CgroupBuilder<'a>,
|
||||
}
|
||||
|
||||
impl<'a> PidResourceBuilder<'a> {
|
||||
|
||||
gen_setter!(pid, maximum_number_of_processes, pid::PidMax);
|
||||
|
||||
pub fn done(self) -> CgroupBuilder<'a> {
|
||||
self.cgroup
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CpuResourceBuilder<'a> {
|
||||
cgroup: CgroupBuilder<'a>,
|
||||
}
|
||||
|
||||
impl<'a> CpuResourceBuilder<'a> {
|
||||
|
||||
gen_setter!(cpu, cpus, String);
|
||||
gen_setter!(cpu, mems, String);
|
||||
gen_setter!(cpu, shares, u64);
|
||||
gen_setter!(cpu, quota, i64);
|
||||
gen_setter!(cpu, period, u64);
|
||||
gen_setter!(cpu, realtime_runtime, i64);
|
||||
gen_setter!(cpu, realtime_period, u64);
|
||||
|
||||
pub fn done(self) -> CgroupBuilder<'a> {
|
||||
self.cgroup
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DeviceResourceBuilder<'a> {
|
||||
cgroup: CgroupBuilder<'a>,
|
||||
}
|
||||
|
||||
impl<'a> DeviceResourceBuilder<'a> {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
pub fn done(self) -> CgroupBuilder<'a> {
|
||||
self.cgroup
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NetworkResourceBuilder<'a> {
|
||||
cgroup: CgroupBuilder<'a>,
|
||||
}
|
||||
|
||||
impl<'a> NetworkResourceBuilder<'a> {
|
||||
|
||||
gen_setter!(network, class_id, u64);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
pub fn done(self) -> CgroupBuilder<'a> {
|
||||
self.cgroup
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HugepagesResourceBuilder<'a> {
|
||||
cgroup: CgroupBuilder<'a>,
|
||||
}
|
||||
|
||||
impl<'a> HugepagesResourceBuilder<'a> {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
pub fn done(self) -> CgroupBuilder<'a> {
|
||||
self.cgroup
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BlkIoResourcesBuilder<'a> {
|
||||
cgroup: CgroupBuilder<'a>,
|
||||
throttling_iops: bool,
|
||||
}
|
||||
|
||||
impl<'a> BlkIoResourcesBuilder<'a> {
|
||||
|
||||
gen_setter!(blkio, weight, u16);
|
||||
gen_setter!(blkio, leaf_weight, u16);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
pub fn throttle_iops(mut self) -> BlkIoResourcesBuilder<'a> {
|
||||
self.throttling_iops = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn throttle_bps(mut self) -> BlkIoResourcesBuilder<'a> {
|
||||
self.throttling_iops = false;
|
||||
self
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
pub fn done(self) -> CgroupBuilder<'a> {
|
||||
self.cgroup
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ impl HugeTlbController {
|
||||
/// Set the limit (in bytes) of how much memory can be backed by hugepages of a certain size
|
||||
/// (`hugetlb_size`).
|
||||
pub fn set_limit_in_bytes(&self, hugetlb_size: &String, limit: u64) -> Result<()> {
|
||||
self.open_path(&format!("hugetlb.{}.limit_in_bytes", hugetlb_size), false)
|
||||
self.open_path(&format!("hugetlb.{}.limit_in_bytes", hugetlb_size), true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
|
||||
@@ -21,6 +21,7 @@ pub mod net_prio;
|
||||
pub mod perf_event;
|
||||
pub mod pid;
|
||||
pub mod rdma;
|
||||
pub mod cgroup_builder;
|
||||
|
||||
use blkio::BlkIoController;
|
||||
use cpu::CpuController;
|
||||
|
||||
145
tests/builder.rs
Normal file
145
tests/builder.rs
Normal file
@@ -0,0 +1,145 @@
|
||||
//! Some simple tests covering the builder pattern for control groups.
|
||||
extern crate cgroups;
|
||||
use cgroups::*;
|
||||
use cgroups::cpu::*;
|
||||
use cgroups::devices::*;
|
||||
use cgroups::pid::*;
|
||||
use cgroups::memory::*;
|
||||
use cgroups::net_cls::*;
|
||||
use cgroups::hugetlb::*;
|
||||
use cgroups::blkio::*;
|
||||
use cgroups::cgroup_builder::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_cpu_res_build() {
|
||||
let v1 = ::hierarchies::V1::new();
|
||||
let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build", &v1)
|
||||
.cpu()
|
||||
.shares(85)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
let cpu: &CpuController = cg.controller_of().unwrap();
|
||||
assert!(cpu.shares().is_ok());
|
||||
assert_eq!(cpu.shares().unwrap(), 85);
|
||||
}
|
||||
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_memory_res_build() {
|
||||
let v1 = ::hierarchies::V1::new();
|
||||
let cg: Cgroup = CgroupBuilder::new("test_memory_res_build", &v1)
|
||||
.memory()
|
||||
.kernel_memory_limit(128 * 1024 * 1024)
|
||||
.swappiness(70)
|
||||
.memory_hard_limit(1024 * 1024 * 1024)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
let c: &MemController = cg.controller_of().unwrap();
|
||||
assert_eq!(c.kmem_stat().limit_in_bytes, 128 * 1024 * 1024);
|
||||
assert_eq!(c.memory_stat().swappiness, 70);
|
||||
assert_eq!(c.memory_stat().limit_in_bytes, 1024 * 1024 * 1024);
|
||||
}
|
||||
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_pid_res_build() {
|
||||
let v1 = ::hierarchies::V1::new();
|
||||
let cg: Cgroup = CgroupBuilder::new("test_pid_res_build", &v1)
|
||||
.pid()
|
||||
.maximum_number_of_processes(PidMax::Value(123))
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
let c: &PidController = cg.controller_of().unwrap();
|
||||
assert!(c.get_pid_max().is_ok());
|
||||
assert_eq!(c.get_pid_max().unwrap(), PidMax::Value(123));
|
||||
}
|
||||
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // ignore this test for now, not sure why my kernel doesn't like it
|
||||
pub fn test_devices_res_build() {
|
||||
let v1 = ::hierarchies::V1::new();
|
||||
let cg: Cgroup = CgroupBuilder::new("test_devices_res_build", &v1)
|
||||
.devices()
|
||||
.device(1, 6, DeviceType::Char, true,
|
||||
vec![DevicePermissions::Read])
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
let c: &DevicesController = cg.controller_of().unwrap();
|
||||
assert!(c.allowed_devices().is_ok());
|
||||
assert_eq!(c.allowed_devices().unwrap(), vec![
|
||||
DeviceResource {
|
||||
allow: true,
|
||||
devtype: DeviceType::Char,
|
||||
major: 1,
|
||||
minor: 6,
|
||||
access: vec![DevicePermissions::Read],
|
||||
}
|
||||
]);
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_network_res_build() {
|
||||
let v1 = ::hierarchies::V1::new();
|
||||
let cg: Cgroup = CgroupBuilder::new("test_network_res_build", &v1)
|
||||
.network()
|
||||
.class_id(1337)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
let c: &NetClsController = cg.controller_of().unwrap();
|
||||
assert!(c.get_class().is_ok());
|
||||
assert_eq!(c.get_class().unwrap(), 1337);
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_hugepages_res_build() {
|
||||
let v1 = ::hierarchies::V1::new();
|
||||
let cg: Cgroup = CgroupBuilder::new("test_hugepages_res_build", &v1)
|
||||
.hugepages()
|
||||
.limit("2MB".to_string(), 4 * 2 * 1024 * 1024)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
let c: &HugeTlbController = cg.controller_of().unwrap();
|
||||
assert!(c.limit_in_bytes(&"2MB".to_string()).is_ok());
|
||||
assert_eq!(c.limit_in_bytes(&"2MB".to_string()).unwrap(), 4 * 2 * 1024 * 1024);
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_blkio_res_build() {
|
||||
let v1 = ::hierarchies::V1::new();
|
||||
let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build", &v1)
|
||||
.blkio()
|
||||
.weight(100)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
let c: &BlkIoController = cg.controller_of().unwrap();
|
||||
assert_eq!(c.blkio().weight, 100);
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
Reference in New Issue
Block a user