diff --git a/crates/krata/proto/krata/control.proto b/crates/krata/proto/krata/control.proto index aeefab3..d0da3ec 100644 --- a/crates/krata/proto/krata/control.proto +++ b/crates/krata/proto/krata/control.proto @@ -6,15 +6,29 @@ option java_outer_classname = "ControlProto"; package krata.control; +message GuestOciImageSpec { + string image = 1; +} + +message GuestImageSpec { + oneof image { + GuestOciImageSpec oci = 1; + } +} + +message GuestNetworkInfo { + string ipv4 = 1; + string ipv6 = 2; +} + message GuestInfo { string id = 1; - string image = 2; - string ipv4 = 3; - string ipv6 = 4; + GuestImageSpec image = 2; + GuestNetworkInfo network = 3; } message LaunchGuestRequest { - string image = 1; + GuestImageSpec image = 1; uint32 vcpus = 2; uint64 mem = 3; repeated string env = 4; diff --git a/crates/kratactl/bin/control.rs b/crates/kratactl/bin/control.rs index 09d4da8..c44e31e 100644 --- a/crates/kratactl/bin/control.rs +++ b/crates/kratactl/bin/control.rs @@ -2,8 +2,8 @@ use anyhow::{anyhow, Result}; use clap::{Parser, Subcommand}; use env_logger::Env; use krata::control::{ - watch_events_reply::Event, DestroyGuestRequest, LaunchGuestRequest, ListGuestsRequest, - WatchEventsRequest, + guest_image_spec::Image, watch_events_reply::Event, DestroyGuestRequest, GuestImageSpec, + GuestOciImageSpec, LaunchGuestRequest, ListGuestsRequest, WatchEventsRequest, }; use kratactl::{client::ControlClientProvider, console::StdioConsoleStream}; use tonic::Request; @@ -31,7 +31,7 @@ enum Commands { #[arg(short, long)] attach: bool, #[arg()] - image: String, + oci: String, #[arg(allow_hyphen_values = true, trailing_var_arg = true)] run: Vec, }, @@ -55,7 +55,7 @@ async fn main() -> Result<()> { match args.command { Commands::Launch { - image, + oci, cpus, mem, attach, @@ -63,7 +63,9 @@ async fn main() -> Result<()> { run, } => { let request = LaunchGuestRequest { - image, + image: Some(GuestImageSpec { + image: Some(Image::Oci(GuestOciImageSpec { image: oci })), + }), vcpus: cpus, mem, env: env.unwrap_or_default(), @@ -111,7 +113,32 @@ async fn main() -> Result<()> { let header = vec!["uuid", "ipv4", "ipv6", "image"]; table.push_row(&header)?; for guest in response.guests { - table.push_row_string(&vec![guest.id, guest.ipv4, guest.ipv6, guest.image])?; + let ipv4 = guest + .network + .as_ref() + .map(|x| x.ipv4.as_str()) + .unwrap_or("unknown"); + let ipv6 = guest + .network + .as_ref() + .map(|x| x.ipv6.as_str()) + .unwrap_or("unknown"); + let image = guest + .image + .map(|x| { + x.image + .map(|y| match y { + Image::Oci(oci) => oci.image, + }) + .unwrap_or("unknown".to_string()) + }) + .unwrap_or("unknown".to_string()); + table.push_row_string(&vec![ + guest.id, + ipv4.to_string(), + ipv6.to_string(), + image, + ])?; } if table.num_records() == 1 { println!("no guests have been launched"); diff --git a/crates/kratad/src/control.rs b/crates/kratad/src/control.rs index 7d3f252..d7d0568 100644 --- a/crates/kratad/src/control.rs +++ b/crates/kratad/src/control.rs @@ -3,9 +3,10 @@ use std::{io, pin::Pin}; use async_stream::try_stream; use futures::Stream; use krata::control::{ - control_service_server::ControlService, ConsoleDataReply, ConsoleDataRequest, - DestroyGuestReply, DestroyGuestRequest, GuestInfo, LaunchGuestReply, LaunchGuestRequest, - ListGuestsReply, ListGuestsRequest, WatchEventsReply, WatchEventsRequest, + control_service_server::ControlService, guest_image_spec::Image, ConsoleDataReply, + ConsoleDataRequest, DestroyGuestReply, DestroyGuestRequest, GuestImageSpec, GuestInfo, + GuestNetworkInfo, GuestOciImageSpec, LaunchGuestReply, LaunchGuestRequest, ListGuestsReply, + ListGuestsRequest, WatchEventsReply, WatchEventsRequest, }; use tokio::{ io::{AsyncReadExt, AsyncWriteExt}, @@ -65,10 +66,25 @@ impl ControlService for RuntimeControlService { request: Request, ) -> Result, Status> { let request = request.into_inner(); + let Some(image) = request.image else { + return Err(ApiError { + message: "image spec not provider".to_string(), + } + .into()); + }; + let oci = match image.image { + Some(Image::Oci(oci)) => oci, + None => { + return Err(ApiError { + message: "image spec not provided".to_string(), + } + .into()) + } + }; let guest: GuestInfo = convert_guest_info( self.runtime .launch(GuestLaunchRequest { - image: &request.image, + image: &oci.image, vcpus: request.vcpus, mem: request.mem, env: empty_vec_optional(request.env), @@ -182,8 +198,12 @@ fn empty_vec_optional(value: Vec) -> Option> { fn convert_guest_info(value: kratart::GuestInfo) -> GuestInfo { GuestInfo { id: value.uuid.to_string(), - image: value.image, - ipv4: value.ipv4.map(|x| x.ip().to_string()).unwrap_or_default(), - ipv6: value.ipv6.map(|x| x.ip().to_string()).unwrap_or_default(), + image: Some(GuestImageSpec { + image: Some(Image::Oci(GuestOciImageSpec { image: value.image })), + }), + network: Some(GuestNetworkInfo { + ipv4: value.ipv4.map(|x| x.ip().to_string()).unwrap_or_default(), + ipv6: value.ipv6.map(|x| x.ip().to_string()).unwrap_or_default(), + }), } }