From 53ea36d3f5b387a0e39d1dd81b93bf1319c2a089 Mon Sep 17 00:00:00 2001 From: ChengyuZhu6 Date: Fri, 1 Sep 2023 14:29:20 +0800 Subject: [PATCH] agent: Introduce ImagePullHandler to support IMAGE_GUEST_PULL volume As we do not employ a forked containerd, we utilize the KataVirtualVolume which storing the image url supplied by snapshotter as an integral part of `CreateContainer`. Within this process, we store the image information in rootfs.storage and pass this image url through `CreateContainerRequest`. This approach distinguishes itself from the use of `PullImageRequest`, as rootfs.storage is already set and initialized at this stage. To maintain clarity and avoid any need for modification to the `OverlayfsHandler`,we introduce the `ImagePullHandler`. This dedicated handler is responsible for orchestrating the image-pulling logic within the guest environment. This logic encompasses tasks such as calling the image-rs to download and unpack the image into `/run/kata-containers/{container_id}/images`, followed by a bind mount to `/run/kata-containers/{container_id}`. Signed-off-by: ChengyuZhu6 --- src/agent/src/image_rpc.rs | 12 ++- src/agent/src/storage/image_pull_handler.rs | 102 ++++++++++++++++++++ src/agent/src/storage/mod.rs | 9 +- 3 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 src/agent/src/storage/image_pull_handler.rs diff --git a/src/agent/src/image_rpc.rs b/src/agent/src/image_rpc.rs index d9812b660d..94d45cb2fd 100644 --- a/src/agent/src/image_rpc.rs +++ b/src/agent/src/image_rpc.rs @@ -198,10 +198,16 @@ impl ImageService { Ok(()) } - /// Pull image when creating container and return the bunld path with rootfs. - pub async fn pull_image_for_container(&self, image: &str, cid: &str) -> Result { + /// Pull image when creating container and return the bundle path with rootfs. + pub async fn pull_image_for_container( + &self, + image: &str, + cid: &str, + image_metadata: &HashMap, + ) -> Result { + info!(sl(), "image metadata: {:?}", image_metadata); Self::set_proxy_env_vars(); - if image.starts_with("pause") { + if image_metadata["io.kubernetes.cri.container-type"] == "sandbox" { let mount_path = Self::unpack_pause_image(cid, "pause")?; self.add_image(String::from(image), String::from(cid)).await; return Ok(mount_path); diff --git a/src/agent/src/storage/image_pull_handler.rs b/src/agent/src/storage/image_pull_handler.rs new file mode 100644 index 0000000000..3ddfcbe87a --- /dev/null +++ b/src/agent/src/storage/image_pull_handler.rs @@ -0,0 +1,102 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::{anyhow, Result}; +use kata_types::mount::KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL; +use kata_types::mount::{ImagePullVolume, StorageDevice}; +use protocols::agent::Storage; +use std::sync::Arc; +use tracing::instrument; + +use crate::image_rpc; +use crate::storage::{StorageContext, StorageHandler}; + +use super::{common_storage_handler, new_device}; + +#[derive(Debug)] +pub struct ImagePullHandler {} + +impl ImagePullHandler { + fn get_image_info(storage: &Storage) -> Result { + for option in storage.driver_options.iter() { + if let Some((key, value)) = option.split_once('=') { + if key == KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL { + let imagepull_volume: ImagePullVolume = serde_json::from_str(value)?; + return Ok(imagepull_volume); + } + } + } + Err(anyhow!("missing Image information for ImagePull volume")) + } +} + +#[async_trait::async_trait] +impl StorageHandler for ImagePullHandler { + #[instrument] + async fn create_device( + &self, + mut storage: Storage, + ctx: &mut StorageContext, + ) -> Result> { + //Currently the image metadata is not used to pulling image in the guest. + let image_pull_volume = Self::get_image_info(&storage)?; + debug!(ctx.logger, "image_pull_volume = {:?}", image_pull_volume); + let image_name = storage.source(); + debug!(ctx.logger, "image_name = {:?}", image_name); + + let cid = ctx + .cid + .clone() + .ok_or_else(|| anyhow!("failed to get container id"))?; + let image_service = image_rpc::ImageService::singleton().await?; + let bundle_path = image_service + .pull_image_for_container(image_name, &cid, &image_pull_volume.metadata) + .await?; + + storage.source = bundle_path; + storage.options = vec!["bind".to_string(), "ro".to_string()]; + + common_storage_handler(ctx.logger, &storage)?; + + new_device(storage.mount_point) + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use kata_types::mount::{ImagePullVolume, KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL}; + use protocols::agent::Storage; + + use crate::storage::image_pull_handler::ImagePullHandler; + + #[test] + fn test_get_image_info() { + let mut res = HashMap::new(); + res.insert("key1".to_string(), "value1".to_string()); + res.insert("key2".to_string(), "value2".to_string()); + + let image_pull = ImagePullVolume { + metadata: res.clone(), + }; + + let image_pull_str = serde_json::to_string(&image_pull); + assert!(image_pull_str.is_ok()); + + let storage = Storage { + driver: KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL.to_string(), + driver_options: vec![format!("image_guest_pull={}", image_pull_str.ok().unwrap())], + ..Default::default() + }; + + match ImagePullHandler::get_image_info(&storage) { + Ok(image_info) => { + assert_eq!(image_info.metadata, res); + } + Err(e) => panic!("err = {}", e), + } + } +} diff --git a/src/agent/src/storage/mod.rs b/src/agent/src/storage/mod.rs index a8a3b3717a..1f3d86c875 100644 --- a/src/agent/src/storage/mod.rs +++ b/src/agent/src/storage/mod.rs @@ -12,7 +12,10 @@ use std::sync::Arc; use anyhow::{anyhow, Context, Result}; use kata_sys_util::mount::{create_mount_destination, parse_mount_options}; -use kata_types::mount::{StorageDevice, StorageHandlerManager, KATA_SHAREDFS_GUEST_PREMOUNT_TAG}; +use kata_types::mount::{ + StorageDevice, StorageHandlerManager, KATA_SHAREDFS_GUEST_PREMOUNT_TAG, + KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL, +}; use kata_types::volume::KATA_VOLUME_TYPE_DMVERITY; use nix::unistd::{Gid, Uid}; use protocols::agent::Storage; @@ -26,7 +29,9 @@ use self::block_handler::{PmemHandler, ScsiHandler, VirtioBlkMmioHandler, Virtio use self::dm_verity::DmVerityHandler; use self::ephemeral_handler::EphemeralHandler; use self::fs_handler::{OverlayfsHandler, Virtio9pHandler, VirtioFsHandler}; +use self::image_pull_handler::ImagePullHandler; use self::local_handler::LocalHandler; + use crate::device::{ DRIVER_9P_TYPE, DRIVER_BLK_MMIO_TYPE, DRIVER_BLK_PCI_TYPE, DRIVER_EPHEMERAL_TYPE, DRIVER_LOCAL_TYPE, DRIVER_NVDIMM_TYPE, DRIVER_OVERLAYFS_TYPE, DRIVER_SCSI_TYPE, @@ -42,6 +47,7 @@ mod block_handler; mod dm_verity; mod ephemeral_handler; mod fs_handler; +mod image_pull_handler; mod local_handler; const RW_MASK: u32 = 0o660; @@ -149,6 +155,7 @@ lazy_static! { manager.add_handler(DRIVER_VIRTIOFS_TYPE, Arc::new(VirtioFsHandler{})).unwrap(); manager.add_handler(DRIVER_WATCHABLE_BIND_TYPE, Arc::new(BindWatcherHandler{})).unwrap(); manager.add_handler(KATA_VOLUME_TYPE_DMVERITY, Arc::new(DmVerityHandler{})).unwrap(); + manager.add_handler(KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL, Arc::new(ImagePullHandler{})).unwrap(); manager }; }