controller: implement automatic exit when process has exited

This commit is contained in:
Alex Zenla
2024-02-23 05:26:32 +00:00
parent 496cdd37be
commit 89e4f1a23d
3 changed files with 34 additions and 46 deletions

View File

@ -5,7 +5,7 @@ use std::{
use anyhow::Result; use anyhow::Result;
use futures::future::join_all; use futures::future::join_all;
use log::warn; use log::debug;
use std::process::exit; use std::process::exit;
use termion::raw::IntoRawMode; use termion::raw::IntoRawMode;
use tokio::{ use tokio::{
@ -34,7 +34,7 @@ impl XenConsole {
let stdout = unsafe { File::from_raw_fd(terminal.as_raw_fd()) }; let stdout = unsafe { File::from_raw_fd(terminal.as_raw_fd()) };
let reader_task = tokio::task::spawn(async move { let reader_task = tokio::task::spawn(async move {
if let Err(error) = XenConsole::copy_stdout(stdout, self.xen_read_handle).await { if let Err(error) = XenConsole::copy_stdout(stdout, self.xen_read_handle).await {
warn!("failed to copy console output: {}", error); debug!("failed to copy console output: {}", error);
} }
}); });
let writer_task = tokio::task::spawn(async move { let writer_task = tokio::task::spawn(async move {
@ -44,7 +44,7 @@ impl XenConsole {
) )
.await .await
{ {
warn!("failed to intercept stdin: {}", error); debug!("failed to intercept stdin: {}", error);
} }
}); });

View File

@ -1,5 +1,11 @@
use anyhow::{anyhow, Result}; use std::{process::exit, time::Duration};
use anyhow::{anyhow, Result};
use log::warn;
use tokio::time::sleep;
use xenstore::client::XsdInterface;
use super::destroy::ControllerDestroy;
use crate::console::XenConsole; use crate::console::XenConsole;
use super::ControllerContext; use super::ControllerContext;
@ -22,7 +28,24 @@ impl ControllerConsole<'_> {
let domid = info.domid; let domid = info.domid;
let tty = self.context.xen.get_console_path(domid).await?; let tty = self.context.xen.get_console_path(domid).await?;
let console = XenConsole::new(&tty).await?; let console = XenConsole::new(&tty).await?;
console.attach().await?;
Ok(()) let dom_path = self.context.xen.store.get_domain_path(domid).await?;
tokio::task::spawn(async move {
if let Err(error) = console.attach().await {
warn!("failed to attach to console: {}", error);
}
});
let exit_code_path = format!("{}/krata/guest/exit-code", dom_path);
loop {
let Some(code) = self.context.xen.store.read_string(&exit_code_path).await? else {
sleep(Duration::from_secs(1)).await;
continue;
};
let mut destroy = ControllerDestroy::new(self.context);
destroy.perform(&domid.to_string()).await?;
exit(code.parse::<i32>()?);
}
} }
} }

View File

@ -1,14 +1,11 @@
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::sys::{XsdMessageHeader, XSD_ERROR}; use crate::sys::{XsdMessageHeader, XSD_ERROR};
use std::ffi::CString; use std::ffi::CString;
use std::fs::{self, metadata, File}; use std::fs::{metadata, File};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::mem::size_of; use std::mem::size_of;
use std::os::unix::fs::FileTypeExt;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::UnixStream;
const XEN_BUS_PATHS: &[&str] = &["/dev/xen/xenbus", "/var/run/xenstored/socket"]; const XEN_BUS_PATHS: &[&str] = &["/dev/xen/xenbus"];
fn find_bus_path() -> Option<String> { fn find_bus_path() -> Option<String> {
for path in XEN_BUS_PATHS { for path in XEN_BUS_PATHS {
@ -20,37 +17,16 @@ fn find_bus_path() -> Option<String> {
None None
} }
#[async_trait::async_trait]
trait XsdTransport {
async fn xsd_write_all(&mut self, buf: &[u8]) -> Result<()>;
async fn xsd_read_exact(&mut self, buf: &mut [u8]) -> Result<()>;
}
#[async_trait::async_trait]
impl XsdTransport for UnixStream {
async fn xsd_write_all(&mut self, buf: &[u8]) -> Result<()> {
Ok(self.write_all(buf).await?)
}
async fn xsd_read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
self.read_exact(buf).await?;
Ok(())
}
}
pub struct XsdFileTransport { pub struct XsdFileTransport {
handle: File, handle: File,
} }
impl XsdFileTransport { impl XsdFileTransport {
pub fn new(path: &str) -> Result<XsdFileTransport> { fn new(path: &str) -> Result<XsdFileTransport> {
let handle = File::options().read(true).write(true).open(path)?; let handle = File::options().read(true).write(true).open(path)?;
Ok(XsdFileTransport { handle }) Ok(XsdFileTransport { handle })
} }
}
#[async_trait::async_trait]
impl XsdTransport for XsdFileTransport {
async fn xsd_read_exact(&mut self, buf: &mut [u8]) -> Result<()> { async fn xsd_read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
Ok(self.handle.read_exact(buf)?) Ok(self.handle.read_exact(buf)?)
} }
@ -63,7 +39,7 @@ impl XsdTransport for XsdFileTransport {
} }
pub struct XsdSocket { pub struct XsdSocket {
handle: Box<dyn XsdTransport>, handle: XsdFileTransport,
} }
#[derive(Debug)] #[derive(Debug)]
@ -103,19 +79,8 @@ impl XsdSocket {
Some(path) => path, Some(path) => path,
None => return Err(Error::BusNotFound), None => return Err(Error::BusNotFound),
}; };
let metadata = fs::metadata(&path)?;
let file_type = metadata.file_type();
if file_type.is_socket() {
let stream = UnixStream::connect(&path).await?;
return Ok(XsdSocket {
handle: Box::new(stream),
});
}
let transport = XsdFileTransport::new(&path)?; let transport = XsdFileTransport::new(&path)?;
Ok(XsdSocket { Ok(XsdSocket { handle: transport })
handle: Box::new(transport),
})
} }
pub async fn send(&mut self, tx: u32, typ: u32, buf: &[u8]) -> Result<XsdResponse> { pub async fn send(&mut self, tx: u32, typ: u32, buf: &[u8]) -> Result<XsdResponse> {