From ed37715e05844a3d2d0eefc9aad5b6a03f18e748 Mon Sep 17 00:00:00 2001 From: Anastassios Nanos Date: Mon, 29 May 2023 09:45:20 +0000 Subject: [PATCH] runtime-rs: handle copy files when share_fs is not available In hypervisors that do not support virtiofs we have to copy files in the VM sandbox to properly setup the network (resolv.conf, hosts, and hostname). To do that, we construct the volume as before, with the addition of an extra variable that designates the path where the file will reside in the sandbox. In this case, we issue a `copy_file` agent request *and* we patch the spec to account for this change. Fixes: #6978 Signed-off-by: Anastassios Nanos Signed-off-by: George Pyrros --- .../crates/resource/src/manager_inner.rs | 2 + .../crates/resource/src/volume/mod.rs | 7 +- .../resource/src/volume/share_fs_volume.rs | 70 ++++++++++++++++++- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/runtime-rs/crates/resource/src/manager_inner.rs b/src/runtime-rs/crates/resource/src/manager_inner.rs index 16f55a36a6..18e74dacf4 100644 --- a/src/runtime-rs/crates/resource/src/manager_inner.rs +++ b/src/runtime-rs/crates/resource/src/manager_inner.rs @@ -10,6 +10,7 @@ use crate::{network::NetworkConfig, resource_persist::ResourceState}; use agent::{types::Device, Agent, Storage}; use anyhow::{anyhow, Context, Ok, Result}; use async_trait::async_trait; + use hypervisor::{ device::{device_manager::DeviceManager, DeviceConfig}, BlockConfig, Hypervisor, @@ -255,6 +256,7 @@ impl ResourceManagerInner { spec, self.device_manager.as_ref(), &self.sid, + self.agent.clone(), ) .await } diff --git a/src/runtime-rs/crates/resource/src/volume/mod.rs b/src/runtime-rs/crates/resource/src/volume/mod.rs index ea7d4f5d60..52b826b2db 100644 --- a/src/runtime-rs/crates/resource/src/volume/mod.rs +++ b/src/runtime-rs/crates/resource/src/volume/mod.rs @@ -11,13 +11,13 @@ mod share_fs_volume; mod shm_volume; use async_trait::async_trait; +use crate::{share_fs::ShareFs, volume::block_volume::is_block_volume}; +use agent::Agent; use anyhow::{Context, Result}; use hypervisor::device::device_manager::DeviceManager; use std::{sync::Arc, vec::Vec}; use tokio::sync::RwLock; -use crate::{share_fs::ShareFs, volume::block_volume::is_block_volume}; - use self::hugepage::{get_huge_page_limits_map, get_huge_page_option}; const BIND: &str = "bind"; @@ -52,6 +52,7 @@ impl VolumeResource { spec: &oci::Spec, d: &RwLock, sid: &str, + agent: Arc, ) -> Result>> { let mut volumes: Vec> = vec![]; let oci_mounts = &spec.mounts; @@ -85,7 +86,7 @@ impl VolumeResource { ) } else if share_fs_volume::is_share_fs_volume(m) { Arc::new( - share_fs_volume::ShareFsVolume::new(share_fs, m, cid, read_only) + share_fs_volume::ShareFsVolume::new(share_fs, m, cid, read_only, agent.clone()) .await .with_context(|| format!("new share fs volume {:?}", m))?, ) diff --git a/src/runtime-rs/crates/resource/src/volume/share_fs_volume.rs b/src/runtime-rs/crates/resource/src/volume/share_fs_volume.rs index 0748e374d1..098dc399f7 100644 --- a/src/runtime-rs/crates/resource/src/volume/share_fs_volume.rs +++ b/src/runtime-rs/crates/resource/src/volume/share_fs_volume.rs @@ -5,11 +5,15 @@ // use std::{ + fs::File, + io::Read, + os::unix::fs::MetadataExt, path::{Path, PathBuf}, str::FromStr, sync::Arc, }; +use agent::Agent; use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use hypervisor::device::device_manager::DeviceManager; @@ -19,6 +23,9 @@ use super::Volume; use crate::share_fs::{MountedInfo, ShareFs, ShareFsVolumeConfig}; use kata_types::mount; +use crate::share_fs::DEFAULT_KATA_GUEST_SANDBOX_DIR; +use crate::share_fs::PASSTHROUGH_FS_DIR; + const SYS_MOUNT_PREFIX: [&str; 2] = ["/proc", "/sys"]; // copy file to container's rootfs if filesystem sharing is not supported, otherwise @@ -39,6 +46,7 @@ impl ShareFsVolume { m: &oci::Mount, cid: &str, readonly: bool, + agent: Arc, ) -> Result { // The file_name is in the format of "sandbox-{uuid}-{file_name}" let file_name = Path::new(&m.source).file_name().unwrap().to_str().unwrap(); @@ -61,11 +69,67 @@ impl ShareFsVolume { Ok(src) => src, }; + // If the mount source is a file, we can copy it to the sandbox if src.is_file() { - // TODO: copy file - debug!(sl!(), "FIXME: copy file {}", &m.source); - } else { + // This is where we set the value for the guest path + let dest = [ + DEFAULT_KATA_GUEST_SANDBOX_DIR, + PASSTHROUGH_FS_DIR, + file_name.clone().as_str(), + ] + .join("/"); + debug!( + sl!(), + "copy local file {:?} to guest {:?}", + &m.source, + dest.clone() + ); + + // Read file metadata + let file_metadata = std::fs::metadata(src.clone()) + .with_context(|| format!("Failed to read metadata from file: {:?}", src))?; + + // Open file + let mut file = File::open(&src) + .with_context(|| format!("Failed to open file: {:?}", src))?; + + // Open read file contents to buffer + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer) + .with_context(|| format!("Failed to read file: {:?}", src))?; + + // Create gRPC request + let r = agent::CopyFileRequest { + path: dest.clone(), + file_size: file_metadata.len() as i64, + uid: file_metadata.uid() as i32, + gid: file_metadata.gid() as i32, + file_mode: file_metadata.mode(), + data: buffer, + ..Default::default() + }; + + debug!(sl!(), "copy_file: {:?} to sandbox {:?}", &src, dest.clone()); + + // Issue gRPC request to agent + agent.copy_file(r).await.with_context(|| { + format!( + "copy file request failed: src: {:?}, dest: {:?}", + file_name, dest + ) + })?; + + // append oci::Mount structure to volume mounts + volume.mounts.push(oci::Mount { + destination: m.destination.clone(), + r#type: "bind".to_string(), + source: dest.clone(), + options: m.options.clone(), + }) + } else { + // If not, we can ignore it. Let's issue a warning so that the user knows. + warn!( sl!(), "Ignoring non-regular file as FS sharing not supported. mount: {:?}", m );