control: introduce protocol for alternative image specs

This commit is contained in:
Alex Zenla
2024-03-08 08:47:18 +00:00
parent bbf4d403f4
commit 7507f17d99
3 changed files with 78 additions and 17 deletions

View File

@ -6,15 +6,29 @@ option java_outer_classname = "ControlProto";
package krata.control; 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 { message GuestInfo {
string id = 1; string id = 1;
string image = 2; GuestImageSpec image = 2;
string ipv4 = 3; GuestNetworkInfo network = 3;
string ipv6 = 4;
} }
message LaunchGuestRequest { message LaunchGuestRequest {
string image = 1; GuestImageSpec image = 1;
uint32 vcpus = 2; uint32 vcpus = 2;
uint64 mem = 3; uint64 mem = 3;
repeated string env = 4; repeated string env = 4;

View File

@ -2,8 +2,8 @@ use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use env_logger::Env; use env_logger::Env;
use krata::control::{ use krata::control::{
watch_events_reply::Event, DestroyGuestRequest, LaunchGuestRequest, ListGuestsRequest, guest_image_spec::Image, watch_events_reply::Event, DestroyGuestRequest, GuestImageSpec,
WatchEventsRequest, GuestOciImageSpec, LaunchGuestRequest, ListGuestsRequest, WatchEventsRequest,
}; };
use kratactl::{client::ControlClientProvider, console::StdioConsoleStream}; use kratactl::{client::ControlClientProvider, console::StdioConsoleStream};
use tonic::Request; use tonic::Request;
@ -31,7 +31,7 @@ enum Commands {
#[arg(short, long)] #[arg(short, long)]
attach: bool, attach: bool,
#[arg()] #[arg()]
image: String, oci: String,
#[arg(allow_hyphen_values = true, trailing_var_arg = true)] #[arg(allow_hyphen_values = true, trailing_var_arg = true)]
run: Vec<String>, run: Vec<String>,
}, },
@ -55,7 +55,7 @@ async fn main() -> Result<()> {
match args.command { match args.command {
Commands::Launch { Commands::Launch {
image, oci,
cpus, cpus,
mem, mem,
attach, attach,
@ -63,7 +63,9 @@ async fn main() -> Result<()> {
run, run,
} => { } => {
let request = LaunchGuestRequest { let request = LaunchGuestRequest {
image, image: Some(GuestImageSpec {
image: Some(Image::Oci(GuestOciImageSpec { image: oci })),
}),
vcpus: cpus, vcpus: cpus,
mem, mem,
env: env.unwrap_or_default(), env: env.unwrap_or_default(),
@ -111,7 +113,32 @@ async fn main() -> Result<()> {
let header = vec!["uuid", "ipv4", "ipv6", "image"]; let header = vec!["uuid", "ipv4", "ipv6", "image"];
table.push_row(&header)?; table.push_row(&header)?;
for guest in response.guests { 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 { if table.num_records() == 1 {
println!("no guests have been launched"); println!("no guests have been launched");

View File

@ -3,9 +3,10 @@ use std::{io, pin::Pin};
use async_stream::try_stream; use async_stream::try_stream;
use futures::Stream; use futures::Stream;
use krata::control::{ use krata::control::{
control_service_server::ControlService, ConsoleDataReply, ConsoleDataRequest, control_service_server::ControlService, guest_image_spec::Image, ConsoleDataReply,
DestroyGuestReply, DestroyGuestRequest, GuestInfo, LaunchGuestReply, LaunchGuestRequest, ConsoleDataRequest, DestroyGuestReply, DestroyGuestRequest, GuestImageSpec, GuestInfo,
ListGuestsReply, ListGuestsRequest, WatchEventsReply, WatchEventsRequest, GuestNetworkInfo, GuestOciImageSpec, LaunchGuestReply, LaunchGuestRequest, ListGuestsReply,
ListGuestsRequest, WatchEventsReply, WatchEventsRequest,
}; };
use tokio::{ use tokio::{
io::{AsyncReadExt, AsyncWriteExt}, io::{AsyncReadExt, AsyncWriteExt},
@ -65,10 +66,25 @@ impl ControlService for RuntimeControlService {
request: Request<LaunchGuestRequest>, request: Request<LaunchGuestRequest>,
) -> Result<Response<LaunchGuestReply>, Status> { ) -> Result<Response<LaunchGuestReply>, Status> {
let request = request.into_inner(); 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( let guest: GuestInfo = convert_guest_info(
self.runtime self.runtime
.launch(GuestLaunchRequest { .launch(GuestLaunchRequest {
image: &request.image, image: &oci.image,
vcpus: request.vcpus, vcpus: request.vcpus,
mem: request.mem, mem: request.mem,
env: empty_vec_optional(request.env), env: empty_vec_optional(request.env),
@ -182,8 +198,12 @@ 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 {
id: value.uuid.to_string(), id: value.uuid.to_string(),
image: value.image, image: Some(GuestImageSpec {
ipv4: value.ipv4.map(|x| x.ip().to_string()).unwrap_or_default(), image: Some(Image::Oci(GuestOciImageSpec { image: value.image })),
ipv6: value.ipv6.map(|x| x.ip().to_string()).unwrap_or_default(), }),
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(),
}),
} }
} }