Compare commits

...

29 Commits

Author SHA1 Message Date
Jose Carlos Venegas Munoz
b119aec556 Update main.yaml 2020-02-21 13:55:05 -06:00
Salvador Fuentes
9d7bbdc5a6 Merge pull request #143 from amshinde/1.11.0-alpha0-branch-bump
# Kata Containers 1.11.0-alpha0
2020-02-19 17:24:45 -06:00
Archana Shinde
83b1712fa9 release: Kata Containers 1.11.0-alpha0
- should ignore  invalid a key-value pair as an env
- Revert: "Makefile: Fix rust agent build using "--release"."
- Makefile: Fix rust agent build using "--release".
- vsock: support log_vport and debug_console_vport
- Agent: Separate logging into a single crate
- agent: fix the issue of crash agent without spec
- fix the issue of missing restore process's cwd
- Running rust-agent on AArch64
- ci: Remove run_rust_test functions as not being used
- add oci compatibility test case
- agent: Add unit tests for sandbox.rs
- version: Add VERSION file
- ci: Add minimal makefile to use central go test script
- netlink: pull out netlink as library crate.
- Fixup workflow 103

40b5a56 agent: ignore invalid a key-value pair as an env
269daa9 Revert: "Makefile: Fix rust agent build using "--release"."
a3e46a3 Makefile: Fix rust agent build using "--release".
3c1252e vsock: support log_vport and debug_console_vport
c373f84 agent: separate logging into a single crate
2be8661 agent: fix the issue of missing restore process's cwd
6c7453d agent: fix the issue of crash agent without spec
4edf537 ci: Remove run_rust_test functions as not being used
d222533 agent: add oci compatibility test case
7dfc4e0 linker: `no such file` linking error on AArch64
44b2caa AArch64: missing symbols on target `aarch64-unknown-linux-musl`
9621a7f ABI: only support arm 64-bit platform
8d60612 version: Add VERSION file
a5192a1 netlink: pull out netlink as library crate.
3881c06 ci: Add minimal makefile to use central go test script
1c57665 workflows: make sure we build the experimental kernel, CLH
cbd5fa0 workflows: fix step output usage
92301a6 agent: Add unit tests for sandbox.rs

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
2020-02-18 19:36:52 +00:00
Yang Bo
e2c9426ebf Merge pull request #134 from liubin/master
should ignore  invalid a key-value pair as an env
2020-02-10 11:14:36 +08:00
Fupan Li
31a97031f8 Merge pull request #136 from yyyeerbo/wip
Revert: "Makefile: Fix rust agent build using "--release"."
2020-02-10 09:17:11 +08:00
Kant
40b5a56688 agent: ignore invalid a key-value pair as an env
Fixes #135

Signed-off-by: Kant <lb203159@antfin.com>
2020-02-08 13:51:28 +08:00
Yang Bo
269daa94ef Revert: "Makefile: Fix rust agent build using "--release"."
This reverts commit a3e46a369f.

There is still problem with static link, built binary will
segmentfault on clearlinux. So revert this patch for now.

Depends-on: github.com/kata-containers/tests#2293

Fixes: #69

Signed-off-by: Yang Bo <bo@hyper.sh>
2020-02-08 12:56:34 +08:00
Yang Bo
afc7b4d523 Merge pull request #129 from yyyeerbo/wip
Makefile: Fix rust agent build using "--release".
2020-02-07 15:31:58 +08:00
Yang Bo
a3e46a369f Makefile: Fix rust agent build using "--release".
Based on @ericho's work on the bug

Depends-on: github.com/kata-containers/tests#2277

Fixes: #69

Signed-off-by: Yang Bo <bo@hyper.sh>
2020-02-07 11:38:03 +08:00
Fupan Li
356222fbba Merge pull request #132 from yyyeerbo/wip2
vsock: support log_vport and debug_console_vport
2020-02-07 10:06:42 +08:00
Fupan Li
7d667a92ee Merge pull request #130 from Tim-Zhang/separate-logging
Agent: Separate logging into a single crate
2020-02-04 22:29:50 +08:00
Yang Bo
3c1252ea79 vsock: support log_vport and debug_console_vport
Fixes: #61, #64

Signed-off-by: Yang Bo <bo@hyper.sh>
2020-02-04 20:32:07 +08:00
Tim Zhang
c373f846f5 agent: separate logging into a single crate
Since the codes in logging.rs is weakly related to the project,
separating it from the project will reduce coupling and make it reusable.

