mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 13:11:31 +00:00
async-ify xenstore and xenclient
This commit is contained in:
@ -69,7 +69,7 @@ async fn main() -> Result<()> {
|
||||
.map(|x| x.to_string())
|
||||
.ok_or_else(|| anyhow!("unable to convert store path to string"))?;
|
||||
|
||||
let mut context = ControllerContext::new(store_path.clone())?;
|
||||
let mut context = ControllerContext::new(store_path.clone()).await?;
|
||||
|
||||
match args.command {
|
||||
Commands::Launch {
|
||||
@ -96,7 +96,7 @@ async fn main() -> Result<()> {
|
||||
run: if run.is_empty() { None } else { Some(run) },
|
||||
debug,
|
||||
};
|
||||
let (uuid, _domid) = launch.perform(request)?;
|
||||
let (uuid, _domid) = launch.perform(request).await?;
|
||||
println!("launched container: {}", uuid);
|
||||
if attach {
|
||||
let mut console = ControllerConsole::new(&mut context);
|
||||
@ -106,7 +106,7 @@ async fn main() -> Result<()> {
|
||||
|
||||
Commands::Destroy { container } => {
|
||||
let mut destroy = ControllerDestroy::new(&mut context);
|
||||
destroy.perform(&container)?;
|
||||
destroy.perform(&container).await?;
|
||||
}
|
||||
|
||||
Commands::Console { container } => {
|
||||
@ -115,7 +115,7 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
Commands::List { .. } => {
|
||||
let containers = context.list()?;
|
||||
let containers = context.list().await?;
|
||||
let mut table = cli_tables::Table::new();
|
||||
let header = vec!["uuid", "ipv4", "ipv6", "image"];
|
||||
table.push_row(&header)?;
|
||||
|
@ -16,10 +16,11 @@ impl ControllerConsole<'_> {
|
||||
pub async fn perform(&mut self, id: &str) -> Result<()> {
|
||||
let info = self
|
||||
.context
|
||||
.resolve(id)?
|
||||
.resolve(id)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("unable to resolve container: {}", id))?;
|
||||
let domid = info.domid;
|
||||
let tty = self.context.xen.get_console_path(domid)?;
|
||||
let tty = self.context.xen.get_console_path(domid).await?;
|
||||
let console = XenConsole::new(&tty).await?;
|
||||
console.attach().await?;
|
||||
Ok(())
|
||||
|
@ -15,15 +15,19 @@ impl ControllerDestroy<'_> {
|
||||
ControllerDestroy { context }
|
||||
}
|
||||
|
||||
pub fn perform(&mut self, id: &str) -> Result<Uuid> {
|
||||
pub async fn perform(&mut self, id: &str) -> Result<Uuid> {
|
||||
let info = self
|
||||
.context
|
||||
.resolve(id)?
|
||||
.resolve(id)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("unable to resolve container: {}", id))?;
|
||||
let domid = info.domid;
|
||||
let mut store = XsdClient::open()?;
|
||||
let dom_path = store.get_domain_path(domid)?;
|
||||
let uuid = match store.read_string_optional(format!("{}/krata/uuid", dom_path).as_str())? {
|
||||
let mut store = XsdClient::open().await?;
|
||||
let dom_path = store.get_domain_path(domid).await?;
|
||||
let uuid = match store
|
||||
.read_string(format!("{}/krata/uuid", dom_path).as_str())
|
||||
.await?
|
||||
{
|
||||
None => {
|
||||
return Err(anyhow!(
|
||||
"domain {} was not found or not created by krata",
|
||||
@ -36,9 +40,11 @@ impl ControllerDestroy<'_> {
|
||||
return Err(anyhow!("unable to find krata uuid based on the domain",));
|
||||
}
|
||||
let uuid = Uuid::parse_str(&uuid)?;
|
||||
let loops = store.read_string(format!("{}/krata/loops", dom_path).as_str())?;
|
||||
let loops = store
|
||||
.read_string(format!("{}/krata/loops", dom_path).as_str())
|
||||
.await?;
|
||||
let loops = ControllerContext::parse_loop_set(&loops);
|
||||
self.context.xen.destroy(domid)?;
|
||||
self.context.xen.destroy(domid).await?;
|
||||
for info in &loops {
|
||||
self.context.autoloop.unloop(&info.device)?;
|
||||
match &info.delete {
|
||||
|
@ -35,7 +35,7 @@ impl ControllerLaunch<'_> {
|
||||
ControllerLaunch { context }
|
||||
}
|
||||
|
||||
pub fn perform(&mut self, request: ControllerLaunchRequest) -> Result<(Uuid, u32)> {
|
||||
pub async fn perform(&mut self, request: ControllerLaunchRequest<'_>) -> Result<(Uuid, u32)> {
|
||||
let uuid = Uuid::new_v4();
|
||||
let name = format!("krata-{uuid}");
|
||||
let image_info = self.compile(request.image)?;
|
||||
@ -47,7 +47,7 @@ impl ControllerLaunch<'_> {
|
||||
container_mac.set_local(true);
|
||||
container_mac.set_multicast(false);
|
||||
|
||||
let guest_ipv4 = self.allocate_ipv4()?;
|
||||
let guest_ipv4 = self.allocate_ipv4().await?;
|
||||
let guest_ipv6 = container_mac.to_link_local_ipv6();
|
||||
let gateway_ipv4 = "192.168.42.1";
|
||||
let gateway_ipv6 = "fe80::1";
|
||||
@ -178,7 +178,7 @@ impl ControllerLaunch<'_> {
|
||||
),
|
||||
],
|
||||
};
|
||||
match self.context.xen.create(&config) {
|
||||
match self.context.xen.create(&config).await {
|
||||
Ok(domid) => Ok((uuid, domid)),
|
||||
Err(error) => {
|
||||
let _ = self.context.autoloop.unloop(&image_squashfs_loop.path);
|
||||
@ -189,17 +189,17 @@ impl ControllerLaunch<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn allocate_ipv4(&mut self) -> Result<Ipv4Addr> {
|
||||
async fn allocate_ipv4(&mut self) -> Result<Ipv4Addr> {
|
||||
let network = Ipv4Network::new(Ipv4Addr::new(192, 168, 42, 0), 24)?;
|
||||
let mut used: Vec<Ipv4Addr> = vec![
|
||||
Ipv4Addr::new(192, 168, 42, 0),
|
||||
Ipv4Addr::new(192, 168, 42, 1),
|
||||
Ipv4Addr::new(192, 168, 42, 255),
|
||||
];
|
||||
for domid_candidate in self.context.xen.store.list_any("/local/domain")? {
|
||||
for domid_candidate in self.context.xen.store.list("/local/domain").await? {
|
||||
let dom_path = format!("/local/domain/{}", domid_candidate);
|
||||
let ip_path = format!("{}/krata/network/guest/ipv4", dom_path);
|
||||
let existing_ip = self.context.xen.store.read_string_optional(&ip_path)?;
|
||||
let existing_ip = self.context.xen.store.read_string(&ip_path).await?;
|
||||
if let Some(existing_ip) = existing_ip {
|
||||
let ipv4_network = Ipv4Network::from_str(&existing_ip)?;
|
||||
used.push(ipv4_network.ip());
|
||||
|
@ -37,12 +37,12 @@ pub struct ContainerInfo {
|
||||
}
|
||||
|
||||
impl ControllerContext {
|
||||
pub fn new(store_path: String) -> Result<ControllerContext> {
|
||||
pub async fn new(store_path: String) -> Result<ControllerContext> {
|
||||
let mut image_cache_path = PathBuf::from(store_path);
|
||||
image_cache_path.push("cache");
|
||||
fs::create_dir_all(&image_cache_path)?;
|
||||
|
||||
let xen = XenClient::open()?;
|
||||
let xen = XenClient::open().await?;
|
||||
image_cache_path.push("image");
|
||||
fs::create_dir_all(&image_cache_path)?;
|
||||
let image_cache = ImageCache::new(&image_cache_path)?;
|
||||
@ -53,14 +53,15 @@ impl ControllerContext {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn list(&mut self) -> Result<Vec<ContainerInfo>> {
|
||||
pub async fn list(&mut self) -> Result<Vec<ContainerInfo>> {
|
||||
let mut containers: Vec<ContainerInfo> = Vec::new();
|
||||
for domid_candidate in self.xen.store.list_any("/local/domain")? {
|
||||
for domid_candidate in self.xen.store.list("/local/domain").await? {
|
||||
let dom_path = format!("/local/domain/{}", domid_candidate);
|
||||
let uuid_string = match self
|
||||
.xen
|
||||
.store
|
||||
.read_string_optional(&format!("{}/krata/uuid", &dom_path))?
|
||||
.read_string(&format!("{}/krata/uuid", &dom_path))
|
||||
.await?
|
||||
{
|
||||
None => continue,
|
||||
Some(value) => value,
|
||||
@ -71,22 +72,25 @@ impl ControllerContext {
|
||||
let image = self
|
||||
.xen
|
||||
.store
|
||||
.read_string_optional(&format!("{}/krata/image", &dom_path))?
|
||||
.read_string(&format!("{}/krata/image", &dom_path))
|
||||
.await?
|
||||
.unwrap_or("unknown".to_string());
|
||||
let loops = self
|
||||
.xen
|
||||
.store
|
||||
.read_string_optional(&format!("{}/krata/loops", &dom_path))?
|
||||
.unwrap_or("".to_string());
|
||||
.read_string(&format!("{}/krata/loops", &dom_path))
|
||||
.await?;
|
||||
let ipv4 = self
|
||||
.xen
|
||||
.store
|
||||
.read_string_optional(&format!("{}/krata/network/guest/ipv4", &dom_path))?
|
||||
.read_string(&format!("{}/krata/network/guest/ipv4", &dom_path))
|
||||
.await?
|
||||
.unwrap_or("unknown".to_string());
|
||||
let ipv6: String = self
|
||||
.xen
|
||||
.store
|
||||
.read_string_optional(&format!("{}/krata/network/guest/ipv6", &dom_path))?
|
||||
.read_string(&format!("{}/krata/network/guest/ipv6", &dom_path))
|
||||
.await?
|
||||
.unwrap_or("unknown".to_string());
|
||||
let loops = ControllerContext::parse_loop_set(&loops);
|
||||
containers.push(ContainerInfo {
|
||||
@ -101,8 +105,8 @@ impl ControllerContext {
|
||||
Ok(containers)
|
||||
}
|
||||
|
||||
pub fn resolve(&mut self, id: &str) -> Result<Option<ContainerInfo>> {
|
||||
for container in self.list()? {
|
||||
pub async fn resolve(&mut self, id: &str) -> Result<Option<ContainerInfo>> {
|
||||
for container in self.list().await? {
|
||||
let uuid_string = container.uuid.to_string();
|
||||
let domid_string = container.domid.to_string();
|
||||
if uuid_string == id || domid_string == id || id == format!("krata-{}", uuid_string) {
|
||||
@ -112,7 +116,10 @@ impl ControllerContext {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn parse_loop_set(input: &str) -> Vec<ContainerLoopInfo> {
|
||||
fn parse_loop_set(input: &Option<String>) -> Vec<ContainerLoopInfo> {
|
||||
let Some(input) = input else {
|
||||
return Vec::new();
|
||||
};
|
||||
let sets = input
|
||||
.split(',')
|
||||
.map(|x| x.to_string())
|
||||
|
Reference in New Issue
Block a user