Skip to content

Commit

Permalink
Add support for cgroups managed by systemd
Browse files Browse the repository at this point in the history
  • Loading branch information
nimrodshn committed May 29, 2021
1 parent 37243cd commit e3f4c5f
Show file tree
Hide file tree
Showing 16 changed files with 171 additions and 137 deletions.
4 changes: 1 addition & 3 deletions src/capabilities.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::{
command::Command,
};
use crate::command::Command;
use caps::*;

use anyhow::Result;
Expand Down
4 changes: 1 addition & 3 deletions src/cgroups/blkio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ use std::{
path::Path,
};

use crate::{
cgroups::Controller,
};
use crate::cgroups::Controller;
use oci_spec::{LinuxBlockIo, LinuxResources};

const CGROUP_BLKIO_THROTTLE_READ_BPS: &str = "blkio.throttle.read_bps_device";
Expand Down
107 changes: 107 additions & 0 deletions src/cgroups/cgroupsfs_manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use crate::cgroups::Manager;
use std::{collections::HashMap, path::PathBuf};
use std::{fs::remove_dir, path::Path};

use anyhow::Result;
use nix::unistd::Pid;
use procfs::process::Process;

use super::{
blkio::Blkio, devices::Devices, hugetlb::Hugetlb, memory::Memory,
network_classifier::NetworkClassifier, network_priority::NetworkPriority, pids::Pids,
Controller,
};
use crate::{cgroups::ControllerType, utils::PathBufExt};
use oci_spec::LinuxResources;

const CONTROLLERS: &[ControllerType] = &[
ControllerType::Devices,
ControllerType::HugeTlb,
ControllerType::Memory,
ControllerType::Pids,
ControllerType::Blkio,
ControllerType::NetworkPriority,
ControllerType::NetworkClassifier,
];

pub struct CGroupsFSManager {
subsystems: HashMap<String, PathBuf>,
}

impl CGroupsFSManager {
pub fn new(cgroup_path: PathBuf) -> Result<Self> {
let mut subsystems = HashMap::<String, PathBuf>::new();
for subsystem in CONTROLLERS.iter().map(|c| c.to_string()) {
subsystems.insert(
subsystem.to_owned(),
Self::get_subsystem_path(&cgroup_path, &subsystem)?,
);
}

Ok(CGroupsFSManager { subsystems })
}

fn get_subsystem_path(cgroup_path: &Path, subsystem: &str) -> anyhow::Result<PathBuf> {
log::debug!("Get path for subsystem: {}", subsystem);
let mount = Process::myself()?
.mountinfo()?
.into_iter()
.find(|m| {
if m.fs_type == "cgroup" {
// Some systems mount net_prio and net_cls in the same directory
// other systems mount them in their own diretories. This
// should handle both cases.
if subsystem == "net_cls" || subsystem == "net_prio" {
return m.mount_point.ends_with("net_cls,net_prio")
|| m.mount_point.ends_with("net_prio,net_cls");
}
}
m.mount_point.ends_with(subsystem)
})
.unwrap();

let cgroup = Process::myself()?
.cgroups()?
.into_iter()
.find(|c| c.controllers.contains(&subsystem.to_owned()))
.unwrap();

let p = if cgroup_path.to_string_lossy().into_owned().is_empty() {
mount
.mount_point
.join_absolute_path(Path::new(&cgroup.pathname))?
} else {
mount.mount_point.join_absolute_path(&cgroup_path)?
};

Ok(p)
}
}