Fixes: #131

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-02-03 20:40:26 +08:00
James O. D. Hunt
b5e741ba8b Merge pull request #125 from lifupan/fix_agent_crash
agent: fix the issue of crash agent without spec
2020-01-20 11:29:16 +00:00
James O. D. Hunt
174f9abee8 Merge pull request #127 from lifupan/fix_cwd
fix the issue of missing restore process's cwd
2020-01-20 11:28:11 +00:00
fupan.lfp
2be8661ffa agent: fix the issue of missing restore process's cwd
It should restore to it's previous cwd after it
create container in which it would change it's
cwd to container's bundle path.

Fixes: #126

Signed-off-by: fupan.lfp <fupan.lfp@antfin.com>
2020-01-20 11:00:48 +08:00
fupan.lfp
6c7453db78 agent: fix the issue of crash agent without spec
To check is the oci spec passed in, other wise,
it would crash the agent unwrap it directly.

Fixes: #124

Signed-off-by: fupan.lfp <fupan.lfp@antfin.com>
2020-01-18 18:26:01 +08:00
Yang Bo
1b1e066083 Merge pull request #108 from Pennyzct/build_bug_fix
Running rust-agent on AArch64
2020-01-15 21:43:31 +08:00
Salvador Fuentes
7ce9c40c76 Merge pull request #122 from GabyCT/topic/removetest
ci: Remove run_rust_test functions as not being used
2020-01-15 07:21:43 -06:00
Gabriela Cervantes
4edf5379ca ci: Remove run_rust_test functions as not being used
This PR removes a function that is never used as the script that is
referring is also non existing at the test repository.

Fixes #113

Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com>
2020-01-14 14:23:14 -06:00
Fupan Li
8fbc673e68 Merge pull request #119 from quanweiZhou/add-test-case
add oci compatibility test case
2020-01-09 14:54:11 +08:00
Yang Bo
c4f15f1280 Merge pull request #91 from ericho/master
agent: Add unit tests for sandbox.rs
2020-01-09 12:51:41 +08:00
quanweiZhou
d2225334d9 agent: add oci compatibility test case
add oci compatibility test case for src/agent/oci/src/lib.rs
follow by Open Container Initiative Runtime Specification

Fixes: #118

Signed-off-by: quanweiZhou <quanweiZhou@linux.alibaba.com>
2020-01-09 11:14:24 +08:00
Penny Zheng
7dfc4e0219 linker: no such file linking error on AArch64
When using default cc linker, we will have segfault.
Debugging with `rust-gdb`, the specific error is as follows:
src/string/memcpy.c: No such file or directory.
Only changing linker with `aarch64-linux-musl-gcc`, the
`rust-agent` could be totally statically linked and run successfully.

Fixes: #107

Signed-off-by: Penny Zheng <penny.zheng@arm.com>
2020-01-09 11:08:23 +08:00
Penny Zheng
44b2caa2e5 AArch64: missing symbols on target aarch64-unknown-linux-musl
The __addtf3, __subtf3 and __multf3 symbols are used by aarch64-musl,
but are not provided by rust compiler-builtins.
For now, the only temporary but functional workaround accepted by rust
communities is to get them from libgcc.

Fixes: #107

Signed-off-by: Penny Zheng <penny.zheng@arm.com>
2020-01-09 11:06:04 +08:00
Penny Zheng
9621a7f3f5 ABI: only support arm 64-bit platform
We only support running Kata Containers on AArch64.

Fixes: #107

Signed-off-by: Penny Zheng <penny.zheng@arm.com>
2020-01-09 09:59:20 +08:00
Jose Carlos Venegas Munoz
3b6a837664 Merge pull request #115 from jcvenegas/fix-114
version: Add VERSION file
2020-01-07 14:42:55 -06:00
Jose Carlos Venegas Munoz
8d60612052 version: Add VERSION file
Needed by some CI scripts, like release or to verify stable
branches state.

Fixes: #114

Signed-off-by: Jose Carlos Venegas Munoz <jose.carlos.venegas.munoz@intel.com>
2020-01-07 19:25:33 +00:00
Erich Cordoba
92301a6382 agent: Add unit tests for sandbox.rs
These are the unit tests for the sandbox struct. This is the summary
of the most important changes:

  - To test containers it was needed to create a `LinuxContainer` type
    and this requires root privileges. So, some tests now requires root
    user to be run.
  - There was a bug in the `unset_sandbox_storage` method. The return
    type was wrapped in a `Result` to avoid this problem.

Fixes: #50

