From 88d26db63f4bcc02d1f60547697c32ac9a6e17fb Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 23 Jan 2023 07:40:23 +0000 Subject: [PATCH] Add descriptors.json when creating checkpoint runc as well as crun create a file called descriptors.json in the checkpoint directory. descriptors.json contains a list of how the FDs 0, 1, 2 are connected before checkpointing: $ cat descriptors.json # created by runc in this case ["/dev/null","pipe:[230688]","pipe:[230689]"] With this information the FDs can be reconnected correctly during restore. With this commit is it possible to do: $ youki run container $ youki checkpointt container $ runc restore container Now the checkpoint is in a format that can be handled by other container runtimes. Signed-off-by: Adrian Reber --- .../src/container/container_checkpoint.rs | 20 ++++++++++++++++++- .../src/tests/lifecycle/checkpoint.rs | 7 +++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/libcontainer/src/container/container_checkpoint.rs b/crates/libcontainer/src/container/container_checkpoint.rs index 48621a4d..c54d97b7 100644 --- a/crates/libcontainer/src/container/container_checkpoint.rs +++ b/crates/libcontainer/src/container/container_checkpoint.rs @@ -6,9 +6,12 @@ use libcgroups::common::CgroupSetup::{Hybrid, Legacy}; #[cfg(feature = "v1")] use libcgroups::common::DEFAULT_CGROUP_ROOT; use oci_spec::runtime::Spec; +use std::fs::{self, File}; +use std::io::Write; use std::os::unix::io::AsRawFd; const CRIU_CHECKPOINT_LOG_FILE: &str = "dump.log"; +const DESCRIPTORS_JSON: &str = "descriptors.json"; impl Container { pub fn checkpoint(&mut self, opts: &CheckpointOptions) -> Result<()> { @@ -88,9 +91,24 @@ impl Container { criu.set_work_dir_fd(work_dir.as_raw_fd()); } + let pid: i32 = self.pid().unwrap().into(); + + // Remember original stdin, stdout, stderr for container restore. + let mut descriptors = Vec::new(); + for n in 0..3 { + let link_path = match fs::read_link(format!("/proc/{}/fd/{}", pid, n)) { + Ok(lp) => lp.into_os_string().into_string().unwrap(), + Err(..) => "/dev/null".to_string(), + }; + descriptors.push(link_path); + } + let descriptors_json_path = opts.image_path.join(DESCRIPTORS_JSON); + let mut descriptors_json = File::create(descriptors_json_path)?; + write!(descriptors_json, "{}", serde_json::to_string(&descriptors)?)?; + criu.set_log_file(CRIU_CHECKPOINT_LOG_FILE.to_string()); criu.set_log_level(4); - criu.set_pid(self.pid().unwrap().into()); + criu.set_pid(pid); criu.set_leave_running(opts.leave_running); criu.set_ext_unix_sk(opts.ext_unix_sk); criu.set_shell_job(opts.shell_job); diff --git a/tests/rust-integration-tests/integration_test/src/tests/lifecycle/checkpoint.rs b/tests/rust-integration-tests/integration_test/src/tests/lifecycle/checkpoint.rs index 827f2e52..57ba7b70 100644 --- a/tests/rust-integration-tests/integration_test/src/tests/lifecycle/checkpoint.rs +++ b/tests/rust-integration-tests/integration_test/src/tests/lifecycle/checkpoint.rs @@ -144,6 +144,13 @@ fn checkpoint( )); } + if !Path::new(&checkpoint_dir.join("descriptors.json")).exists() { + return TestResult::Failed(anyhow::anyhow!( + "resulting checkpoint does not seem to be complete. {:?}/descriptors.json is missing", + &checkpoint_dir, + )); + } + let dump_log = match work_path { Some(wp) => Path::new(wp).join("dump.log"), _ => checkpoint_dir.join("dump.log"),