Skip to content
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
6 changes: 3 additions & 3 deletions crates/containerd-shim-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

pub mod sandbox;
pub mod services;
#[cfg_attr(unix, path = "sys/unix.rs")]
#[cfg_attr(windows, path = "sys/windows.rs")]
pub mod sys;
#[cfg_attr(unix, path = "sys/unix/mod.rs")]
#[cfg_attr(windows, path = "sys/windows/mod.rs")]
pub(crate) mod sys;

#[cfg(all(feature = "libcontainer", not(target_os = "windows")))]
pub mod libcontainer_instance;
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
use std::fs::OpenOptions;
use std::io::Read;
use std::os::fd::RawFd;
use std::path::PathBuf;

use libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
use libcontainer::workload::default::DefaultExecutor;
use libcontainer::workload::{Executor, ExecutorError};
use nix::unistd::{dup, dup2};
use oci_spec::runtime::Spec;

use crate::sandbox::oci;
use crate::sandbox::{oci, Stdio};

#[derive(Default)]
pub struct LinuxContainerExecutor {
stdin: Option<RawFd>,
stdout: Option<RawFd>,
stderr: Option<RawFd>,
stdio: Stdio,
default_executor: DefaultExecutor,
}

impl LinuxContainerExecutor {
pub fn new(stdin: Option<RawFd>, stdout: Option<RawFd>, stderr: Option<RawFd>) -> Self {
pub fn new(stdio: Stdio) -> Self {
Self {
stdin,
stdout,
stderr,
stdio,
..Default::default()
}
}
}

impl Executor for LinuxContainerExecutor {
fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> {
redirect_io(self.stdin, self.stdout, self.stderr).map_err(|err| {
self.stdio.redirect().map_err(|err| {
log::error!("failed to redirect io: {}", err);
ExecutorError::Other(format!("failed to redirect io: {}", err))
})?;
Expand Down Expand Up @@ -118,19 +111,3 @@ impl Executor for LinuxContainerExecutor {
self.default_executor.name()
}
}

fn redirect_io(stdin: Option<i32>, stdout: Option<i32>, stderr: Option<i32>) -> anyhow::Result<()> {
if let Some(stdin) = stdin {
dup(STDIN_FILENO)?;
dup2(stdin, STDIN_FILENO)?;
}
if let Some(stdout) = stdout {
dup(STDOUT_FILENO)?;
dup2(stdout, STDOUT_FILENO)?;
}
if let Some(stderr) = stderr {
dup(STDERR_FILENO)?;
dup2(stderr, STDERR_FILENO)?;
}
Ok(())
}
2 changes: 1 addition & 1 deletion crates/containerd-shim-wasm/src/sandbox/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use super::error::Error;
use super::instance::Instance;
use super::{oci, sandbox};
use crate::services::sandbox_ttrpc::{Manager, ManagerClient};
use crate::sys::setup_namespaces;
use crate::sys::networking::setup_namespaces;

/// Sandbox wraps an Instance and is used with the `Service` to manage multiple instances.
pub trait Sandbox: Task + Send + Sync {
Expand Down
2 changes: 2 additions & 0 deletions crates/containerd-shim-wasm/src/sandbox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ pub mod instance;
pub mod instance_utils;
pub mod manager;
pub mod shim;
pub mod stdio;

pub use error::{Error, Result};
pub use instance::{Instance, InstanceConfig};
pub use manager::{Sandbox as SandboxService, Service as ManagerService};
pub use shim::{Cli as ShimCli, Local};
pub use stdio::Stdio;

pub mod oci;

Expand Down
3 changes: 2 additions & 1 deletion crates/containerd-shim-wasm/src/sandbox/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ use ttrpc::context::Context;

use super::instance::{Instance, InstanceConfig, Nop, Wait};
use super::{oci, Error, SandboxService};
use crate::sys::{get_metrics, setup_namespaces};
use crate::sys::metrics::get_metrics;
use crate::sys::networking::setup_namespaces;

type InstanceDataStatus = (Mutex<Option<(u32, DateTime<Utc>)>>, Condvar);

Expand Down
66 changes: 66 additions & 0 deletions crates/containerd-shim-wasm/src/sandbox/stdio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use std::fs::{File, OpenOptions};
use std::io::ErrorKind::NotFound;
use std::io::{Error, Result};
use std::path::Path;
use std::sync::{Arc, Mutex};

use crate::sys::stdio::*;

#[derive(Default, Clone)]
pub struct Stdio {
pub stdin: Stdin,
pub stdout: Stdout,
pub stderr: Stderr,
}

impl Stdio {
pub fn redirect(&self) -> Result<()> {
self.stdin.redirect()?;
self.stdout.redirect()?;
self.stderr.redirect()?;
Ok(())
}
}

macro_rules! stdio_impl {
( $stdio_type:ident, $fd:expr ) => {
#[derive(Default, Clone)]
pub struct $stdio_type(Arc<Mutex<Option<File>>>);

impl<P: AsRef<Path>> TryFrom<Option<P>> for $stdio_type {
type Error = std::io::Error;
fn try_from(path: Option<P>) -> Result<Self> {
path.and_then(|path| match path.as_ref() {
path if path.as_os_str().is_empty() => None,
path => Some(path.to_owned()),
})
.map(
|path| match OpenOptions::new().read(true).write(true).open(path) {
Err(err) if err.kind() == NotFound => Ok(None),
Ok(f) => Ok(Some(f)),
Err(err) => Err(err),
},
)
.transpose()
.map(|opt| Self(Arc::new(Mutex::new(opt.flatten()))))
}
}

impl $stdio_type {
pub fn redirect(&self) -> Result<()> {
if let Some(f) = self.0.try_lock().ok().and_then(|mut f| f.take()) {
let f = try_into_fd(f)?;
let _ = unsafe { libc::dup($fd) };
if unsafe { libc::dup2(f.as_raw_fd(), $fd) } == -1 {
return Err(Error::last_os_error());
}
}
Ok(())
}
}
};
}

stdio_impl!(Stdin, STDIN_FILENO);
stdio_impl!(Stdout, STDOUT_FILENO);
stdio_impl!(Stderr, STDERR_FILENO);
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
use std::fs::{self, File};
use std::os::unix::io::AsRawFd;
use std::fs;
use std::path::Path;

use anyhow::Result;
use cgroups_rs::cgroup::get_cgroups_relative_paths_by_pid;
use cgroups_rs::hierarchies::{self};
use cgroups_rs::{Cgroup, Subsystem};
use containerd_shim::error::Error as ShimError;
use containerd_shim::{self as shim};
use nix::sched::{setns, unshare, CloneFlags};
use oci_spec::runtime;
use protobuf::well_known_types::any::Any;
use shim::protos::cgroups::metrics::{
CPUStat, CPUUsage, MemoryEntry, MemoryStat, Metrics, PidsStat, Throttle,
Expand Down Expand Up @@ -118,39 +114,3 @@ pub fn get_metrics(pid: u32) -> Result<Any> {
let metrics = convert_to_any(Box::new(metrics)).map_err(|e| Error::Others(e.to_string()))?;
Ok(metrics)
}

pub fn setup_namespaces(spec: &runtime::Spec) -> Result<()> {
let namespaces = spec
.linux()
.as_ref()
.unwrap()
.namespaces()
.as_ref()
.unwrap();
for ns in namespaces {
if ns.typ() == runtime::LinuxNamespaceType::Network {
if let Some(p) = ns.path() {
let f = File::open(p).map_err(|err| {
ShimError::Other(format!(
"could not open network namespace {}: {}",
p.display(),
err
))
})?;
setns(f.as_raw_fd(), CloneFlags::CLONE_NEWNET).map_err(|err| {
ShimError::Other(format!("could not set network namespace: {0}", err))
})?;
} else {
unshare(CloneFlags::CLONE_NEWNET).map_err(|err| {
ShimError::Other(format!("could not unshare network namespace: {0}", err))
})?;
}
}
}

// Keep all mounts changes (such as for the rootfs) private to the shim
// This way mounts will automatically be cleaned up when the shim exits.
unshare(CloneFlags::CLONE_NEWNS)
.map_err(|err| shim::Error::Other(format!("failed to unshare mount namespace: {}", err)))?;
Ok(())
}
3 changes: 3 additions & 0 deletions crates/containerd-shim-wasm/src/sys/unix/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod metrics;
pub mod networking;
pub mod stdio;
44 changes: 44 additions & 0 deletions crates/containerd-shim-wasm/src/sys/unix/networking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::fs::File;
use std::os::unix::io::AsRawFd;

use anyhow::Result;
use containerd_shim::error::Error as ShimError;
use containerd_shim::{self as shim};
use nix::sched::{setns, unshare, CloneFlags};
use oci_spec::runtime;

pub fn setup_namespaces(spec: &runtime::Spec) -> Result<()> {
let namespaces = spec
.linux()
.as_ref()
.unwrap()
.namespaces()
.as_ref()
.unwrap();
for ns in namespaces {
if ns.typ() == runtime::LinuxNamespaceType::Network {
if let Some(p) = ns.path() {
let f = File::open(p).map_err(|err| {
ShimError::Other(format!(
"could not open network namespace {}: {}",
p.display(),
err
))
})?;
setns(f.as_raw_fd(), CloneFlags::CLONE_NEWNET).map_err(|err| {
ShimError::Other(format!("could not set network namespace: {0}", err))
})?;
} else {
unshare(CloneFlags::CLONE_NEWNET).map_err(|err| {
ShimError::Other(format!("could not unshare network namespace: {0}", err))
})?;
}
}
}

// Keep all mounts changes (such as for the rootfs) private to the shim
// This way mounts will automatically be cleaned up when the shim exits.
unshare(CloneFlags::CLONE_NEWNS)
.map_err(|err| shim::Error::Other(format!("failed to unshare mount namespace: {}", err)))?;
Ok(())
}
9 changes: 9 additions & 0 deletions crates/containerd-shim-wasm/src/sys/unix/stdio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use std::io::Result;
pub use std::os::fd::AsRawFd as StdioAsRawFd;
use std::os::fd::OwnedFd;

pub use libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};

pub fn try_into_fd(f: impl Into<OwnedFd>) -> Result<impl StdioAsRawFd> {
Ok(f.into())
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,3 @@ pub fn get_metrics(pid: u32) -> Result<Any> {
let metrics = convert_to_any(Box::new(m)).map_err(|e| Error::Others(e.to_string()))?;
Ok(metrics)
}

pub fn setup_namespaces(spec: &runtime::Spec) -> Result<()> {
// noop for now
Ok(())
}
3 changes: 3 additions & 0 deletions crates/containerd-shim-wasm/src/sys/windows/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod metrics;
pub mod networking;
pub mod stdio;
4 changes: 4 additions & 0 deletions crates/containerd-shim-wasm/src/sys/windows/networking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub fn setup_namespaces(spec: &oci_spec::runtime::Spec) -> anyhow::Result<()> {
// noop for now
Ok(())
}
39 changes: 39 additions & 0 deletions crates/containerd-shim-wasm/src/sys/windows/stdio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::io::ErrorKind::Other;
use std::io::{Error, Result};
use std::os::windows::prelude::{AsRawHandle, IntoRawHandle, OwnedHandle};

use libc::{c_int, close, intptr_t, open_osfhandle, O_APPEND};

type StdioRawFd = libc::c_int;

pub static STDIN_FILENO: StdioRawFd = 0;
pub static STDOUT_FILENO: StdioRawFd = 1;
pub static STDERR_FILENO: StdioRawFd = 2;

struct StdioOwnedFd(c_int);

pub fn try_into_fd(f: impl Into<OwnedHandle>) -> Result<impl StdioAsRawFd> {
let handle = f.into();
let fd = unsafe { open_osfhandle(handle.as_raw_handle() as intptr_t, O_APPEND) };
if fd == -1 {
return Err(Error::new(Other, "Failed to open file descriptor"));
}
let _ = handle.into_raw_handle(); // drop ownership of the handle, it's managed by fd now
Ok(StdioOwnedFd(fd))
}

pub trait StdioAsRawFd {
fn as_raw_fd(&self) -> c_int;
}

impl StdioAsRawFd for StdioOwnedFd {
fn as_raw_fd(&self) -> c_int {
self.0
}
}

impl Drop for StdioOwnedFd {
fn drop(&mut self) {
unsafe { close(self.0) };
}
}
Loading