mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-05 22:21:31 +00:00
feat: oci compliance work (#85)
* chore: rework oci crate to be more composable * feat: image pull is now internally explicit * feat: utilize vfs for assembling oci images * feat: rework oci to preserve permissions via a vfs
This commit is contained in:
@ -1,5 +1,3 @@
|
||||
use std::{pin::Pin, str::FromStr};
|
||||
|
||||
use async_stream::try_stream;
|
||||
use futures::Stream;
|
||||
use krata::{
|
||||
@ -8,19 +6,26 @@ use krata::{
|
||||
IdmMetricsRequest,
|
||||
},
|
||||
v1::{
|
||||
common::{Guest, GuestState, GuestStatus},
|
||||
common::{Guest, GuestOciImageFormat, GuestState, GuestStatus},
|
||||
control::{
|
||||
control_service_server::ControlService, ConsoleDataReply, ConsoleDataRequest,
|
||||
CreateGuestReply, CreateGuestRequest, DestroyGuestReply, DestroyGuestRequest,
|
||||
ListGuestsReply, ListGuestsRequest, ReadGuestMetricsReply, ReadGuestMetricsRequest,
|
||||
ResolveGuestReply, ResolveGuestRequest, SnoopIdmReply, SnoopIdmRequest,
|
||||
WatchEventsReply, WatchEventsRequest,
|
||||
ListGuestsReply, ListGuestsRequest, PullImageReply, PullImageRequest,
|
||||
ReadGuestMetricsReply, ReadGuestMetricsRequest, ResolveGuestReply, ResolveGuestRequest,
|
||||
SnoopIdmReply, SnoopIdmRequest, WatchEventsReply, WatchEventsRequest,
|
||||
},
|
||||
},
|
||||
};
|
||||
use krataoci::{
|
||||
name::ImageName,
|
||||
packer::{service::OciPackerService, OciImagePacked, OciPackedFormat},
|
||||
progress::{OciProgress, OciProgressContext},
|
||||
};
|
||||
use std::{pin::Pin, str::FromStr};
|
||||
use tokio::{
|
||||
select,
|
||||
sync::mpsc::{channel, Sender},
|
||||
task::JoinError,
|
||||
};
|
||||
use tokio_stream::StreamExt;
|
||||
use tonic::{Request, Response, Status, Streaming};
|
||||
@ -28,7 +33,7 @@ use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
console::DaemonConsoleHandle, db::GuestStore, event::DaemonEventContext, idm::DaemonIdmHandle,
|
||||
metrics::idm_metric_to_api,
|
||||
metrics::idm_metric_to_api, oci::convert_oci_progress,
|
||||
};
|
||||
|
||||
pub struct ApiError {
|
||||
@ -50,21 +55,23 @@ impl From<ApiError> for Status {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RuntimeControlService {
|
||||
pub struct DaemonControlService {
|
||||
events: DaemonEventContext,
|
||||
console: DaemonConsoleHandle,
|
||||
idm: DaemonIdmHandle,
|
||||
guests: GuestStore,
|
||||
guest_reconciler_notify: Sender<Uuid>,
|
||||
packer: OciPackerService,
|
||||
}
|
||||
|
||||
impl RuntimeControlService {
|
||||
impl DaemonControlService {
|
||||
pub fn new(
|
||||
events: DaemonEventContext,
|
||||
console: DaemonConsoleHandle,
|
||||
idm: DaemonIdmHandle,
|
||||
guests: GuestStore,
|
||||
guest_reconciler_notify: Sender<Uuid>,
|
||||
packer: OciPackerService,
|
||||
) -> Self {
|
||||
Self {
|
||||
events,
|
||||
@ -72,6 +79,7 @@ impl RuntimeControlService {
|
||||
idm,
|
||||
guests,
|
||||
guest_reconciler_notify,
|
||||
packer,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -81,11 +89,19 @@ enum ConsoleDataSelect {
|
||||
Write(Option<Result<ConsoleDataRequest, tonic::Status>>),
|
||||
}
|
||||
|
||||
enum PullImageSelect {
|
||||
Progress(usize),
|
||||
Completed(Result<Result<OciImagePacked, anyhow::Error>, JoinError>),
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl ControlService for RuntimeControlService {
|
||||
impl ControlService for DaemonControlService {
|
||||
type ConsoleDataStream =
|
||||
Pin<Box<dyn Stream<Item = Result<ConsoleDataReply, Status>> + Send + 'static>>;
|
||||
|
||||
type PullImageStream =
|
||||
Pin<Box<dyn Stream<Item = Result<PullImageReply, Status>> + Send + 'static>>;
|
||||
|
||||
type WatchEventsStream =
|
||||
Pin<Box<dyn Stream<Item = Result<WatchEventsReply, Status>> + Send + 'static>>;
|
||||
|
||||
@ -337,6 +353,71 @@ impl ControlService for RuntimeControlService {
|
||||
Ok(Response::new(reply))
|
||||
}
|
||||
|
||||
async fn pull_image(
|
||||
&self,
|
||||
request: Request<PullImageRequest>,
|
||||
) -> Result<Response<Self::PullImageStream>, Status> {
|
||||
let request = request.into_inner();
|
||||
let name = ImageName::parse(&request.image).map_err(|err| ApiError {
|
||||
message: err.to_string(),
|
||||
})?;
|
||||
let format = match request.format() {
|
||||
GuestOciImageFormat::Unknown => OciPackedFormat::Squashfs,
|
||||
GuestOciImageFormat::Squashfs => OciPackedFormat::Squashfs,
|
||||
GuestOciImageFormat::Erofs => OciPackedFormat::Erofs,
|
||||
};
|
||||
let (sender, mut receiver) = channel::<OciProgress>(100);
|
||||
let context = OciProgressContext::new(sender);
|
||||
|
||||
let our_packer = self.packer.clone();
|
||||
|
||||
let output = try_stream! {
|
||||
let mut task = tokio::task::spawn(async move {
|
||||
our_packer.request(name, format, context).await
|
||||
});
|
||||
loop {
|
||||
let mut progresses = Vec::new();
|
||||
let what = select! {
|
||||
x = receiver.recv_many(&mut progresses, 10) => PullImageSelect::Progress(x),
|
||||
x = &mut task => PullImageSelect::Completed(x),
|
||||
};
|
||||
match what {
|
||||
PullImageSelect::Progress(count) => {
|
||||
if count > 0 {
|
||||
let progress = progresses.remove(progresses.len() - 1);
|
||||
let reply = PullImageReply {
|
||||
progress: Some(convert_oci_progress(progress)),
|
||||
digest: String::new(),
|
||||
format: GuestOciImageFormat::Unknown.into(),
|
||||
};
|
||||
yield reply;
|
||||
}
|
||||
},
|
||||
|
||||
PullImageSelect::Completed(result) => {
|
||||
let result = result.map_err(|err| ApiError {
|
||||
message: err.to_string(),
|
||||
})?;
|
||||
let packed = result.map_err(|err| ApiError {
|
||||
message: err.to_string(),
|
||||
})?;
|
||||
let reply = PullImageReply {
|
||||
progress: None,
|
||||
digest: packed.digest,
|
||||
format: match packed.format {
|
||||
OciPackedFormat::Squashfs => GuestOciImageFormat::Squashfs.into(),
|
||||
OciPackedFormat::Erofs => GuestOciImageFormat::Erofs.into(),
|
||||
},
|
||||
};
|
||||
yield reply;
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(Response::new(Box::pin(output) as Self::PullImageStream))
|
||||
}
|
||||
|
||||
async fn watch_events(
|
||||
&self,
|
||||
request: Request<WatchEventsRequest>,
|
||||
|
Reference in New Issue
Block a user