diff --git a/.gitignore b/.gitignore index 9039ea945..5bc7a06de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ +youki +/tutorial + /target .vagrant/ tags tags.lock tags.temp + diff --git a/.gitmodules b/.gitmodules index ccbf3c853..73b6451a1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,5 @@ [submodule "integration_test/src/github.com/opencontainers/runtime-tools"] path = integration_test/src/github.com/opencontainers/runtime-tools url = https://github.com/opencontainers/runtime-tools.git + ignore = dirty + diff --git a/README.md b/README.md index 1738a1e17..fcda365fd 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,30 @@ For other platforms, please use the devcontainer that we prepared. ```sh $ git clone git@github.com:utam0k/youki.git $ cd youki -$ cargo build +$ ./build.sh +$ ./youki -h // you can get information about youki command +``` + +## Tutorial +Let's try to run a container that executes `sleep 5` using youki. +Maybe this tutorial is need permission as root. + +```sh +$ git clone git@github.com:utam0k/youki.git +$ cd youki +$ ./build.sh +$ mkdir tutorial +$ cd tutorial +$ mkdir rootfs +$ docker export $(docker create busybox) | tar -C rootfs -xvf - +// Prepare a configuration file for the container that will run `sleep 5`. +$ curl https://gist.githubusercontent.com/utam0k/8ab419996633066eaf53ac9c66d962e7/raw/e81548f591f26ec03d85ce38b0443144573b4cf6/config.json -o config.json +$ cd ../ +$ ./youki create -b tutorial tutorial_container +$ ./youki state tutorial_container // You can see the state the container is in as it is being generate. +$ ./youki start tutorial_container +$ ./youki state tutorial_container // Run it within 5 seconds to see the running container. +$ ./youki delete tutorial_container // Run it after the container is finished running. ``` ## Usage diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..d8de37c30 --- /dev/null +++ b/build.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +TARGET=${TARGET-x86_64-unknown-linux-gnu} +if [ "$TARGET" != "" ]; then + TGT="--target $TARGET" +fi +VERSION=debug +if [[ "$1" == "--release" ]]; then + VERSION=release +fi +cargo when --channel=stable build --verbose $TGT $1 && \ +cargo when --channel=beta build --verbose $TGT $1 && \ +cargo when --channel=nightly build --verbose --features nightly $TGT $1 && \ +rm -f youki +cp target/$TARGET/$VERSION/youki . diff --git a/integration_test.sh b/integration_test.sh index 9e6395868..8d23965e4 100755 --- a/integration_test.sh +++ b/integration_test.sh @@ -9,4 +9,5 @@ for case in "${test_cases[@]}"; do if [ 0 -ne $(sudo RUST_BACKTRACE=1 RUNTIME=$root/target/x86_64-unknown-linux-gnu/debug/youki $root/integration_test/src/github.com/opencontainers/runtime-tools/validation/$case | grep "not ok" | wc -l) ]; then exit 1 fi + sleep 1 done diff --git a/oci_spec/src/lib.rs b/oci_spec/src/lib.rs index 7dbb31aed..a9cf45995 100644 --- a/oci_spec/src/lib.rs +++ b/oci_spec/src/lib.rs @@ -603,6 +603,7 @@ impl Spec { pub fn load(path: &str) -> Result { let file = File::open(path)?; let mut spec: Spec = serde_json::from_reader(&file)?; + // FIME: It is fail if the caller isn't in the correct directory. spec.root.path = std::fs::canonicalize(spec.root.path)?; Ok(spec) } diff --git a/src/create.rs b/src/create.rs index 38cef5e9c..323bcf567 100644 --- a/src/create.rs +++ b/src/create.rs @@ -32,6 +32,8 @@ pub struct Create { impl Create { pub fn exec(&self, root_path: PathBuf, command: impl Command) -> Result<()> { + let bundle_canonicalized = fs::canonicalize(&self.bundle) + .unwrap_or_else(|_| panic!("failed to canonicalied {:?}", &self.bundle)); let container_dir = root_path.join(&self.container_id); if !container_dir.exists() { fs::create_dir(&container_dir).unwrap(); @@ -53,7 +55,7 @@ impl Create { &self.container_id, ContainerStatus::Creating, None, - self.bundle.to_str().unwrap(), + bundle_canonicalized.to_str().unwrap(), &container_dir, )?; container.save()?; diff --git a/src/main.rs b/src/main.rs index 663edd48e..9a00c4ed6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ //! This crate provides a container runtime which can be used by a high-level container runtime to run containers. use std::fs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use anyhow::{bail, Result}; use clap::Clap; @@ -109,6 +109,7 @@ fn main() -> Result<()> { } } SubCommand::Delete(delete) => { + log::debug!("start deleting {}", delete.container_id); // state of container is stored in a directory named as container id inside // root directory given in commandline options let container_root = root_path.join(&delete.container_id); @@ -117,15 +118,23 @@ fn main() -> Result<()> { } // load container state from json file, and check status of the container // it might be possible that delete is invoked on a running container. + log::debug!("load the container from {:?}", container_root); let container = Container::load(container_root)?.refresh_status()?; if container.can_delete() { if container.root.exists() { + nix::unistd::chdir(&PathBuf::from(&container.state.bundle))?; + let config_absolute_path = &PathBuf::from(&container.state.bundle) + .join(Path::new("config.json")) + .to_string_lossy() + .to_string(); + log::debug!("load spec from {:?}", config_absolute_path); + let spec = oci_spec::Spec::load(config_absolute_path)?; + log::debug!("spec: {:?}", spec); + // remove the directory storing container state log::debug!("remove dir {:?}", container.root); fs::remove_dir_all(&container.root)?; - let spec = oci_spec::Spec::load("config.json")?; - let cgroups_path = utils::get_cgroup_path(&spec.linux.unwrap().cgroups_path, container.id());