impl Manager for CGroupsFSManager {
fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> {
for subsys in &self.subsystems {
match subsys.0.as_str() {
"devices" => Devices::apply(linux_resources, &subsys.1, pid)?,
"hugetlb" => Hugetlb::apply(linux_resources, &subsys.1, pid)?,
"memory" => Memory::apply(linux_resources, &subsys.1, pid)?,
"pids" => Pids::apply(linux_resources, &subsys.1, pid)?,
"blkio" => Blkio::apply(linux_resources, &subsys.1, pid)?,
"net_prio" => NetworkPriority::apply(linux_resources, &subsys.1, pid)?,
"net_cls" => NetworkClassifier::apply(linux_resources, &subsys.1, pid)?,
_ => continue,
}
}
Ok(())
}

fn remove(&self) -> Result<()> {
for cgroup_path in &self.subsystems {
if cgroup_path.1.exists() {
log::debug!("remove cgroup {:?}", cgroup_path.1);
remove_dir(&cgroup_path.1)?;
}
}
Ok(())
}
}
5 changes: 1 addition & 4 deletions src/cgroups/devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ use std::{
use anyhow::Result;
use nix::unistd::Pid;

use crate::{
cgroups::Controller,
rootfs::default_devices,
};
use crate::{cgroups::Controller, rootfs::default_devices};
use oci_spec::{LinuxDeviceCgroup, LinuxDeviceType, LinuxResources};

pub struct Devices {}
Expand Down
4 changes: 1 addition & 3 deletions src/cgroups/hugetlb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ use std::{
use anyhow::anyhow;
use regex::Regex;

use crate::{
cgroups::Controller,
};
use crate::cgroups::Controller;
use oci_spec::{LinuxHugepageLimit, LinuxResources};

pub struct Hugetlb {}
Expand Down
103 changes: 4 additions & 99 deletions src/cgroups/manager.rs
Original file line number Diff line number Diff line change
@@ -1,106 +1,11 @@
use std::{collections::HashMap, path::PathBuf};
use std::{fs::remove_dir, path::Path};

use anyhow::Result;
use nix::unistd::Pid;
use procfs::process::Process;

use crate::{cgroups::ControllerType, utils::PathBufExt};
use crate::{cgroups::ControllerType, utils::PathBufExt};
use oci_spec::LinuxResources;
use super::{
blkio::Blkio, devices::Devices, hugetlb::Hugetlb, memory::Memory,
network_classifier::NetworkClassifier, network_priority::NetworkPriority, pids::Pids,
Controller,
};

const CONTROLLERS: &[ControllerType] = &[
ControllerType::Devices,
ControllerType::HugeTlb,
ControllerType::Memory,
ControllerType::Pids,
ControllerType::Blkio,
ControllerType::NetworkPriority,
ControllerType::NetworkClassifier,
];

pub struct Manager {
subsystems: HashMap<String, PathBuf>,
}

impl Manager {
pub fn new(cgroup_path: PathBuf) -> Result<Self> {
let mut subsystems = HashMap::<String, PathBuf>::new();
for subsystem in CONTROLLERS.iter().map(|c| c.to_string()) {
subsystems.insert(
subsystem.to_owned(),
Self::get_subsystem_path(&cgroup_path, &subsystem)?,
);
}

Ok(Manager { subsystems })
}

pub fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> {
for subsys in &self.subsystems {
match subsys.0.as_str() {
"devices" => Devices::apply(linux_resources, &subsys.1, pid)?,
"hugetlb" => Hugetlb::apply(linux_resources, &subsys.1, pid)?,
"memory" => Memory::apply(linux_resources, &subsys.1, pid)?,
"pids" => Pids::apply(linux_resources, &subsys.1, pid)?,
"blkio" => Blkio::apply(linux_resources, &subsys.1, pid)?,
"net_prio" => NetworkPriority::apply(linux_resources, &subsys.1, pid)?,
"net_cls" => NetworkClassifier::apply(linux_resources, &subsys.1, pid)?,
_ => continue,
}
}

Ok(())
}

pub fn remove(&self) -> Result<()> {
for cgroup_path in &self.subsystems {
if cgroup_path.1.exists() {
log::debug!("remove cgroup {:?}", cgroup_path.1);
remove_dir(&cgroup_path.1)?;
}
}

Ok(())
}

fn get_subsystem_path(cgroup_path: &Path, subsystem: &str) -> anyhow::Result<PathBuf> {
log::debug!("Get path for subsystem: {}", subsystem);
let mount = Process::myself()?
.mountinfo()?
.into_iter()
.find(|m| {
if m.fs_type == "cgroup" {
// Some systems mount net_prio and net_cls in the same directory
// other systems mount them in their own diretories. This
// should handle both cases.
if subsystem == "net_cls" || subsystem == "net_prio" {
return m.mount_point.ends_with("net_cls,net_prio")
|| m.mount_point.ends_with("net_prio,net_cls");
}
}
m.mount_point.ends_with(subsystem)
})
.unwrap();

let cgroup = Process::myself()?
.cgroups()?
.into_iter()
.find(|c| c.controllers.contains(&subsystem.to_owned()))
.unwrap();

let p = if cgroup_path.to_string_lossy().into_owned().is_empty() {
mount
.mount_point
.join_absolute_path(Path::new(&cgroup.pathname))?
} else {
mount.mount_point.join_absolute_path(&cgroup_path)?
};

Ok(p)
}
pub trait Manager {
fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()>;
fn remove(&self) -> Result<()>;
}
4 changes: 1 addition & 3 deletions src/cgroups/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ use std::{
use anyhow::{Result, *};
use nix::{errno::Errno, unistd::Pid};

use crate::{
cgroups::Controller,
};
use crate::cgroups::Controller;
use oci_spec::{LinuxMemory, LinuxResources};

const CGROUP_MEMORY_SWAP_LIMIT: &str = "memory.memsw.limit_in_bytes";
Expand Down
6 changes: 5 additions & 1 deletion src/cgroups/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
mod blkio;
mod cgroupsfs_manager;
mod controller;
mod controller_type;
mod devices;
mod hugetlb;
mod blkio;
mod manager;
mod memory;
mod network_classifier;
mod network_priority;
mod pids;
mod systemd_manager;
pub use cgroupsfs_manager::CGroupsFSManager;
pub use controller::Controller;
pub use controller_type::ControllerType;
pub use manager::Manager;
pub use systemd_manager::SystemDCGroupManager;
4 changes: 1 addition & 3 deletions src/cgroups/network_classifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ use std::{
use anyhow::Result;
use nix::unistd::Pid;

use crate::{
cgroups::Controller,
};
use crate::cgroups::Controller;
use oci_spec::{LinuxNetwork, LinuxResources};

pub struct NetworkClassifier {}
Expand Down
4 changes: 1 addition & 3 deletions src/cgroups/pids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ use std::{

use anyhow::Result;

use crate::{
cgroups::Controller,
};
use crate::cgroups::Controller;
use oci_spec::{LinuxPids, LinuxResources};

pub struct Pids {}
Expand Down
16 changes: 16 additions & 0 deletions src/cgroups/systemd_manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use crate::cgroups::Manager;
use anyhow::Result;
use nix::unistd::Pid;
use oci_spec::LinuxResources;

pub struct SystemDCGroupManager;

impl Manager for SystemDCGroupManager {
fn apply(&self, linux_resources: &LinuxResources, pid: Pid) -> Result<()> {
Ok(())
}

fn remove(&self) -> Result<()> {
Ok(())
}
}
18 changes: 14 additions & 4 deletions src/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ use crate::namespaces::Namespaces;
use crate::notify_socket::NotifyListener;
use crate::process::{fork, Process};
use crate::rootfs;
use oci_spec;
use crate::stdio::FileDescriptor;
use crate::tty;
use crate::utils;
use crate::{capabilities, command::Command};
use oci_spec;

#[derive(Clap, Debug)]
pub struct Create {
Expand All @@ -32,7 +32,12 @@ pub struct Create {
}

impl Create {
pub fn exec(&self, root_path: PathBuf, command: impl Command) -> Result<()> {
pub fn exec(
&self,
root_path: PathBuf,
systemd_cgroup: bool,
command: impl Command,
) -> Result<()> {
let container_dir = root_path.join(&self.container_id);
if !container_dir.exists() {
fs::create_dir(&container_dir).unwrap();
Expand Down Expand Up @@ -79,6 +84,7 @@ impl Create {
rootfs,
spec,
csocketfd,
systemd_cgroup,
container,
command,
)?;
Expand All @@ -95,14 +101,18 @@ fn run_container<P: AsRef<Path>>(
rootfs: PathBuf,
spec: oci_spec::Spec,
csocketfd: Option<FileDescriptor>,
systemd_cgroup: bool,
container: Container,
command: impl Command,
) -> Result<Process> {
prctl::set_dumpable(false).unwrap();
let linux = spec.linux.as_ref().unwrap();
let namespaces: Namespaces = linux.namespaces.clone().into();

let cmanager = cgroups::Manager::new(linux.cgroups_path.clone())?;
let cmanager: Box<dyn cgroups::Manager> = match systemd_cgroup {
true => Box::new(cgroups::SystemDCGroupManager),
false => Box::new(cgroups::CGroupsFSManager::new(linux.cgroups_path.clone())?),
};

match fork::fork_first(
pid_file,
Expand All @@ -111,7 +121,7 @@ fn run_container<P: AsRef<Path>>(
.contains(sched::CloneFlags::CLONE_NEWUSER),
linux,
&container,
&cmanager,
cmanager,
)? {
Process::Parent(parent) => Ok(Process::Parent(parent)),
Process::Child(child) => {
Expand Down
Loading

0 comments on commit e3f4c5f

Please sign in to comment.