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 <ananos@nubificus.co.uk>
Signed-off-by: George Pyrros <gpyrros@nubificus.co.uk>
This commit is contained in:
Anastassios Nanos 2023-05-29 09:45:20 +00:00
parent 18b1a019d4
commit ed37715e05
3 changed files with 73 additions and 6 deletions

View File

@ -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
}

View File

@ -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<DeviceManager>,
sid: &str,
agent: Arc<dyn Agent>,
) -> Result<Vec<Arc<dyn Volume>>> {
let mut volumes: Vec<Arc<dyn Volume>> = 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))?,
)

View File

@ -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<dyn Agent>,
) -> Result<Self> {
// 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
);