Signed-off-by: Erich Cordoba <erich.cordoba.malibran@intel.com>
2019-12-06 13:11:07 -06:00
16 changed files with 1308 additions and 94 deletions

View File

@@ -342,4 +342,5 @@ jobs:
mv release-candidate/kata-static.tar.xz release-candidate/kata-static-$tag-x86_64.tar.xz
git clone https://github.com/kata-containers/runtime.git
cd runtime
ls ../release-candidate/*
GITHUB_TOKEN=${{ secrets.GIT_UPLOAD_TOKEN }} hub release edit -m "" -a ../release-candidate/kata-static-${tag}-x86_64.tar.xz "${tag}"

1
VERSION Normal file
View File

@@ -0,0 +1 @@
1.11.0-alpha0

View File

@@ -28,12 +28,6 @@ run_static_checks()
bash "$tests_repo_dir/.ci/static-checks.sh" "github.com/kata-containers/kata-containers"
}
run_rust_test()
{
clone_tests_repo
bash "$tests_repo_dir/.ci/rust-test.sh"
}
run_go_test()
{
clone_tests_repo

15
src/agent/.cargo/config Normal file
View File

@@ -0,0 +1,15 @@
## Copyright (c) 2020 ARM Limited
##
## SPDX-License-Identifier: Apache-2.0
##
[target.aarch64-unknown-linux-musl]
## Only setting linker with `aarch64-linux-musl-gcc`, the
## `rust-agent` could be totally statically linked.
linker = "aarch64-linux-musl-gcc"
## The __addtf3, __subtf3 and __multf3 symbols are used by aarch64-musl,
## but are not provided by rust compiler-builtins.
## For now, the only functional workaround accepted by rust communities
## is to get them from libgcc.
rustflags = [ "-C", "link-arg=-lgcc" ]

View File

@@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
oci = { path = "oci" }
logging = { path = "logging" }
rustjail = { path = "rustjail" }
protocols = { path = "protocols" }
netlink = { path = "netlink" }
@@ -15,19 +16,18 @@ grpcio = { git="https://github.com/alipay/grpc-rs", branch="rust_agent" }
protobuf = "2.6.1"
futures = "0.1.27"
libc = "0.2.58"
nix = "0.14.1"
nix = "0.17.0"
prctl = "1.0.0"
serde_json = "1.0.39"
signal-hook = "0.1.9"
scan_fmt = "0.2.3"
scopeguard = "1.0.0"
regex = "1"
# slog:
# - Dynamic keys required to allow HashMap keys to be slog::Serialized.
# - The 'max_*' features allow changing the log level at runtime
# (by stopping the compiler from removing log calls).
slog = { version = "2.5.2", features = ["dynamic-keys", "max_level_trace", "release_max_level_info"] }
slog-json = "2.3.0"
slog-async = "2.3.0"
slog-scope = "4.1.2"
# for testing
tempfile = "3.1.0"

View File

@@ -0,0 +1,20 @@
[package]
name = "logging"
version = "0.1.0"
authors = ["Tim Zhang <tim@hyper.sh>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde_json = "1.0.39"
# slog:
# - Dynamic keys required to allow HashMap keys to be slog::Serialized.
# - The 'max_*' features allow changing the log level at runtime
# (by stopping the compiler from removing log calls).
slog = { version = "2.5.2", features = ["dynamic-keys", "max_level_trace", "release_max_level_info"] }
slog-json = "2.3.0"
slog-async = "2.3.0"
slog-scope = "4.1.2"
# for testing
tempfile = "3.1.0"

View File

@@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: Apache-2.0
//
#[macro_use]
extern crate slog;
use slog::{BorrowedKV, Drain, Key, OwnedKV, OwnedKVList, Record, KV};
use std::collections::HashMap;
@@ -146,12 +148,6 @@ impl<D> RuntimeLevelFilter<D> {
level: Mutex::new(level),
}
}
fn set_level(&self, level: slog::Level) {
let mut log_level = self.level.lock().unwrap();
*log_level = level;
}
}
impl<D> Drain for RuntimeLevelFilter<D>

View File

@@ -8,7 +8,7 @@ edition = "2018"
[dependencies]
libc = "0.2.58"
nix = "0.14.1"
nix = "0.17.0"
protobuf = "2.6.1"
rustjail = { path = "../rustjail" }
protocols = { path = "../protocols" }

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ serde_derive = "1.0.91"
oci = { path = "../oci" }
protocols = { path ="../protocols" }
caps = "0.3.0"
nix = "0.14.1"
nix = "0.17.0"
scopeguard = "1.0.0"
prctl = "1.0.0"
lazy_static = "1.3.0"

View File

@@ -6,7 +6,7 @@
use lazy_static;
use protocols::oci::{Hook, Linux, LinuxNamespace, LinuxResources, POSIXRlimit, Spec};
use serde_json;
use std::ffi::CString;
use std::ffi::{CStr, CString};
use std::fs;
use std::mem;
use std::os::unix::io::RawFd;
@@ -672,19 +672,21 @@ fn do_exec(logger: &Logger, path: &str, args: &[String], env: &[String]) -> Resu
let logger = logger.new(o!("command" => "exec"));
let p = CString::new(path.to_string()).unwrap();
let a: Vec<CString> = args
let sa: Vec<CString> = args
.iter()
.map(|s| CString::new(s.to_string()).unwrap_or_default())
.collect();
let a: Vec<&CStr> = sa.iter().map(|s| s.as_c_str()).collect();
for (key, _) in env::vars() {
env::remove_var(key);
}
for e in env.iter() {
let v: Vec<&str> = e.split("=").collect();
let v: Vec<&str> = e.splitn(2, "=").collect();
if v.len() != 2 {
info!(logger, "incorrect env config!");
continue;
}
env::set_var(v[0], v[1]);
}
@@ -696,7 +698,7 @@ fn do_exec(logger: &Logger, path: &str, args: &[String], env: &[String]) -> Resu
*/
// execvp doesn't use env for the search path, so we set env manually
debug!(logger, "exec process right now!");
if let Err(e) = unistd::execvp(&p, &a) {
if let Err(e) = unistd::execvp(p.as_c_str(), a.as_slice()) {
info!(logger, "execve failed!!!");
info!(logger, "binary: {:?}, args: {:?}, envs: {:?}", p, a, env);
match e {

View File

@@ -10,6 +10,8 @@ const DEBUG_CONSOLE_FLAG: &str = "agent.debug_console";
const DEV_MODE_FLAG: &str = "agent.devmode";
const LOG_LEVEL_OPTION: &str = "agent.log";
const HOTPLUG_TIMOUT_OPTION: &str = "agent.hotplug_timeout";
const DEBUG_CONSOLE_VPORT_OPTION: &str = "agent.debug_console_vport";
const LOG_VPORT_OPTION: &str = "agent.log_vport";
const DEFAULT_LOG_LEVEL: slog::Level = slog::Level::Info;
const DEFAULT_HOTPLUG_TIMEOUT: time::Duration = time::Duration::from_secs(3);
@@ -24,6 +26,8 @@ pub struct agentConfig {
pub dev_mode: bool,
pub log_level: slog::Level,
pub hotplug_timeout: time::Duration,
pub debug_console_vport: i32,
pub log_vport: i32,
}
impl agentConfig {
@@ -33,6 +37,8 @@ impl agentConfig {
dev_mode: false,
log_level: DEFAULT_LOG_LEVEL,
hotplug_timeout: DEFAULT_HOTPLUG_TIMEOUT,
debug_console_vport: 0,
log_vport: 0,
}
}
@@ -60,12 +66,35 @@ impl agentConfig {
self.hotplug_timeout = hotplugTimeout;
}
}
if param.starts_with(format!("{}=", DEBUG_CONSOLE_VPORT_OPTION).as_str()) {
let port = get_vsock_port(param)?;
if port > 0 {
self.debug_console_vport = port;
}
}
if param.starts_with(format!("{}=", LOG_VPORT_OPTION).as_str()) {
let port = get_vsock_port(param)?;
if port > 0 {
self.log_vport = port;
}
}
}
Ok(())
}
}
fn get_vsock_port(p: &str) -> Result<i32> {
let fields: Vec<&str> = p.split("=").collect();
if fields.len() != 2 {
return Err(ErrorKind::ErrorCode("invalid port parameter".to_string()).into());
}
Ok(fields[1].parse::<i32>()?)
}
// Map logrus (https://godoc.org/github.com/sirupsen/logrus)
// log level to the equivalent slog log levels.
//

