mirror of
				https://github.com/edera-dev/krata.git
				synced 2025-11-03 07:19:37 +00:00 
			
		
		
		
	krata: implement guest tab for automatic guest startup
This commit is contained in:
		@ -48,6 +48,7 @@ rand = "0.8.5"
 | 
				
			|||||||
rtnetlink = "0.14.1"
 | 
					rtnetlink = "0.14.1"
 | 
				
			||||||
serde_json = "1.0.113"
 | 
					serde_json = "1.0.113"
 | 
				
			||||||
sha256 = "1.5.0"
 | 
					sha256 = "1.5.0"
 | 
				
			||||||
 | 
					serde_yaml = "0.9"
 | 
				
			||||||
signal-hook = "0.3.17"
 | 
					signal-hook = "0.3.17"
 | 
				
			||||||
slice-copy = "0.3.0"
 | 
					slice-copy = "0.3.0"
 | 
				
			||||||
smoltcp = "0.11.0"
 | 
					smoltcp = "0.11.0"
 | 
				
			||||||
 | 
				
			|||||||
@ -23,16 +23,18 @@ message GuestNetworkInfo {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
message GuestInfo {
 | 
					message GuestInfo {
 | 
				
			||||||
    string id = 1;
 | 
					    string id = 1;
 | 
				
			||||||
    GuestImageSpec image = 2;
 | 
					    string name = 2;
 | 
				
			||||||
    GuestNetworkInfo network = 3;
 | 
					    GuestImageSpec image = 3;
 | 
				
			||||||
 | 
					    GuestNetworkInfo network = 4;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message LaunchGuestRequest {
 | 
					message LaunchGuestRequest {
 | 
				
			||||||
    GuestImageSpec image = 1;
 | 
					    string name = 1;
 | 
				
			||||||
    uint32 vcpus = 2;
 | 
					    GuestImageSpec image = 2;
 | 
				
			||||||
    uint64 mem = 3;
 | 
					    uint32 vcpus = 3;
 | 
				
			||||||
    repeated string env = 4;
 | 
					    uint64 mem = 4;
 | 
				
			||||||
    repeated string run = 5;
 | 
					    repeated string env = 5;
 | 
				
			||||||
 | 
					    repeated string run = 6;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message LaunchGuestReply {
 | 
					message LaunchGuestReply {
 | 
				
			||||||
 | 
				
			|||||||
@ -22,6 +22,8 @@ struct ControllerArgs {
 | 
				
			|||||||
enum Commands {
 | 
					enum Commands {
 | 
				
			||||||
    List {},
 | 
					    List {},
 | 
				
			||||||
    Launch {
 | 
					    Launch {
 | 
				
			||||||
 | 
					        #[arg(short, long)]
 | 
				
			||||||
 | 
					        name: Option<String>,
 | 
				
			||||||
        #[arg(short, long, default_value_t = 1)]
 | 
					        #[arg(short, long, default_value_t = 1)]
 | 
				
			||||||
        cpus: u32,
 | 
					        cpus: u32,
 | 
				
			||||||
        #[arg(short, long, default_value_t = 512)]
 | 
					        #[arg(short, long, default_value_t = 512)]
 | 
				
			||||||
@ -59,6 +61,7 @@ async fn main() -> Result<()> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    match args.command {
 | 
					    match args.command {
 | 
				
			||||||
        Commands::Launch {
 | 
					        Commands::Launch {
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
            oci,
 | 
					            oci,
 | 
				
			||||||
            cpus,
 | 
					            cpus,
 | 
				
			||||||
            mem,
 | 
					            mem,
 | 
				
			||||||
@ -67,6 +70,7 @@ async fn main() -> Result<()> {
 | 
				
			|||||||
            run,
 | 
					            run,
 | 
				
			||||||
        } => {
 | 
					        } => {
 | 
				
			||||||
            let request = LaunchGuestRequest {
 | 
					            let request = LaunchGuestRequest {
 | 
				
			||||||
 | 
					                name: name.unwrap_or_default(),
 | 
				
			||||||
                image: Some(GuestImageSpec {
 | 
					                image: Some(GuestImageSpec {
 | 
				
			||||||
                    image: Some(Image::Oci(GuestOciImageSpec { image: oci })),
 | 
					                    image: Some(Image::Oci(GuestOciImageSpec { image: oci })),
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
@ -119,7 +123,7 @@ async fn main() -> Result<()> {
 | 
				
			|||||||
                .await?
 | 
					                .await?
 | 
				
			||||||
                .into_inner();
 | 
					                .into_inner();
 | 
				
			||||||
            let mut table = cli_tables::Table::new();
 | 
					            let mut table = cli_tables::Table::new();
 | 
				
			||||||
            let header = vec!["uuid", "ipv4", "ipv6", "image"];
 | 
					            let header = vec!["name", "uuid", "ipv4", "ipv6", "image"];
 | 
				
			||||||
            table.push_row(&header)?;
 | 
					            table.push_row(&header)?;
 | 
				
			||||||
            for guest in response.guests {
 | 
					            for guest in response.guests {
 | 
				
			||||||
                let ipv4 = guest
 | 
					                let ipv4 = guest
 | 
				
			||||||
@ -143,6 +147,7 @@ async fn main() -> Result<()> {
 | 
				
			|||||||
                    })
 | 
					                    })
 | 
				
			||||||
                    .unwrap_or("unknown".to_string());
 | 
					                    .unwrap_or("unknown".to_string());
 | 
				
			||||||
                table.push_row_string(&vec![
 | 
					                table.push_row_string(&vec![
 | 
				
			||||||
 | 
					                    guest.name,
 | 
				
			||||||
                    guest.id,
 | 
					                    guest.id,
 | 
				
			||||||
                    ipv4.to_string(),
 | 
					                    ipv4.to_string(),
 | 
				
			||||||
                    ipv6.to_string(),
 | 
					                    ipv6.to_string(),
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,8 @@ futures = { workspace = true }
 | 
				
			|||||||
krata = { path = "../krata" }
 | 
					krata = { path = "../krata" }
 | 
				
			||||||
kratart = { path = "../kratart" }
 | 
					kratart = { path = "../kratart" }
 | 
				
			||||||
log = { workspace = true }
 | 
					log = { workspace = true }
 | 
				
			||||||
 | 
					serde = { workspace = true }
 | 
				
			||||||
 | 
					serde_yaml = { workspace = true }
 | 
				
			||||||
signal-hook = { workspace = true }
 | 
					signal-hook = { workspace = true }
 | 
				
			||||||
tokio = { workspace = true }
 | 
					tokio = { workspace = true }
 | 
				
			||||||
tokio-stream = { workspace = true }
 | 
					tokio-stream = { workspace = true }
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ use env_logger::Env;
 | 
				
			|||||||
use krata::dial::ControlDialAddress;
 | 
					use krata::dial::ControlDialAddress;
 | 
				
			||||||
use kratad::Daemon;
 | 
					use kratad::Daemon;
 | 
				
			||||||
use kratart::Runtime;
 | 
					use kratart::Runtime;
 | 
				
			||||||
 | 
					use log::error;
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    str::FromStr,
 | 
					    str::FromStr,
 | 
				
			||||||
    sync::{atomic::AtomicBool, Arc},
 | 
					    sync::{atomic::AtomicBool, Arc},
 | 
				
			||||||
@ -15,6 +16,8 @@ struct Args {
 | 
				
			|||||||
    listen: String,
 | 
					    listen: String,
 | 
				
			||||||
    #[arg(short, long, default_value = "/var/lib/krata")]
 | 
					    #[arg(short, long, default_value = "/var/lib/krata")]
 | 
				
			||||||
    store: String,
 | 
					    store: String,
 | 
				
			||||||
 | 
					    #[arg(long, default_value = "false")]
 | 
				
			||||||
 | 
					    no_load_guest_tab: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
 | 
					#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
 | 
				
			||||||
@ -26,6 +29,11 @@ async fn main() -> Result<()> {
 | 
				
			|||||||
    let addr = ControlDialAddress::from_str(&args.listen)?;
 | 
					    let addr = ControlDialAddress::from_str(&args.listen)?;
 | 
				
			||||||
    let runtime = Runtime::new(args.store.clone()).await?;
 | 
					    let runtime = Runtime::new(args.store.clone()).await?;
 | 
				
			||||||
    let mut daemon = Daemon::new(args.store.clone(), runtime).await?;
 | 
					    let mut daemon = Daemon::new(args.store.clone(), runtime).await?;
 | 
				
			||||||
 | 
					    if !args.no_load_guest_tab {
 | 
				
			||||||
 | 
					        if let Err(error) = daemon.load_guest_tab().await {
 | 
				
			||||||
 | 
					            error!("failed to load guest tab: {}", error);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    daemon.listen(addr).await?;
 | 
					    daemon.listen(addr).await?;
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -84,6 +84,11 @@ impl ControlService for RuntimeControlService {
 | 
				
			|||||||
        let guest: GuestInfo = convert_guest_info(
 | 
					        let guest: GuestInfo = convert_guest_info(
 | 
				
			||||||
            self.runtime
 | 
					            self.runtime
 | 
				
			||||||
                .launch(GuestLaunchRequest {
 | 
					                .launch(GuestLaunchRequest {
 | 
				
			||||||
 | 
					                    name: if request.name.is_empty() {
 | 
				
			||||||
 | 
					                        None
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        Some(&request.name)
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
                    image: &oci.image,
 | 
					                    image: &oci.image,
 | 
				
			||||||
                    vcpus: request.vcpus,
 | 
					                    vcpus: request.vcpus,
 | 
				
			||||||
                    mem: request.mem,
 | 
					                    mem: request.mem,
 | 
				
			||||||
@ -197,6 +202,7 @@ fn empty_vec_optional<T>(value: Vec<T>) -> Option<Vec<T>> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn convert_guest_info(value: kratart::GuestInfo) -> GuestInfo {
 | 
					fn convert_guest_info(value: kratart::GuestInfo) -> GuestInfo {
 | 
				
			||||||
    GuestInfo {
 | 
					    GuestInfo {
 | 
				
			||||||
 | 
					        name: value.name.unwrap_or_default(),
 | 
				
			||||||
        id: value.uuid.to_string(),
 | 
					        id: value.uuid.to_string(),
 | 
				
			||||||
        image: Some(GuestImageSpec {
 | 
					        image: Some(GuestImageSpec {
 | 
				
			||||||
            image: Some(Image::Oci(GuestOciImageSpec { image: value.image })),
 | 
					            image: Some(Image::Oci(GuestOciImageSpec { image: value.image })),
 | 
				
			||||||
 | 
				
			|||||||
@ -4,14 +4,16 @@ use anyhow::Result;
 | 
				
			|||||||
use control::RuntimeControlService;
 | 
					use control::RuntimeControlService;
 | 
				
			||||||
use event::{DaemonEventContext, DaemonEventGenerator};
 | 
					use event::{DaemonEventContext, DaemonEventGenerator};
 | 
				
			||||||
use krata::{control::control_service_server::ControlServiceServer, dial::ControlDialAddress};
 | 
					use krata::{control::control_service_server::ControlServiceServer, dial::ControlDialAddress};
 | 
				
			||||||
use kratart::Runtime;
 | 
					use kratart::{launch::GuestLaunchRequest, Runtime};
 | 
				
			||||||
use log::info;
 | 
					use log::{info, warn};
 | 
				
			||||||
use tokio::{net::UnixListener, task::JoinHandle};
 | 
					use tab::Tab;
 | 
				
			||||||
 | 
					use tokio::{fs, net::UnixListener, task::JoinHandle};
 | 
				
			||||||
use tokio_stream::wrappers::UnixListenerStream;
 | 
					use tokio_stream::wrappers::UnixListenerStream;
 | 
				
			||||||
use tonic::transport::{Identity, Server, ServerTlsConfig};
 | 
					use tonic::transport::{Identity, Server, ServerTlsConfig};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod control;
 | 
					pub mod control;
 | 
				
			||||||
pub mod event;
 | 
					pub mod event;
 | 
				
			||||||
 | 
					pub mod tab;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Daemon {
 | 
					pub struct Daemon {
 | 
				
			||||||
    store: String,
 | 
					    store: String,
 | 
				
			||||||
@ -32,6 +34,66 @@ impl Daemon {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn load_guest_tab(&mut self) -> Result<()> {
 | 
				
			||||||
 | 
					        let tab_path = PathBuf::from(format!("{}/guests.yml", self.store));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if !tab_path.exists() {
 | 
				
			||||||
 | 
					            return Ok(());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        info!("loading guest tab");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let tab_content = fs::read_to_string(tab_path).await?;
 | 
				
			||||||
 | 
					        let tab: Tab = serde_yaml::from_str(&tab_content)?;
 | 
				
			||||||
 | 
					        let running = self.runtime.list().await?;
 | 
				
			||||||
 | 
					        for (name, guest) in tab.guests {
 | 
				
			||||||
 | 
					            let existing = running
 | 
				
			||||||
 | 
					                .iter()
 | 
				
			||||||
 | 
					                .filter(|x| x.name.is_some())
 | 
				
			||||||
 | 
					                .find(|run| *run.name.as_ref().unwrap() == name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if let Some(existing) = existing {
 | 
				
			||||||
 | 
					                info!("guest {} is already running: {}", name, existing.uuid);
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let request = GuestLaunchRequest {
 | 
				
			||||||
 | 
					                name: Some(&name),
 | 
				
			||||||
 | 
					                image: &guest.image,
 | 
				
			||||||
 | 
					                vcpus: guest.cpus,
 | 
				
			||||||
 | 
					                mem: guest.mem,
 | 
				
			||||||
 | 
					                env: if guest.env.is_empty() {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Some(
 | 
				
			||||||
 | 
					                        guest
 | 
				
			||||||
 | 
					                            .env
 | 
				
			||||||
 | 
					                            .iter()
 | 
				
			||||||
 | 
					                            .map(|(key, value)| format!("{}={}", key, value))
 | 
				
			||||||
 | 
					                            .collect::<Vec<String>>(),
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                run: if guest.run.is_empty() {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Some(guest.run)
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                debug: false,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            match self.runtime.launch(request).await {
 | 
				
			||||||
 | 
					                Err(error) => {
 | 
				
			||||||
 | 
					                    warn!("failed to launch guest {}: {}", name, error);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Ok(info) => {
 | 
				
			||||||
 | 
					                    info!("launched guest {}: {}", name, info.uuid);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        info!("loaded guest tab");
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn listen(&mut self, addr: ControlDialAddress) -> Result<()> {
 | 
					    pub async fn listen(&mut self, addr: ControlDialAddress) -> Result<()> {
 | 
				
			||||||
        let control_service = RuntimeControlService::new(self.events.clone(), self.runtime.clone());
 | 
					        let control_service = RuntimeControlService::new(self.events.clone(), self.runtime.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								crates/kratad/src/tab.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								crates/kratad/src/tab.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct Tab {
 | 
				
			||||||
 | 
					    #[serde(default)]
 | 
				
			||||||
 | 
					    pub guests: HashMap<String, TabGuest>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct TabGuest {
 | 
				
			||||||
 | 
					    pub image: String,
 | 
				
			||||||
 | 
					    pub mem: u64,
 | 
				
			||||||
 | 
					    pub cpus: u32,
 | 
				
			||||||
 | 
					    #[serde(default)]
 | 
				
			||||||
 | 
					    pub env: HashMap<String, String>,
 | 
				
			||||||
 | 
					    #[serde(default)]
 | 
				
			||||||
 | 
					    pub run: Vec<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -22,6 +22,7 @@ use crate::RuntimeContext;
 | 
				
			|||||||
use super::{GuestInfo, GuestState};
 | 
					use super::{GuestInfo, GuestState};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct GuestLaunchRequest<'a> {
 | 
					pub struct GuestLaunchRequest<'a> {
 | 
				
			||||||
 | 
					    pub name: Option<&'a str>,
 | 
				
			||||||
    pub image: &'a str,
 | 
					    pub image: &'a str,
 | 
				
			||||||
    pub vcpus: u32,
 | 
					    pub vcpus: u32,
 | 
				
			||||||
    pub mem: u64,
 | 
					    pub mem: u64,
 | 
				
			||||||
@ -112,36 +113,8 @@ impl GuestLauncher {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        let container_mac_string = container_mac.to_string().replace('-', ":");
 | 
					        let container_mac_string = container_mac.to_string().replace('-', ":");
 | 
				
			||||||
        let gateway_mac_string = gateway_mac.to_string().replace('-', ":");
 | 
					        let gateway_mac_string = gateway_mac.to_string().replace('-', ":");
 | 
				
			||||||
        let config = DomainConfig {
 | 
					
 | 
				
			||||||
            backend_domid: 0,
 | 
					        let mut extra_keys = vec![
 | 
				
			||||||
            name: &name,
 | 
					 | 
				
			||||||
            max_vcpus: request.vcpus,
 | 
					 | 
				
			||||||
            mem_mb: request.mem,
 | 
					 | 
				
			||||||
            kernel_path: &context.kernel,
 | 
					 | 
				
			||||||
            initrd_path: &context.initrd,
 | 
					 | 
				
			||||||
            cmdline: &cmdline,
 | 
					 | 
				
			||||||
            disks: vec![
 | 
					 | 
				
			||||||
                DomainDisk {
 | 
					 | 
				
			||||||
                    vdev: "xvda",
 | 
					 | 
				
			||||||
                    block: &image_squashfs_loop,
 | 
					 | 
				
			||||||
                    writable: false,
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                DomainDisk {
 | 
					 | 
				
			||||||
                    vdev: "xvdb",
 | 
					 | 
				
			||||||
                    block: &cfgblk_squashfs_loop,
 | 
					 | 
				
			||||||
                    writable: false,
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
            consoles: vec![],
 | 
					 | 
				
			||||||
            vifs: vec![DomainNetworkInterface {
 | 
					 | 
				
			||||||
                mac: &container_mac_string,
 | 
					 | 
				
			||||||
                mtu: 1500,
 | 
					 | 
				
			||||||
                bridge: None,
 | 
					 | 
				
			||||||
                script: None,
 | 
					 | 
				
			||||||
            }],
 | 
					 | 
				
			||||||
            filesystems: vec![],
 | 
					 | 
				
			||||||
            event_channels: vec![],
 | 
					 | 
				
			||||||
            extra_keys: vec![
 | 
					 | 
				
			||||||
            ("krata/uuid".to_string(), uuid.to_string()),
 | 
					            ("krata/uuid".to_string(), uuid.to_string()),
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                "krata/loops".to_string(),
 | 
					                "krata/loops".to_string(),
 | 
				
			||||||
@ -179,11 +152,47 @@ impl GuestLauncher {
 | 
				
			|||||||
                "krata/network/gateway/mac".to_string(),
 | 
					                "krata/network/gateway/mac".to_string(),
 | 
				
			||||||
                gateway_mac_string.clone(),
 | 
					                gateway_mac_string.clone(),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(name) = request.name {
 | 
				
			||||||
 | 
					            extra_keys.push(("krata/name".to_string(), name.to_string()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let config = DomainConfig {
 | 
				
			||||||
 | 
					            backend_domid: 0,
 | 
				
			||||||
 | 
					            name: &name,
 | 
				
			||||||
 | 
					            max_vcpus: request.vcpus,
 | 
				
			||||||
 | 
					            mem_mb: request.mem,
 | 
				
			||||||
 | 
					            kernel_path: &context.kernel,
 | 
				
			||||||
 | 
					            initrd_path: &context.initrd,
 | 
				
			||||||
 | 
					            cmdline: &cmdline,
 | 
				
			||||||
 | 
					            disks: vec![
 | 
				
			||||||
 | 
					                DomainDisk {
 | 
				
			||||||
 | 
					                    vdev: "xvda",
 | 
				
			||||||
 | 
					                    block: &image_squashfs_loop,
 | 
				
			||||||
 | 
					                    writable: false,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                DomainDisk {
 | 
				
			||||||
 | 
					                    vdev: "xvdb",
 | 
				
			||||||
 | 
					                    block: &cfgblk_squashfs_loop,
 | 
				
			||||||
 | 
					                    writable: false,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
 | 
					            consoles: vec![],
 | 
				
			||||||
 | 
					            vifs: vec![DomainNetworkInterface {
 | 
				
			||||||
 | 
					                mac: &container_mac_string,
 | 
				
			||||||
 | 
					                mtu: 1500,
 | 
				
			||||||
 | 
					                bridge: None,
 | 
				
			||||||
 | 
					                script: None,
 | 
				
			||||||
 | 
					            }],
 | 
				
			||||||
 | 
					            filesystems: vec![],
 | 
				
			||||||
 | 
					            event_channels: vec![],
 | 
				
			||||||
 | 
					            extra_keys,
 | 
				
			||||||
            extra_rw_paths: vec!["krata/guest".to_string()],
 | 
					            extra_rw_paths: vec!["krata/guest".to_string()],
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        match context.xen.create(&config).await {
 | 
					        match context.xen.create(&config).await {
 | 
				
			||||||
            Ok(domid) => Ok(GuestInfo {
 | 
					            Ok(domid) => Ok(GuestInfo {
 | 
				
			||||||
 | 
					                name: request.name.map(|x| x.to_string()),
 | 
				
			||||||
                uuid,
 | 
					                uuid,
 | 
				
			||||||
                domid,
 | 
					                domid,
 | 
				
			||||||
                image: request.image.to_string(),
 | 
					                image: request.image.to_string(),
 | 
				
			||||||
 | 
				
			|||||||
@ -37,6 +37,7 @@ pub struct GuestState {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct GuestInfo {
 | 
					pub struct GuestInfo {
 | 
				
			||||||
 | 
					    pub name: Option<String>,
 | 
				
			||||||
    pub uuid: Uuid,
 | 
					    pub uuid: Uuid,
 | 
				
			||||||
    pub domid: u32,
 | 
					    pub domid: u32,
 | 
				
			||||||
    pub image: String,
 | 
					    pub image: String,
 | 
				
			||||||
@ -92,6 +93,9 @@ impl RuntimeContext {
 | 
				
			|||||||
    pub async fn list(&mut self) -> Result<Vec<GuestInfo>> {
 | 
					    pub async fn list(&mut self) -> Result<Vec<GuestInfo>> {
 | 
				
			||||||
        let mut guests: Vec<GuestInfo> = Vec::new();
 | 
					        let mut guests: Vec<GuestInfo> = Vec::new();
 | 
				
			||||||
        for domid_candidate in self.xen.store.list("/local/domain").await? {
 | 
					        for domid_candidate in self.xen.store.list("/local/domain").await? {
 | 
				
			||||||
 | 
					            if domid_candidate == "0" {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            let dom_path = format!("/local/domain/{}", domid_candidate);
 | 
					            let dom_path = format!("/local/domain/{}", domid_candidate);
 | 
				
			||||||
            let uuid_string = match self
 | 
					            let uuid_string = match self
 | 
				
			||||||
                .xen
 | 
					                .xen
 | 
				
			||||||
@ -105,6 +109,13 @@ impl RuntimeContext {
 | 
				
			|||||||
            let domid =
 | 
					            let domid =
 | 
				
			||||||
                u32::from_str(&domid_candidate).map_err(|_| anyhow!("failed to parse domid"))?;
 | 
					                u32::from_str(&domid_candidate).map_err(|_| anyhow!("failed to parse domid"))?;
 | 
				
			||||||
            let uuid = Uuid::from_str(&uuid_string)?;
 | 
					            let uuid = Uuid::from_str(&uuid_string)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let name = self
 | 
				
			||||||
 | 
					                .xen
 | 
				
			||||||
 | 
					                .store
 | 
				
			||||||
 | 
					                .read_string(&format!("{}/krata/name", &dom_path))
 | 
				
			||||||
 | 
					                .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let image = self
 | 
					            let image = self
 | 
				
			||||||
                .xen
 | 
					                .xen
 | 
				
			||||||
                .store
 | 
					                .store
 | 
				
			||||||
@ -154,6 +165,7 @@ impl RuntimeContext {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            let loops = RuntimeContext::parse_loop_set(&loops);
 | 
					            let loops = RuntimeContext::parse_loop_set(&loops);
 | 
				
			||||||
            guests.push(GuestInfo {
 | 
					            guests.push(GuestInfo {
 | 
				
			||||||
 | 
					                name,
 | 
				
			||||||
                uuid,
 | 
					                uuid,
 | 
				
			||||||
                domid,
 | 
					                domid,
 | 
				
			||||||
                image,
 | 
					                image,
 | 
				
			||||||
@ -170,6 +182,13 @@ impl RuntimeContext {
 | 
				
			|||||||
        for guest in self.list().await? {
 | 
					        for guest in self.list().await? {
 | 
				
			||||||
            let uuid_string = guest.uuid.to_string();
 | 
					            let uuid_string = guest.uuid.to_string();
 | 
				
			||||||
            let domid_string = guest.domid.to_string();
 | 
					            let domid_string = guest.domid.to_string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if let Some(ref name) = guest.name {
 | 
				
			||||||
 | 
					                if name == id {
 | 
				
			||||||
 | 
					                    return Ok(Some(guest));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if uuid_string == id || domid_string == id || id == format!("krata-{}", uuid_string) {
 | 
					            if uuid_string == id || domid_string == id || id == format!("krata-{}", uuid_string) {
 | 
				
			||||||
                return Ok(Some(guest));
 | 
					                return Ok(Some(guest));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user