mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-02 00:02:01 +00:00
vsock: support log_vport and debug_console_vport
Fixes: #61, #64 Signed-off-by: Yang Bo <bo@hyper.sh>
This commit is contained in:
parent
b5e741ba8b
commit
3c1252ea79
@ -15,7 +15,7 @@ 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"
|
||||
|
@ -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" }
|
||||
|
@ -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"
|
||||
|
@ -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,10 +672,11 @@ 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);
|
||||
@ -696,7 +697,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 {
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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;
|
||||
@ -303,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
|
||||
|
@ -31,6 +31,8 @@ extern crate slog_json;
|
||||
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;
|
||||
@ -38,7 +40,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;
|
||||
@ -108,13 +110,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)?;
|
||||
}
|
||||
@ -128,7 +134,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);
|
||||
|
||||
@ -146,13 +177,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";
|
||||
@ -199,6 +231,7 @@ fn main() -> Result<()> {
|
||||
// let _ = rx.wait();
|
||||
|
||||
handle.join().unwrap();
|
||||
let _ = log_handle.join();
|
||||
|
||||
if config.debug_console {
|
||||
shell_handle.join().unwrap();
|
||||
@ -333,18 +366,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) })
|
||||
@ -384,7 +434,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'");
|
||||
@ -407,7 +457,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!(
|
||||
|
Loading…
Reference in New Issue
Block a user