You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
4.2 KiB
Rust

use std::fmt::{Display, Formatter};
use nix::sys::signal::kill;
use nix::unistd::Pid;
use nix::sys::signal::Signal;
use serde::de::value;
use std::path::Path;
use crate::{create_dir, get_container_info, ContainerInfo};
use crate::error::Result;
static CGROUP_PATH: &str = "/sys/fs/cgroup/rocker";
pub enum CgroupLevel {
V1,
V2,
V3,
V4,
V5,
V6,
V7,
V8,
V9,
}
impl From<&str> for CgroupLevel {
fn from(value: &str) -> Self {
match value {
"v1" => CgroupLevel::V1,
"v2" => CgroupLevel::V2,
"v3" => CgroupLevel::V3,
"v4" => CgroupLevel::V4,
"v5" => CgroupLevel::V5,
"v6" => CgroupLevel::V6,
"v7" => CgroupLevel::V7,
"v8" => CgroupLevel::V8,
"v9" => CgroupLevel::V9,
_ => todo!("invalid cgroup level"),
}
}
}
impl Display for CgroupLevel {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::V1 => write!(f, "v1"),
Self::V2 => write!(f, "v2"),
Self::V3 => write!(f, "v3"),
Self::V4 => write!(f, "v4"),
Self::V5 => write!(f, "v5"),
Self::V6 => write!(f, "v6"),
Self::V7 => write!(f, "v7"),
Self::V8 => write!(f, "v8"),
Self::V9 => write!(f, "v9"),
}
}
}
impl Default for CgroupLevel {
fn default() -> Self {
CgroupLevel::V1
}
}
pub struct Cgroup {
pub procs: Vec<i32>,
pub populated: i32
}
impl From<&str> for Cgroup {
fn from(container_id: &str) -> Self {
let cgroup_path = format!("{CGROUP_PATH}/{}", container_id);
let procs = std::fs::read_to_string(format!("{cgroup_path}/cgroup.procs"))
.unwrap_or_default()
.lines()
.filter_map(|pid|pid.parse::<i32>().ok())
.collect();
// 找到 cgroup.events 第一行的值
let populated = std::fs::read_to_string(format!("{cgroup_path}/cgroup.events"))
.unwrap_or_default()
.lines()
.next()
.unwrap_or_default()
.split(" ")
.nth(1)
.unwrap_or("0")
.parse::<i32>()
.unwrap_or_default();
Self {
procs,
populated
}
}
}
impl Cgroup {
pub fn create(container_id: &str, pid: i32, cgroup_s: &str) -> Result<()> {
let cgroup_path = format!("{CGROUP_PATH}/{container_id}");
create_dir(&cgroup_path, false)?;
// 根据 cgroup_s 写入指定参数
let _ = cgroup_s.split(" ")
.map(|s|s.split("="))
.map(|mut x|(x.next(), x.next()))
.filter_map(|(dev, value)| {
if let (Some(dev), Ok(value)) = (dev, value.unwrap_or("").parse::<i32>()) {
Some((dev, value))
} else {
None
}
}).for_each(|(dev, value)| {
match (dev, value) {
("cpu", 1..=100) => {
if let Ok(_) = std::fs::write(format!("{cgroup_path}/cpu.max"), format!("{} 100000", 100000 / 100 * value)) {
println!("cpu 限制 {value}% 成功")
}
}
("memory", 1..=4096) => {
}
_ => {
println!("🔴 没有定义的 cgroup 参数: {dev}={value}")
}
}
});
// 加入控制组
std::fs::write(format!("{cgroup_path}/cgroup.procs"), pid.to_string())?;
Ok(())
}
pub fn remove(container_id: &str) {
let _self = Self::from(container_id);
for pid in _self.procs {
let _ = kill(Pid::from_raw(pid), Signal::SIGKILL);
let pid_path = Path::new("/proc").join(pid.to_string());
(0..100).any(|i|{
std::thread::sleep(std::time::Duration::from_millis(i));
pid_path.exists() == false
});
}
let cgroup_path = format!("{CGROUP_PATH}/{container_id}");
let _ = std::fs::remove_dir(&cgroup_path);
println!("删除cgroup {cgroup_path}")
}
}