mirror of
https://github.com/kata-containers/cgroups-rs.git
synced 2026-08-05 02:13:23 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a7fd32e4f | ||
|
|
3961c4b0dd | ||
|
|
fdcf75b27b | ||
|
|
7cd1cda42f | ||
|
|
0236d210d5 | ||
|
|
0d1029646c | ||
|
|
a32f96e473 | ||
|
|
acad18f4a5 | ||
|
|
3eeab4ef1c | ||
|
|
b99114bf40 | ||
|
|
f44ae5d4da | ||
|
|
cf4c62dd34 | ||
|
|
c1a99fff50 | ||
|
|
6a11b32b64 | ||
|
|
a30729bcf1 | ||
|
|
69e3897a6d | ||
|
|
c49bee218f |
3
.github/workflows/bvt.yaml
vendored
3
.github/workflows/bvt.yaml
vendored
@@ -1,7 +1,7 @@
|
||||
name: BVT
|
||||
on: [pull_request]
|
||||
env:
|
||||
RUST_VERSION: 1.85.1
|
||||
RUST_VERSION: 1.90.0
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
@@ -35,4 +35,3 @@ jobs:
|
||||
- run: rustup install ${{ env.RUST_VERSION }} && rustup default ${{ env.RUST_VERSION }}
|
||||
- run: make test
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ repository = "https://github.com/kata-containers/cgroups-rs"
|
||||
keywords = ["linux", "cgroup", "containers", "isolation"]
|
||||
categories = ["os", "api-bindings", "os::unix-apis"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
version = "0.4.0"
|
||||
version = "0.5.1"
|
||||
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>", "Levente Kurusa <lkurusa@acm.org>", "Sam Wilson <tecywiz121@hotmail.com>"]
|
||||
edition = "2018"
|
||||
homepage = "https://github.com/kata-containers/cgroups-rs"
|
||||
@@ -17,7 +17,7 @@ nix = { version = "0.25.0", default-features = false, features = ["event", "fs",
|
||||
libc = "0.2"
|
||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
thiserror = "1"
|
||||
oci-spec = { version = "0.8.1", optional = true }
|
||||
oci-spec = { version = "0.10.0", optional = true }
|
||||
zbus = "5.8"
|
||||
bit-vec = "0.6"
|
||||
|
||||
|
||||
15
README.md
15
README.md
@@ -1,15 +1,14 @@
|
||||
# cgroups-rs 
|
||||
Native Rust library for managing control groups under Linux
|
||||
# cgroups-rs
|
||||
|
||||
Both v1 and v2 of cgroups are supported.
|
||||
[](https://crates.io/crates/cgroups-rs)
|
||||
|
||||
# Examples
|
||||
Native Rust library for managing Linux control groups. Supports both cgroups v1 and v2.
|
||||
|
||||
## Create a control group using the builder pattern
|
||||
|
||||
``` rust
|
||||
## Examples
|
||||
|
||||
### Create a control group using the builder pattern
|
||||
|
||||
```rust
|
||||
use cgroups_rs::*;
|
||||
use cgroups_rs::cgroup_builder::*;
|
||||
|
||||
@@ -44,7 +43,7 @@ cg.delete();
|
||||
// major version change.
|
||||
```
|
||||
|
||||
# Disclaimer
|
||||
## Disclaimer
|
||||
|
||||
This crate is licensed under:
|
||||
|
||||
|
||||
@@ -84,9 +84,9 @@ impl Cgroup {
|
||||
if self.hier.v2() {
|
||||
create_v2_cgroup(self.hier.root(), &self.path, &self.specified_controllers)
|
||||
} else {
|
||||
for subsystem in &self.subsystems {
|
||||
subsystem.to_controller().create();
|
||||
}
|
||||
self.subsystems
|
||||
.iter()
|
||||
.try_for_each(|subsystem| subsystem.to_controller().create())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -550,18 +550,18 @@ fn create_v2_cgroup(
|
||||
// path: "a/b/c"
|
||||
let elements = path.split('/').collect::<Vec<&str>>();
|
||||
let last_index = elements.len() - 1;
|
||||
// Build up the directory hierarchy element by element, enabling the controllers for all
|
||||
// parents along the way.
|
||||
for (i, ele) in elements.iter().enumerate() {
|
||||
// ROOT/a
|
||||
fp.push(ele);
|
||||
// create dir, need not check if is a file or directory
|
||||
if !fp.exists() {
|
||||
if let Err(e) = std::fs::create_dir(fp.clone()) {
|
||||
return Err(Error::with_cause(ErrorKind::FsError, e));
|
||||
}
|
||||
// create dir if necessary
|
||||
if let Err(e) = std::fs::create_dir_all(fp.clone()) {
|
||||
return Err(Error::with_cause(ErrorKind::FsError, e));
|
||||
}
|
||||
|
||||
if i < last_index {
|
||||
// enable controllers for substree
|
||||
// enable controllers for subtree
|
||||
enable_controllers(&controllers, &fp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
//
|
||||
|
||||
#![allow(clippy::unnecessary_unwrap)]
|
||||
use log::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
@@ -165,20 +164,10 @@ mod sealed {
|
||||
false
|
||||
}
|
||||
|
||||
fn verify_path(&self) -> Result<()> {
|
||||
if self.get_path().starts_with(self.get_base()) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::new(ErrorKind::InvalidPath))
|
||||
}
|
||||
}
|
||||
|
||||
fn open_path(&self, p: &str, w: bool) -> Result<File> {
|
||||
let mut path = self.get_path().clone();
|
||||
path.push(p);
|
||||
|
||||
self.verify_path()?;
|
||||
|
||||
if w {
|
||||
match File::create(&path) {
|
||||
Err(e) => Err(Error::with_cause(
|
||||
@@ -214,10 +203,6 @@ mod sealed {
|
||||
|
||||
#[doc(hidden)]
|
||||
fn path_exists(&self, p: &str) -> bool {
|
||||
if self.verify_path().is_err() {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::path::Path::new(p).exists()
|
||||
}
|
||||
}
|
||||
@@ -265,7 +250,7 @@ pub trait Controller {
|
||||
fn apply(&self, res: &Resources) -> Result<()>;
|
||||
|
||||
/// Create this controller
|
||||
fn create(&self);
|
||||
fn create(&self) -> Result<()>;
|
||||
|
||||
/// Does this controller already exist?
|
||||
fn exists(&self) -> bool;
|
||||
@@ -323,14 +308,11 @@ where
|
||||
}
|
||||
|
||||
/// Create this controller
|
||||
fn create(&self) {
|
||||
self.verify_path()
|
||||
.unwrap_or_else(|_| panic!("path should be valid: {:?}", self.path()));
|
||||
|
||||
match ::std::fs::create_dir_all(self.get_path()) {
|
||||
Ok(_) => self.post_create(),
|
||||
Err(e) => warn!("error create_dir: {:?} error: {:?}", self.get_path(), e),
|
||||
}
|
||||
fn create(&self) -> Result<()> {
|
||||
std::fs::create_dir_all(self.get_path())
|
||||
.map_err(|err| Error::with_cause(ErrorKind::FsError, err))?;
|
||||
self.post_create();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set notify_on_release
|
||||
|
||||
15
src/lib.rs
15
src/lib.rs
@@ -72,22 +72,11 @@ pub mod tests {
|
||||
child
|
||||
}
|
||||
|
||||
pub fn systemd_version() -> Option<usize> {
|
||||
pub fn systemd_version() -> Option<String> {
|
||||
let output = Command::new("systemd").arg("--version").output().ok()?; // Return None if command execution fails
|
||||
|
||||
if !output.status.success() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
|
||||
// The first line is typically like "systemd 254 (254.5-1-arch)"
|
||||
let first_line = stdout.lines().next()?;
|
||||
let mut words = first_line.split_whitespace();
|
||||
|
||||
words.next()?; // Skip the "systemd" word
|
||||
let version_str = words.next()?; // The version number as string
|
||||
|
||||
version_str.parse::<usize>().ok()
|
||||
Some(String::from_utf8_lossy(&output.stdout).to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,31 +91,21 @@ impl SystemdManager<'_> {
|
||||
&self.unit
|
||||
}
|
||||
|
||||
fn set_cpuset(
|
||||
&self,
|
||||
props: &mut Vec<Property>,
|
||||
linux_cpu: &LinuxCpu,
|
||||
systemd_version: usize,
|
||||
) -> Result<()> {
|
||||
fn set_cpuset(&self, props: &mut Vec<Property>, linux_cpu: &LinuxCpu) -> Result<()> {
|
||||
if let Some(cpus) = linux_cpu.cpus().as_ref() {
|
||||
let (id, value) = cpuset::cpus(cpus, systemd_version)?;
|
||||
let (id, value) = cpuset::cpus(cpus)?;
|
||||
props.push((id, value.into()));
|
||||
}
|
||||
|
||||
if let Some(mems) = linux_cpu.mems().as_ref() {
|
||||
let (id, value) = cpuset::mems(mems, systemd_version)?;
|
||||
let (id, value) = cpuset::mems(mems)?;
|
||||
props.push((id, value.into()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_cpu(
|
||||
&self,
|
||||
props: &mut Vec<Property>,
|
||||
linux_cpu: &LinuxCpu,
|
||||
systemd_version: usize,
|
||||
) -> Result<()> {
|
||||
fn set_cpu(&self, props: &mut Vec<Property>, linux_cpu: &LinuxCpu) -> Result<()> {
|
||||
if let Some(shares) = linux_cpu.shares() {
|
||||
let shares = if self.v2() {
|
||||
conv::cpu_shares_to_cgroup_v2(shares)
|
||||
@@ -130,7 +120,7 @@ impl SystemdManager<'_> {
|
||||
let quota = linux_cpu.quota().unwrap_or(0);
|
||||
|
||||
if period != 0 {
|
||||
let (id, value) = cpu::period(period, systemd_version)?;
|
||||
let (id, value) = cpu::period(period)?;
|
||||
props.push((id, value.into()));
|
||||
}
|
||||
|
||||
@@ -272,11 +262,9 @@ impl Manager for SystemdManager<'_> {
|
||||
fn set(&mut self, resources: &LinuxResources) -> Result<()> {
|
||||
let mut props = vec![];
|
||||
|
||||
let systemd_version = self.systemd_client.systemd_version()?;
|
||||
|
||||
if let Some(linux_cpu) = resources.cpu() {
|
||||
self.set_cpuset(&mut props, linux_cpu, systemd_version)?;
|
||||
self.set_cpu(&mut props, linux_cpu, systemd_version)?;
|
||||
self.set_cpuset(&mut props, linux_cpu)?;
|
||||
self.set_cpu(&mut props, linux_cpu)?;
|
||||
}
|
||||
|
||||
if let Some(linux_memory) = resources.memory() {
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 or MIT
|
||||
//
|
||||
|
||||
use crate::systemd::error::{Error, Result};
|
||||
use crate::systemd::{
|
||||
CPU_QUOTA_PERIOD_US, CPU_QUOTA_PER_SEC_US, CPU_SHARES, CPU_SYSTEMD_VERSION, CPU_WEIGHT,
|
||||
};
|
||||
use crate::systemd::error::Result;
|
||||
use crate::systemd::{CPU_QUOTA_PERIOD_US, CPU_QUOTA_PER_SEC_US, CPU_SHARES, CPU_WEIGHT};
|
||||
|
||||
/// Returns the property for CPU shares.
|
||||
///
|
||||
@@ -21,11 +19,7 @@ pub fn shares(shares: u64, v2: bool) -> Result<(&'static str, u64)> {
|
||||
}
|
||||
|
||||
/// Returns the property for CPU period.
|
||||
pub fn period(period: u64, systemd_version: usize) -> Result<(&'static str, u64)> {
|
||||
if systemd_version < CPU_SYSTEMD_VERSION {
|
||||
return Err(Error::ObsoleteSystemd);
|
||||
}
|
||||
|
||||
pub fn period(period: u64) -> Result<(&'static str, u64)> {
|
||||
Ok((CPU_QUOTA_PERIOD_US, period))
|
||||
}
|
||||
|
||||
|
||||
@@ -6,29 +6,19 @@
|
||||
use bit_vec::BitVec;
|
||||
|
||||
use crate::systemd::error::{Error, Result};
|
||||
use crate::systemd::{ALLOWED_CPUS, ALLOWED_MEMORY_NODES, CPUSET_SYSTEMD_VERSION};
|
||||
use crate::systemd::{ALLOWED_CPUS, ALLOWED_MEMORY_NODES};
|
||||
|
||||
const BYTE_IN_BITS: usize = 8;
|
||||
|
||||
/// Returns the property for cpuset CPUs.
|
||||
pub fn cpus(cpus: &str, systemd_version: usize) -> Result<(&'static str, Vec<u8>)> {
|
||||
if systemd_version < CPUSET_SYSTEMD_VERSION {
|
||||
return Err(Error::ObsoleteSystemd);
|
||||
}
|
||||
|
||||
pub fn cpus(cpus: &str) -> Result<(&'static str, Vec<u8>)> {
|
||||
let mask = convert_list_to_mask(cpus)?;
|
||||
|
||||
Ok((ALLOWED_CPUS, mask))
|
||||
}
|
||||
|
||||
/// Returns the property for cpuset memory nodes.
|
||||
pub fn mems(mems: &str, systemd_version: usize) -> Result<(&'static str, Vec<u8>)> {
|
||||
if systemd_version < CPUSET_SYSTEMD_VERSION {
|
||||
return Err(Error::ObsoleteSystemd);
|
||||
}
|
||||
|
||||
pub fn mems(mems: &str) -> Result<(&'static str, Vec<u8>)> {
|
||||
let mask = convert_list_to_mask(mems)?;
|
||||
|
||||
Ok((ALLOWED_MEMORY_NODES, mask))
|
||||
}
|
||||
|
||||
|
||||
@@ -143,21 +143,6 @@ impl SystemdClient<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the systemd version.
|
||||
pub fn systemd_version(&self) -> Result<usize> {
|
||||
let sys_proxy = systemd_manager_proxy()?;
|
||||
|
||||
// Parse 249 from "249.11-0ubuntu3.16"
|
||||
let version = sys_proxy.version()?;
|
||||
let version = version
|
||||
.split('.')
|
||||
.next()
|
||||
.and_then(|v| v.parse::<usize>().ok())
|
||||
.ok_or(Error::CorruptedSystemdVersion(version))?;
|
||||
|
||||
Ok(version)
|
||||
}
|
||||
|
||||
/// Check if the unit exists.
|
||||
pub fn exists(&self) -> bool {
|
||||
let sys_proxy = match systemd_manager_proxy() {
|
||||
@@ -216,7 +201,7 @@ pub mod tests {
|
||||
use crate::systemd::props::PropertiesBuilder;
|
||||
use crate::systemd::utils::expand_slice;
|
||||
use crate::systemd::{DEFAULT_DESCRIPTION, DESCRIPTION, PIDS};
|
||||
use crate::tests::{spawn_sleep_inf, spawn_yes, systemd_version};
|
||||
use crate::tests::{spawn_sleep_inf, spawn_yes};
|
||||
|
||||
const TEST_SLICE: &str = "cgroupsrs-test.slice";
|
||||
|
||||
@@ -248,7 +233,7 @@ pub mod tests {
|
||||
String::from_utf8_lossy(&output.stdout).to_string()
|
||||
}
|
||||
|
||||
fn start_default_cgroup(pid: CgroupPid, unit: &str) -> SystemdClient {
|
||||
fn start_default_cgroup(pid: CgroupPid, unit: &'_ str) -> SystemdClient<'_> {
|
||||
let mut props = PropertiesBuilder::default_cgroup(TEST_SLICE, unit).build();
|
||||
props.push((PIDS, Value::Array(vec![pid.pid as u32].into())));
|
||||
let cgroup = SystemdClient::new(unit, props).unwrap();
|
||||
@@ -504,19 +489,6 @@ pub mod tests {
|
||||
child.wait().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_systemd_version() {
|
||||
skip_if_no_systemd!();
|
||||
|
||||
let unit = test_unit();
|
||||
let props = PropertiesBuilder::default_cgroup(TEST_SLICE, &unit).build();
|
||||
let cgroup = SystemdClient::new(&unit, props).unwrap();
|
||||
let version = cgroup.systemd_version().unwrap();
|
||||
|
||||
let expected_version = systemd_version().unwrap();
|
||||
assert_eq!(version, expected_version, "Systemd version mismatch");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_exists() {
|
||||
skip_if_no_systemd!();
|
||||
|
||||
@@ -12,7 +12,4 @@ pub enum Error {
|
||||
|
||||
#[error("dbus error: {0}")]
|
||||
Dbus(#[from] zbus::Error),
|
||||
|
||||
#[error("corrupted systemd version: {0}")]
|
||||
CorruptedSystemdVersion(String),
|
||||
}
|
||||
|
||||
@@ -10,9 +10,6 @@ pub enum Error {
|
||||
#[error("invalid argument")]
|
||||
InvalidArgument,
|
||||
|
||||
#[error("obsolete systemd, please upgrade your systemd")]
|
||||
ObsoleteSystemd,
|
||||
|
||||
#[error("resource not supported by cgroups v1")]
|
||||
CgroupsV1NotSupported,
|
||||
}
|
||||
|
||||
@@ -20,6 +20,3 @@ pub const DEFAULT_SLICE: &str = "system.slice";
|
||||
|
||||
pub const SLICE_SUFFIX: &str = ".slice";
|
||||
pub const SCOPE_SUFFIX: &str = ".scope";
|
||||
|
||||
pub const CPU_SYSTEMD_VERSION: usize = 242;
|
||||
pub const CPUSET_SYSTEMD_VERSION: usize = 244;
|
||||
|
||||
Reference in New Issue
Block a user