mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-28 16:27:50 +00:00
Merge pull request #82 from ericho/namespace-uts
agent: Add unit tests for `namespace.rs`
This commit is contained in:
commit
60d713e84d
@ -6,37 +6,22 @@
|
||||
use nix::mount::MsFlags;
|
||||
use nix::sched::{unshare, CloneFlags};
|
||||
use nix::unistd::{getpid, gettid};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::thread;
|
||||
|
||||
use crate::mount::{BareMount, FLAGS};
|
||||
use slog::Logger;
|
||||
|
||||
//use container::Process;
|
||||
|
||||
const PERSISTENT_NS_DIR: &'static str = "/var/run/sandbox-ns";
|
||||
pub const NSTYPEIPC: &'static str = "ipc";
|
||||
pub const NSTYPEUTS: &'static str = "uts";
|
||||
pub const NSTYPEPID: &'static str = "pid";
|
||||
|
||||
lazy_static! {
|
||||
static ref CLONE_FLAG_TABLE: HashMap<&'static str, CloneFlags> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert(NSTYPEIPC, CloneFlags::CLONE_NEWIPC);
|
||||
m.insert(NSTYPEUTS, CloneFlags::CLONE_NEWUTS);
|
||||
m
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Namespace {
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
pub fn get_current_thread_ns_path(ns_type: &str) -> String {
|
||||
format!(
|
||||
"/proc/{}/task/{}/ns/{}",
|
||||
@ -46,34 +31,75 @@ pub fn get_current_thread_ns_path(ns_type: &str) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Namespace {
|
||||
logger: Logger,
|
||||
pub path: String,
|
||||
persistent_ns_dir: String,
|
||||
ns_type: NamespaceType,
|
||||
}
|
||||
|
||||
impl Namespace {
|
||||
pub fn new(logger: &Logger) -> Self {
|
||||
Namespace {
|
||||
logger: logger.clone(),
|
||||
path: String::from(""),
|
||||
persistent_ns_dir: String::from(PERSISTENT_NS_DIR),
|
||||
ns_type: NamespaceType::IPC,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ipc(mut self) -> Self {
|
||||
self.ns_type = NamespaceType::IPC;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn as_uts(mut self) -> Self {
|
||||
self.ns_type = NamespaceType::UTS;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_root_dir(mut self, dir: &str) -> Self {
|
||||
self.persistent_ns_dir = dir.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
// setup_persistent_ns creates persistent namespace without switchin to it.
|
||||
// Note, pid namespaces cannot be persisted.
|
||||
pub fn setup_persistent_ns(logger: Logger, ns_type: &'static str) -> Result<Namespace, String> {
|
||||
if let Err(err) = fs::create_dir_all(PERSISTENT_NS_DIR) {
|
||||
pub fn setup(mut self) -> Result<Self, String> {
|
||||
if let Err(err) = fs::create_dir_all(&self.persistent_ns_dir) {
|
||||
return Err(err.to_string());
|
||||
}
|
||||
|
||||
let ns_path = Path::new(PERSISTENT_NS_DIR);
|
||||
let new_ns_path = ns_path.join(ns_type);
|
||||
let ns_path = PathBuf::from(&self.persistent_ns_dir);
|
||||
let ns_type = self.ns_type.clone();
|
||||
let logger = self.logger.clone();
|
||||
|
||||
let new_ns_path = ns_path.join(&ns_type.get());
|
||||
|
||||
if let Err(err) = File::create(new_ns_path.as_path()) {
|
||||
return Err(err.to_string());
|
||||
}
|
||||
|
||||
self.path = new_ns_path.into_os_string().into_string().unwrap();
|
||||
|
||||
let new_thread = thread::spawn(move || {
|
||||
let origin_ns_path = get_current_thread_ns_path(ns_type);
|
||||
let ns_path = ns_path.clone();
|
||||
let ns_type = ns_type.clone();
|
||||
let logger = logger;
|
||||
let new_ns_path = ns_path.join(&ns_type.get());
|
||||
|
||||
let origin_ns_path = get_current_thread_ns_path(&ns_type.get());
|
||||
|
||||
let _origin_ns_fd = match File::open(Path::new(&origin_ns_path)) {
|
||||
Err(err) => return Err(err.to_string()),
|
||||
Ok(file) => file.as_raw_fd(),
|
||||
};
|
||||
|
||||
// Create a new netns on the current thread.
|
||||
let cf = match CLONE_FLAG_TABLE.get(ns_type) {
|
||||
None => return Err(format!("Failed to get ns type {}", ns_type).to_string()),
|
||||
Some(cf) => cf,
|
||||
};
|
||||
let cf = ns_type.get_flags().clone();
|
||||
|
||||
if let Err(err) = unshare(*cf) {
|
||||
if let Err(err) = unshare(cf) {
|
||||
return Err(err.to_string());
|
||||
}
|
||||
|
||||
@ -112,8 +138,96 @@ pub fn setup_persistent_ns(logger: Logger, ns_type: &'static str) -> Result<Name
|
||||
Err(err) => return Err(format!("Failed to join thread {:?}!", err)),
|
||||
}
|
||||
|
||||
let new_ns_path = ns_path.join(ns_type);
|
||||
Ok(Namespace {
|
||||
path: new_ns_path.into_os_string().into_string().unwrap(),
|
||||
})
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the Namespace type.
|
||||
#[derive(Clone, Copy)]
|
||||
enum NamespaceType {
|
||||
IPC,
|
||||
UTS,
|
||||
PID,
|
||||
}
|
||||
|
||||
impl NamespaceType {
|
||||
/// Get the string representation of the namespace type.
|
||||
pub fn get(&self) -> String {
|
||||
match *self {
|
||||
Self::IPC => String::from("ipc"),
|
||||
Self::UTS => String::from("uts"),
|
||||
Self::PID => String::from("pid"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the associate flags with the namespace type.
|
||||
pub fn get_flags(&self) -> CloneFlags {
|
||||
match *self {
|
||||
Self::IPC => CloneFlags::CLONE_NEWIPC,
|
||||
Self::UTS => CloneFlags::CLONE_NEWUTS,
|
||||
Self::PID => CloneFlags::CLONE_NEWPID,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for NamespaceType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NamespaceType {
|
||||
fn default() -> Self {
|
||||
NamespaceType::IPC
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Namespace, NamespaceType};
|
||||
use crate::{mount::remove_mounts, skip_if_not_root};
|
||||
use nix::sched::CloneFlags;
|
||||
use tempfile::Builder;
|
||||
|
||||
#[test]
|
||||
fn test_setup_persistent_ns() {
|
||||
skip_if_not_root!();
|
||||
// Create dummy logger and temp folder.
|
||||
let logger = slog::Logger::root(slog::Discard, o!());
|
||||
let tmpdir = Builder::new().prefix("ipc").tempdir().unwrap();
|
||||
|
||||
let ns_ipc = Namespace::new(&logger)
|
||||
.as_ipc()
|
||||
.set_root_dir(tmpdir.path().to_str().unwrap())
|
||||
.setup();
|
||||
|
||||
assert!(ns_ipc.is_ok());
|
||||
assert!(remove_mounts(&vec![ns_ipc.unwrap().path]).is_ok());
|
||||
|
||||
let logger = slog::Logger::root(slog::Discard, o!());
|
||||
let tmpdir = Builder::new().prefix("ipc").tempdir().unwrap();
|
||||
|
||||
let ns_uts = Namespace::new(&logger)
|
||||
.as_uts()
|
||||
.set_root_dir(tmpdir.path().to_str().unwrap())
|
||||
.setup();
|
||||
|
||||
assert!(ns_uts.is_ok());
|
||||
assert!(remove_mounts(&vec![ns_uts.unwrap().path]).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_namespace_type() {
|
||||
let ipc = NamespaceType::IPC;
|
||||
assert_eq!("ipc", ipc.get());
|
||||
assert_eq!(CloneFlags::CLONE_NEWIPC, ipc.get_flags());
|
||||
|
||||
let uts = NamespaceType::UTS;
|
||||
assert_eq!("uts", uts.get());
|
||||
assert_eq!(CloneFlags::CLONE_NEWUTS, uts.get_flags());
|
||||
|
||||
let pid = NamespaceType::PID;
|
||||
assert_eq!("pid", pid.get());
|
||||
assert_eq!(CloneFlags::CLONE_NEWPID, pid.get_flags());
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
//use crate::container::Container;
|
||||
use crate::mount::{get_mount_fs_type, remove_mounts, TYPEROOTFS};
|
||||
use crate::namespace::{setup_persistent_ns, Namespace, NSTYPEIPC, NSTYPEUTS};
|
||||
use crate::namespace::Namespace;
|
||||
use crate::netlink::{RtnlHandle, NETLINK_ROUTE};
|
||||
use crate::network::Network;
|
||||
use libc::pid_t;
|
||||
@ -48,7 +48,7 @@ impl Sandbox {
|
||||
let logger = logger.new(o!("subsystem" => "sandbox"));
|
||||
|
||||
Ok(Sandbox {
|
||||
logger: logger,
|
||||
logger: logger.clone(),
|
||||
id: "".to_string(),
|
||||
hostname: "".to_string(),
|
||||
network: Network::new(),
|
||||
@ -56,12 +56,8 @@ impl Sandbox {
|
||||
mounts: Vec::new(),
|
||||
container_mounts: HashMap::new(),
|
||||
pci_device_map: HashMap::new(),
|
||||
shared_utsns: Namespace {
|
||||
path: "".to_string(),
|
||||
},
|
||||
shared_ipcns: Namespace {
|
||||
path: "".to_string(),
|
||||
},
|
||||
shared_utsns: Namespace::new(&logger),
|
||||
shared_ipcns: Namespace::new(&logger),
|
||||
storages: HashMap::new(),
|
||||
running: false,
|
||||
no_pivot_root: fs_type.eq(TYPEROOTFS),
|
||||
@ -129,29 +125,28 @@ impl Sandbox {
|
||||
|
||||
pub fn setup_shared_namespaces(&mut self) -> Result<bool> {
|
||||
// Set up shared IPC namespace
|
||||
self.shared_ipcns = match setup_persistent_ns(self.logger.clone(), NSTYPEIPC) {
|
||||
self.shared_ipcns = match Namespace::new(&self.logger).as_ipc().setup() {
|
||||
Ok(ns) => ns,
|
||||
Err(err) => {
|
||||
return Err(ErrorKind::ErrorCode(format!(
|
||||
"Failed to setup persisten IPC namespace with error: {}",
|
||||
&err
|
||||
"Failed to setup persistent IPC namespace with error: {}",
|
||||
err
|
||||
))
|
||||
.into())
|
||||
}
|
||||
};
|
||||
|
||||
// Set up shared UTS namespace
|
||||
self.shared_utsns = match setup_persistent_ns(self.logger.clone(), NSTYPEUTS) {
|
||||
// // Set up shared UTS namespace
|
||||
self.shared_utsns = match Namespace::new(&self.logger).as_uts().setup() {
|
||||
Ok(ns) => ns,
|
||||
Err(err) => {
|
||||
return Err(ErrorKind::ErrorCode(format!(
|
||||
"Failed to setup persisten UTS namespace with error: {} ",
|
||||
&err
|
||||
"Failed to setup persistent UTS namespace with error: {}",
|
||||
err
|
||||
))
|
||||
.into())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user