View File

@@ -40,6 +40,7 @@ use netlink::{RtnlHandle, NETLINK_ROUTE};
use libc::{self, c_ushort, pid_t, winsize, TIOCSWINSZ};
use serde_json;
use std::convert::TryFrom;
use std::fs;
use std::os::unix::io::RawFd;
use std::os::unix::prelude::PermissionsExt;
@@ -79,7 +80,15 @@ impl agentService {
let sandbox;
let mut s;
let oci = oci_spec.as_mut().unwrap();
let oci = match oci_spec.as_mut() {
Some(spec) => spec,
None => {
error!(sl!(), "no oci spec in the create container request!");
return Err(
ErrorKind::Nix(nix::Error::from_errno(nix::errno::Errno::EINVAL)).into(),
);
}
};
info!(sl!(), "receive createcontainer {}", &cid);
@@ -113,7 +122,9 @@ impl agentService {
// write spec to bundle path, hooks might
// read ocispec
setup_bundle(oci)?;
let olddir = setup_bundle(oci)?;
// restore the cwd for kata-agent process.
defer!(unistd::chdir(&olddir).unwrap());
let opts = CreateOpts {
cgroup_name: "".to_string(),
@@ -293,7 +304,7 @@ impl agentService {
);
let p = find_process(&mut sandbox, cid.as_str(), eid.as_str(), true)?;
let mut signal = Signal::from_c_int(req.signal as i32).unwrap();
let mut signal = Signal::try_from(req.signal as i32).unwrap();
// For container initProcess, if it hasn't installed handler for "SIGTERM" signal,
// it will ignore the "SIGTERM" signal sent to it, thus send it "SIGKILL" signal
@@ -1738,7 +1749,7 @@ fn do_copy_file(req: &CopyFileRequest) -> Result<()> {
Ok(())
}
fn setup_bundle(gspec: &Spec) -> Result<()> {
fn setup_bundle(gspec: &Spec) -> Result<PathBuf> {
if gspec.Root.is_none() {
return Err(nix::Error::Sys(Errno::EINVAL).into());
}
@@ -1757,7 +1768,8 @@ fn setup_bundle(gspec: &Spec) -> Result<()> {
);
let _ = oci.save(config.as_str());
let olddir = unistd::getcwd().chain_err(|| "cannot getcwd")?;
unistd::chdir(bundle_path)?;
Ok(())
Ok(olddir)
}

View File

@@ -16,7 +16,7 @@ pub const SYSFS_PCI_BUS_RESCAN_FILE: &str = "/sys/bus/pci/rescan";
target_arch = "x86"
))]
pub const PCI_ROOT_BUS_PATH: &str = "/devices/pci0000:00";
#[cfg(target_arch = "arm")]
#[cfg(target_arch = "aarch64")]
pub const PCI_ROOT_BUS_PATH: &str = "/devices/platform/4010000000.pcie/pci0000:00";
pub const SYSFS_CPU_ONLINE_PATH: &str = "/sys/devices/system/cpu";

View File

@@ -20,14 +20,17 @@ extern crate signal_hook;
extern crate scan_fmt;
extern crate oci;
#[macro_use]
extern crate scopeguard;
#[macro_use]
extern crate slog;
extern crate slog_async;
extern crate slog_json;
#[macro_use]
extern crate netlink;
use futures::*;
use nix::fcntl::{self, OFlag};
use nix::sys::socket::{self, AddressFamily, SockAddr, SockFlag, SockType};
use nix::sys::wait::{self, WaitStatus};
use nix::unistd;
use prctl::set_child_subreaper;
@@ -35,7 +38,7 @@ use rustjail::errors::*;
use signal_hook::{iterator::Signals, SIGCHLD};
use std::collections::HashMap;
use std::env;
use std::fs;
use std::fs::{self, File};
use std::os::unix::fs as unixfs;
use std::os::unix::io::AsRawFd;
use std::path::Path;
@@ -47,7 +50,6 @@ use unistd::Pid;
mod config;
mod device;
mod linux_abi;
mod logging;
mod mount;
mod namespace;
mod network;
@@ -105,13 +107,17 @@ fn main() -> Result<()> {
lazy_static::initialize(&SHELLS);
lazy_static::initialize(&AGENT_CONFIG);
// support vsock log
let (rfd, wfd) = unistd::pipe2(OFlag::O_CLOEXEC)?;
let writer = unsafe { File::from_raw_fd(wfd) };
let agentConfig = AGENT_CONFIG.clone();
if unistd::getpid() == Pid::from_raw(1) {
// Init a temporary logger used by init agent as init process
// since before do the base mount, it wouldn't access "/proc/cmdline"
// to get the customzied debug level.
let writer = io::stdout();
let logger = logging::create_logger(NAME, "agent", slog::Level::Debug, writer);
init_agent_as_init(&logger)?;
}
@@ -125,7 +131,32 @@ fn main() -> Result<()> {
}
let config = agentConfig.read().unwrap();
let writer = io::stdout();
let log_vport = config.log_vport as u32;
let log_handle = thread::spawn(move || -> Result<()> {
let mut reader = unsafe { File::from_raw_fd(rfd) };
if log_vport > 0 {
let listenfd = socket::socket(
AddressFamily::Vsock,
SockType::Stream,
SockFlag::SOCK_CLOEXEC,
None,
)?;
let addr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, log_vport);
socket::bind(listenfd, &addr)?;
socket::listen(listenfd, 1)?;
let datafd = socket::accept4(listenfd, SockFlag::SOCK_CLOEXEC)?;
let mut log_writer = unsafe { File::from_raw_fd(datafd) };
let _ = io::copy(&mut reader, &mut log_writer)?;
let _ = unistd::close(listenfd);
let _ = unistd::close(datafd);
}
// copy log to stdout
let mut stdout_writer = io::stdout();
let _ = io::copy(&mut reader, &mut stdout_writer)?;
Ok(())
});
let writer = unsafe { File::from_raw_fd(wfd) };
// Recreate a logger with the log level get from "/proc/cmdline".
let logger = logging::create_logger(NAME, "agent", config.log_level, writer);
@@ -143,13 +174,14 @@ fn main() -> Result<()> {
let _guard = slog_scope::set_global_logger(logger.new(o!("subsystem" => "grpc")));
let shells = SHELLS.clone();
let debug_console_vport = config.debug_console_vport as u32;
let shell_handle = if config.debug_console {
let thread_logger = logger.clone();
thread::spawn(move || {
let shells = shells.lock().unwrap();
let result = setup_debug_console(shells.to_vec());
let result = setup_debug_console(shells.to_vec(), debug_console_vport);
if result.is_err() {
// Report error, but don't fail
warn!(thread_logger, "failed to setup debug console";
@@ -196,6 +228,7 @@ fn main() -> Result<()> {
// let _ = rx.wait();
handle.join().unwrap();
let _ = log_handle.join();
if config.debug_console {
shell_handle.join().unwrap();
@@ -330,18 +363,35 @@ lazy_static! {
// pub static mut TRACE_MODE: ;
use crate::config::agentConfig;
use nix::fcntl::{self, OFlag};
use nix::sys::stat::Mode;
use std::os::unix::io::{FromRawFd, RawFd};
use std::path::PathBuf;
use std::process::{exit, Command, Stdio};
fn setup_debug_console(shells: Vec<String>) -> Result<()> {
fn setup_debug_console(shells: Vec<String>, port: u32) -> Result<()> {
for shell in shells.iter() {
let binary = PathBuf::from(shell);
if binary.exists() {
let f: RawFd = fcntl::open(CONSOLE_PATH, OFlag::O_RDWR, Mode::empty())?;
let f: RawFd = if port > 0 {
let listenfd = socket::socket(
AddressFamily::Vsock,
SockType::Stream,
SockFlag::SOCK_CLOEXEC,
None,
)?;
let addr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port);
socket::bind(listenfd, &addr)?;
socket::listen(listenfd, 1)?;
socket::accept4(listenfd, SockFlag::SOCK_CLOEXEC)?
} else {
let mut flags = OFlag::empty();
flags.insert(OFlag::O_RDWR);
flags.insert(OFlag::O_CLOEXEC);
fcntl::open(CONSOLE_PATH, flags, Mode::empty())?
};
let cmd = Command::new(shell)
.arg("-i")
.stdin(unsafe { Stdio::from_raw_fd(f) })
.stdout(unsafe { Stdio::from_raw_fd(f) })
.stderr(unsafe { Stdio::from_raw_fd(f) })
@@ -381,7 +431,7 @@ mod tests {
let mut shells = shells_ref.lock().unwrap();
shells.clear();
let result = setup_debug_console(shells.to_vec());
let result = setup_debug_console(shells.to_vec(), 0);
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Error Code: 'no shell'");
@@ -404,7 +454,7 @@ mod tests {
shells.push(shell);
let result = setup_debug_console(shells.to_vec());
let result = setup_debug_console(shells.to_vec(), 0);
assert!(result.is_err());
assert_eq!(

View File

@@ -97,16 +97,22 @@ impl Sandbox {
//
// It's assumed that caller is calling this method after
// acquiring a lock on sandbox.
pub fn unset_sandbox_storage(&mut self, path: &str) -> bool {
pub fn unset_sandbox_storage(&mut self, path: &str) -> Result<bool> {
match self.storages.get_mut(path) {
None => return false,
None => {
return Err(ErrorKind::ErrorCode(format!(
"Sandbox storage with path {} not found",
path
))
.into())
}
Some(count) => {
*count -= 1;
if *count < 1 {
self.storages.remove(path);
return true;
return Ok(true);
}
false
return Ok(false);
}
}
}
@@ -130,8 +136,15 @@ impl Sandbox {
// It's assumed that caller is calling this method after
// acquiring a lock on sandbox.
pub fn unset_and_remove_sandbox_storage(&mut self, path: &str) -> Result<()> {
if self.unset_sandbox_storage(path) {
return self.remove_sandbox_storage(path);
match self.unset_sandbox_storage(path) {
Ok(res) => {
if res {
return self.remove_sandbox_storage(path);
}
}
Err(err) => {
return Err(err);
}
}
Ok(())
}
@@ -262,3 +275,279 @@ fn online_memory(logger: &Logger) -> Result<()> {
online_resources(logger, SYSFS_MEMORY_ONLINE_PATH, r"memory[0-9]+", -1)?;
Ok(())
}
#[cfg(test)]
mod tests {
//use rustjail::Error;
use super::Sandbox;
use crate::{mount::BareMount, skip_if_not_root};
use nix::mount::MsFlags;
use protocols::oci::{Linux, Root, Spec};
use rustjail::container::LinuxContainer;
use rustjail::specconv::CreateOpts;
use slog::Logger;
use tempfile::Builder;
fn bind_mount(src: &str, dst: &str, logger: &Logger) -> Result<(), rustjail::errors::Error> {
let baremount = BareMount::new(src, dst, "bind", MsFlags::MS_BIND, "", &logger);
baremount.mount()
}
#[test]
fn set_sandbox_storage() {
let logger = slog::Logger::root(slog::Discard, o!());
let mut s = Sandbox::new(&logger).unwrap();
let tmpdir = Builder::new().tempdir().unwrap();
let tmpdir_path = tmpdir.path().to_str().unwrap();
// Add a new sandbox storage
let new_storage = s.set_sandbox_storage(&tmpdir_path);
// Check the reference counter
let ref_count = s.storages[tmpdir_path];
assert_eq!(
ref_count, 1,
"Invalid refcount, got {} expected 1.",
ref_count
);
assert_eq!(new_storage, true);
// Use the existing sandbox storage
let new_storage = s.set_sandbox_storage(&tmpdir_path);
assert_eq!(new_storage, false, "Should be false as already exists.");
// Since we are using existing storage, the reference counter
// should be 2 by now.
let ref_count = s.storages[tmpdir_path];
assert_eq!(
ref_count, 2,
"Invalid refcount, got {} expected 2.",
ref_count
);
}
#[test]
fn remove_sandbox_storage() {
skip_if_not_root!();
let logger = slog::Logger::root(slog::Discard, o!());
let s = Sandbox::new(&logger).unwrap();
let tmpdir = Builder::new().tempdir().unwrap();
let tmpdir_path = tmpdir.path().to_str().unwrap();
let srcdir = Builder::new()
.prefix("src")
.tempdir_in(tmpdir_path)
.unwrap();
let srcdir_path = srcdir.path().to_str().unwrap();
let destdir = Builder::new()
.prefix("dest")
.tempdir_in(tmpdir_path)
.unwrap();
let destdir_path = destdir.path().to_str().unwrap();
let emptydir = Builder::new()
.prefix("empty")
.tempdir_in(tmpdir_path)
.unwrap();
assert!(
s.remove_sandbox_storage(&srcdir_path).is_err(),
"Expect Err as the directory i not a mountpoint"
);
assert!(s.remove_sandbox_storage("").is_err());
let invalid_dir = emptydir.path().join("invalid");
assert!(s
.remove_sandbox_storage(invalid_dir.to_str().unwrap())
.is_err());
// Now, create a double mount as this guarantees the directory cannot
// be deleted after the first umount.
for _i in 0..2 {
assert!(bind_mount(srcdir_path, destdir_path, &logger).is_ok());
}
assert!(
s.remove_sandbox_storage(destdir_path).is_err(),
"Expect fail as deletion cannot happen due to the second mount."
);
// This time it should work as the previous two calls have undone the double
// mount.
assert!(s.remove_sandbox_storage(destdir_path).is_ok());
}
#[test]
#[allow(unused_assignments)]
fn unset_and_remove_sandbox_storage() {
skip_if_not_root!();
let logger = slog::Logger::root(slog::Discard, o!());
let mut s = Sandbox::new(&logger).unwrap();
// FIX: This test fails, not sure why yet.
assert!(
s.unset_and_remove_sandbox_storage("/tmp/testEphePath")
.is_err(),
"Should fail because sandbox storage doesn't exist"
);
let tmpdir = Builder::new().tempdir().unwrap();
let tmpdir_path = tmpdir.path().to_str().unwrap();
let srcdir = Builder::new()
.prefix("src")
.tempdir_in(tmpdir_path)
.unwrap();
let srcdir_path = srcdir.path().to_str().unwrap();
let destdir = Builder::new()
.prefix("dest")
.tempdir_in(tmpdir_path)
.unwrap();
let destdir_path = destdir.path().to_str().unwrap();
assert!(bind_mount(srcdir_path, destdir_path, &logger).is_ok());
assert_eq!(s.set_sandbox_storage(&destdir_path), true);
assert!(s.unset_and_remove_sandbox_storage(&destdir_path).is_ok());
let mut other_dir_str = String::new();
{
// Create another folder in a separate scope to ensure that is
// deleted
let other_dir = Builder::new()
.prefix("dir")
.tempdir_in(tmpdir_path)
.unwrap();
let other_dir_path = other_dir.path().to_str().unwrap();
other_dir_str = other_dir_path.to_string();
assert_eq!(s.set_sandbox_storage(&other_dir_path), true);
}
assert!(s.unset_and_remove_sandbox_storage(&other_dir_str).is_err());
}
#[test]
fn unset_sandbox_storage() {
let logger = slog::Logger::root(slog::Discard, o!());
let mut s = Sandbox::new(&logger).unwrap();
let storage_path = "/tmp/testEphe";
// Add a new sandbox storage
assert_eq!(s.set_sandbox_storage(&storage_path), true);
// Use the existing sandbox storage
assert_eq!(
s.set_sandbox_storage(&storage_path),
false,
"Expects false as the storage is not new."
);
assert_eq!(
s.unset_sandbox_storage(&storage_path).unwrap(),
false,
"Expects false as there is still a storage."
);
// Reference counter should decrement to 1.
let ref_count = s.storages[storage_path];
assert_eq!(
ref_count, 1,
"Invalid refcount, got {} expected 1.",
ref_count
);
assert_eq!(
s.unset_sandbox_storage(&storage_path).unwrap(),
true,
"Expects true as there is still a storage."
);
// Since no container is using this sandbox storage anymore
// there should not be any reference in sandbox struct
// for the given storage
assert!(
!s.storages.contains_key(storage_path),
"The storages map should not contain the key {}",
storage_path
);
// If no container is using the sandbox storage, the reference
// counter for it should not exist.
assert!(
s.unset_sandbox_storage(&storage_path).is_err(),
"Expects false as the reference counter should no exist."
);
}
fn create_dummy_opts() -> CreateOpts {
let mut root = Root::new();
root.Path = String::from("/");
let linux = Linux::new();
let mut spec = Spec::new();
spec.Root = Some(root).into();
spec.Linux = Some(linux).into();
CreateOpts {
cgroup_name: "".to_string(),
use_systemd_cgroup: false,
no_pivot_root: false,
no_new_keyring: false,
spec: Some(spec),
rootless_euid: false,
rootless_cgroup: false,
}
}
fn create_linuxcontainer() -> LinuxContainer {
LinuxContainer::new(
"some_id",
"/run/agent",
create_dummy_opts(),
&slog_scope::logger(),
)
.unwrap()
}
#[test]
fn get_container_entry_exist() {
skip_if_not_root!();
let logger = slog::Logger::root(slog::Discard, o!());
let mut s = Sandbox::new(&logger).unwrap();
let linux_container = create_linuxcontainer();
s.containers
.insert("testContainerID".to_string(), linux_container);
let cnt = s.get_container("testContainerID");
assert!(cnt.is_some());
}
#[test]
fn get_container_no_entry() {
let logger = slog::Logger::root(slog::Discard, o!());
let mut s = Sandbox::new(&logger).unwrap();
let cnt = s.get_container("testContainerID");
assert!(cnt.is_none());
}
#[test]
fn add_and_get_container() {
skip_if_not_root!();
let logger = slog::Logger::root(slog::Discard, o!());
let mut s = Sandbox::new(&logger).unwrap();
let linux_container = create_linuxcontainer();
s.add_container(linux_container);
assert!(s.get_container("some_id").is_some());
}
}