Skip to content

Commit

Permalink
feat: add default executor to spin shim
Browse files Browse the repository at this point in the history
Signed-off-by: jiaxiao zhou <[email protected]>
  • Loading branch information
Mossaka committed Aug 4, 2023
1 parent df29600 commit b2e015c
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 5 deletions.
102 changes: 102 additions & 0 deletions containerd-shim-spin-v1/src/linux_executor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! This file is copied over from runwasi's <https://github.com/containerd/runwasi/blob/f46aa5f1e90c8282dfb09f2f832dcde73f6d62dd/crates/containerd-shim-wasmtime/src/executors/container.rs>
//!
//! TODO: I believe the can_handle function can be abstracted to runwasi's containerd-shim-wasm crate
//! for sharing.

use containerd_shim_wasm::sandbox::oci;
use libcontainer::workload::default::DefaultExecutor;
use libcontainer::workload::{Executor, ExecutorError};

use oci_spec::runtime::Spec;
use std::io::Read;
use std::{fs::OpenOptions, path::PathBuf};

#[derive(Default)]
pub struct LinuxContainerExecutor {
default_executor: DefaultExecutor,
}

impl Executor for LinuxContainerExecutor {
fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> {
self.default_executor.exec(spec)
}

fn can_handle(&self, spec: &Spec) -> bool {
let args = oci::get_args(spec);

if args.is_empty() {
return false;
}

let executable = args[0].as_str();

// mostly follows youki's verify_binary implementation
// https://github.com/containers/youki/blob/2d6fd7650bb0f22a78fb5fa982b5628f61fe25af/crates/libcontainer/src/process/container_init_process.rs#L106
let path = if executable.contains('/') {
PathBuf::from(executable)
} else {
let path = std::env::var("PATH").unwrap_or_default();
// check each path in $PATH
let mut found = false;
let mut found_path = PathBuf::default();
for p in path.split(':') {
let path = PathBuf::from(p).join(executable);
if path.exists() {
found = true;
found_path = path;
break;
}
}
if !found {
return false;
}
found_path
};

// check execute permission
use std::os::unix::fs::PermissionsExt;
let metadata = path.metadata();
if metadata.is_err() {
log::info!("failed to get metadata of {:?}", path);
return false;
}
let metadata = metadata.unwrap();
let permissions = metadata.permissions();
if !metadata.is_file() || permissions.mode() & 0o001 == 0 {
log::info!("{} is not a file or has no execute permission", executable);
return false;
}

// check the shebang and ELF magic number
// https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
let mut buffer = [0; 4];

let file = OpenOptions::new().read(true).open(path);
if file.is_err() {
log::info!("failed to open {}", executable);
return false;
}
let mut file = file.unwrap();
match file.read_exact(&mut buffer) {
Ok(_) => {}
Err(err) => {
log::info!("failed to read shebang of {}: {}", executable, err);
return false;
}
}
match buffer {
// ELF magic number
[0x7f, 0x45, 0x4c, 0x46] => true,
// shebang
[0x23, 0x21, ..] => true,
_ => {
log::info!("{} is not a valid script or elf file", executable);
false
}
}
}

fn name(&self) -> &'static str {
self.default_executor.name()
}
}
16 changes: 11 additions & 5 deletions containerd-shim-spin-v1/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ use libcontainer::container::Container;
use libcontainer::container::ContainerStatus;
use libcontainer::signal::Signal;
use libcontainer::syscall::syscall::create_syscall;
use linux_executor::LinuxContainerExecutor;
use log::error;
use nix::errno::Errno;
use nix::sys::wait::{waitid, Id as WaitID, WaitPidFlag, WaitStatus};
use serde::Deserialize;
use serde::Serialize;

mod executor;
mod linux_executor;

const SPIN_ADDR: &str = "0.0.0.0:80";
static DEFAULT_CONTAINER_ROOT_DIR: &str = "/run/containerd/spin";
Expand Down Expand Up @@ -92,15 +94,19 @@ impl Wasi {
let stdout = maybe_open_stdio(stdout).context("could not open stdout")?;
let stderr = maybe_open_stdio(stderr).context("could not open stderr")?;

let spin_executor = Box::new(SpinExecutor {
stdin,
stdout,
stderr,
});
let default_executor = Box::<LinuxContainerExecutor>::default();

let container = ContainerBuilder::new(self.id.clone(), syscall.as_ref())
.with_executor(vec![Box::new(SpinExecutor {
stdin,
stdout,
stderr,
})])?
.with_executor(vec![default_executor, spin_executor])?
.with_root_path(self.rootdir.clone())?
.as_init(&self.bundle)
.with_systemd(false)
.with_detach(true)
.build()?;
Ok(container)
}
Expand Down

0 comments on commit b2e015c

Please sign in to comment.