Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pause and resume command #139

Merged
merged 1 commit into from
Jul 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/cgroups/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{

use anyhow::{bail, Context, Result};
use nix::unistd::Pid;
use oci_spec::LinuxResources;
use oci_spec::{FreezerState, LinuxResources};
use procfs::process::Process;
use systemd::daemon::booted;

Expand All @@ -25,6 +25,8 @@ pub trait CgroupManager {
fn apply(&self, linux_resources: &LinuxResources) -> Result<()>;
/// Removes the cgroup
fn remove(&self) -> Result<()>;
// Sets the freezer cgroup to the specified state
fn freeze(&self, state: FreezerState) -> Result<()>;
}

#[derive(Debug)]
Expand Down
15 changes: 13 additions & 2 deletions src/cgroups/v1/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use super::{
use crate::cgroups::common::CGROUP_PROCS;
use crate::utils;
use crate::{cgroups::common::CgroupManager, utils::PathBufExt};
use oci_spec::LinuxResources;
use oci_spec::{FreezerState, LinuxResources};
pub struct Manager {
subsystems: HashMap<CtrlType, PathBuf>,
}
Expand Down Expand Up @@ -112,7 +112,7 @@ impl CgroupManager for Manager {
CtrlType::Blkio => Blkio::add_task(pid, subsys.1)?,
CtrlType::NetworkPriority => NetworkPriority::add_task(pid, subsys.1)?,
CtrlType::NetworkClassifier => NetworkClassifier::add_task(pid, subsys.1)?,
_ => continue,
CtrlType::Freezer => Freezer::add_task(pid, subsys.1)?,
}
}

Expand Down Expand Up @@ -159,4 +159,15 @@ impl CgroupManager for Manager {

Ok(())
}

fn freeze(&self, state: FreezerState) -> Result<()> {
let linux_resources = LinuxResources {
freezer: Some(state),
..Default::default()
};
Freezer::apply(
&linux_resources,
&self.subsystems.get(&CtrlType::Freezer).unwrap(),
)
}
}
10 changes: 9 additions & 1 deletion src/cgroups/v2/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{
use anyhow::{bail, Result};

use nix::unistd::Pid;
use oci_spec::LinuxResources;
use oci_spec::{FreezerState, LinuxResources};

use super::{
cpu::Cpu, cpuset::CpuSet, freezer::Freezer, hugetlb::HugeTlb, io::Io, memory::Memory,
Expand Down Expand Up @@ -146,4 +146,12 @@ impl CgroupManager for Manager {

Ok(())
}

fn freeze(&self, state: FreezerState) -> Result<()> {
let linux_resources = LinuxResources {
freezer: Some(state),
..Default::default()
};
Freezer::apply(&linux_resources, &self.full_path)
}
}
10 changes: 9 additions & 1 deletion src/cgroups/v2/systemd_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{

use anyhow::{anyhow, bail, Result};
use nix::unistd::Pid;
use oci_spec::LinuxResources;
use oci_spec::{FreezerState, LinuxResources};
use std::path::{Path, PathBuf};

use super::{
Expand Down Expand Up @@ -247,6 +247,14 @@ impl CgroupManager for SystemDCGroupManager {
fn remove(&self) -> Result<()> {
Ok(())
}

fn freeze(&self, state: FreezerState) -> Result<()> {
let linux_resources = LinuxResources {
freezer: Some(state),
..Default::default()
};
Freezer::apply(&linux_resources, &self.full_path)
}
}

#[cfg(test)]
Expand Down
17 changes: 16 additions & 1 deletion src/container/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use chrono::DateTime;
use nix::unistd::Pid;

use chrono::Utc;
use oci_spec::Spec;
use procfs::process::Process;

use crate::command::syscall::create_syscall;
Expand Down Expand Up @@ -56,7 +57,9 @@ impl Container {
match proc.stat.state().unwrap() {
ProcState::Zombie | ProcState::Dead => ContainerStatus::Stopped,
_ => match self.status() {
ContainerStatus::Creating | ContainerStatus::Created => self.status(),
ContainerStatus::Creating
| ContainerStatus::Created
| ContainerStatus::Paused => self.status(),
_ => ContainerStatus::Running,
},
}
Expand Down Expand Up @@ -98,6 +101,14 @@ impl Container {
self.state.status == ContainerStatus::Running
}

pub fn can_pause(&self) -> bool {
self.state.status.can_pause()
}

pub fn can_resume(&self) -> bool {
self.state.status.can_resume()
}

pub fn pid(&self) -> Option<Pid> {
self.state.pid.map(Pid::from_raw)
}
Expand Down Expand Up @@ -169,4 +180,8 @@ impl Container {
root: container_root,
})
}

pub fn spec(&self) -> Result<Spec> {
Spec::load(self.root.join("config.json"))
}
}
13 changes: 12 additions & 1 deletion src/container/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub enum ContainerStatus {
Running,
// The container process has exited
Stopped,
// The container process has paused
Paused,
}

impl ContainerStatus {
Expand All @@ -33,13 +35,21 @@ impl ContainerStatus {
use ContainerStatus::*;
match self {
Creating | Stopped => false,
Created | Running => true,
Created | Running | Paused => true,
}
}

pub fn can_delete(&self) -> bool {
matches!(self, ContainerStatus::Stopped)
}

pub fn can_pause(&self) -> bool {
matches!(self, ContainerStatus::Running)
}

pub fn can_resume(&self) -> bool {
matches!(self, ContainerStatus::Paused)
}
}

impl Display for ContainerStatus {
Expand All @@ -49,6 +59,7 @@ impl Display for ContainerStatus {
Self::Created => "Created",
Self::Running => "Running",
Self::Stopped => "Stopped",
Self::Paused => "Paused",
};

write!(f, "{}", print)
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ pub mod list;
pub mod logger;
pub mod namespaces;
pub mod notify_socket;
pub mod pause;
pub mod pipe;
pub mod process;
pub mod resume;
pub mod rootfs;
pub mod rootless;
pub mod signal;
Expand Down
8 changes: 8 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use youki::exec;
use youki::info;
use youki::kill;
use youki::list;
use youki::pause;
use youki::resume;
use youki::rootless::should_use_rootless;
use youki::start;
use youki::state;
Expand Down Expand Up @@ -59,6 +61,10 @@ enum SubCommand {
Info(info::Info),
#[clap(version = "0.0.1", author = "utam0k <[email protected]>")]
List(list::List),
#[clap(version = "0.0.1", author = "utam0k <[email protected]>")]
Pause(pause::Pause),
#[clap(version = "0.0.1", author = "utam0k <[email protected]>")]
Resume(resume::Resume),
}

/// This is the entry point in the container runtime. The binary is run by a high-level container runtime,
Expand Down Expand Up @@ -88,5 +94,7 @@ fn main() -> Result<()> {
SubCommand::State(state) => state.exec(root_path),
SubCommand::Info(info) => info.exec(),
SubCommand::List(list) => list.exec(root_path),
SubCommand::Pause(pause) => pause.exec(root_path, systemd_cgroup),
SubCommand::Resume(resume) => return resume.exec(root_path, systemd_cgroup),
}
}
49 changes: 49 additions & 0 deletions src/pause.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Contains functionality of pause container command
use std::fs::canonicalize;
use std::path::PathBuf;

use anyhow::{bail, Result};
use clap::Clap;

use crate::cgroups;
use crate::container::Container;
use crate::container::ContainerStatus;
use crate::utils;
use oci_spec::FreezerState;

#[derive(Clap, Debug)]
pub struct Pause {
pub container_id: String,
}

impl Pause {
pub fn exec(&self, root_path: PathBuf, systemd_cgroup: bool) -> Result<()> {
log::debug!("start pausing container {}", self.container_id);
let root_path = canonicalize(root_path)?;
let container_root = root_path.join(&self.container_id);
if !container_root.exists() {
bail!("{} doesn't exist.", self.container_id)
}

let container = Container::load(container_root)?.refresh_status()?;
if !container.can_pause() {
bail!(
"{} could not be paused because it was {:?}",
self.container_id,
container.status()
);
}

let spec = container.spec()?;
let cgroups_path =
utils::get_cgroup_path(&spec.linux.unwrap().cgroups_path, &self.container_id);
let cmanager = cgroups::common::create_cgroup_manager(cgroups_path, systemd_cgroup)?;
cmanager.freeze(FreezerState::Frozen)?;

log::debug!("saving paused status");
container.update_status(ContainerStatus::Paused).save()?;

log::debug!("container {} paused", self.container_id);
Ok(())
}
}
49 changes: 49 additions & 0 deletions src/resume.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Contains functionality of resume container command
use std::fs::canonicalize;
use std::path::PathBuf;

use anyhow::{bail, Result};
use clap::Clap;

use crate::cgroups;
use crate::container::Container;
use crate::container::ContainerStatus;
use crate::utils;
use oci_spec::FreezerState;

#[derive(Clap, Debug)]
pub struct Resume {
pub container_id: String,
}

impl Resume {
pub fn exec(&self, root_path: PathBuf, systemd_cgroup: bool) -> Result<()> {
log::debug!("start resuming container {}", self.container_id);
let root_path = canonicalize(root_path)?;
let container_root = root_path.join(&self.container_id);
if !container_root.exists() {
bail!("{} doesn't exist.", self.container_id)
}

let container = Container::load(container_root)?.refresh_status()?;
if !container.can_resume() {
bail!(
"{} could not be resumed because it was {:?}",
self.container_id,
container.status()
);
}

let spec = container.spec()?;
let cgroups_path =
utils::get_cgroup_path(&spec.linux.unwrap().cgroups_path, &self.container_id);
let cmanager = cgroups::common::create_cgroup_manager(cgroups_path, systemd_cgroup)?;
cmanager.freeze(FreezerState::Thawed)?;

log::debug!("saving running status");
container.update_status(ContainerStatus::Running).save()?;

log::debug!("container {} resumed", self.container_id);
Ok(())
}
}