Skip to content

Commit

Permalink
runtime-rs: Enhancing DirectVolMount Handling with Patching Support
Browse files Browse the repository at this point in the history
The current infra(K8S, CSI, CRI, Containerd) for Kata containers is
unable to properly handle direct volumes, resulting in the need for
workarounds like patching up mount type and options after it created.

Fixes: #8300

Signed-off-by: alex.lyn <alex.lyn@antgroup.com>
  • Loading branch information
Apokleos committed Oct 26, 2023
1 parent 1b8ec08 commit 791f2d9
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 18 deletions.
75 changes: 61 additions & 14 deletions src/libs/kata-sys-util/src/k8s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
//! This module depends on kubelet internal implementation details, a better way is needed
//! to detect K8S EmptyDir medium type from `oci::spec::Mount` objects.

use kata_types::mount;
use oci::Spec;
use anyhow::{anyhow, Result};

use kata_types::mount::{self, get_volume_mount_info};
use oci::{Mount, Spec};

use crate::mount::get_linux_mount_info;

Expand Down Expand Up @@ -49,23 +51,68 @@ pub fn is_host_empty_dir(path: &str) -> bool {
false
}

// update_ephemeral_storage_type sets the mount type to 'ephemeral'
// patchup_container_storage_type to correct the mount type
pub fn patchup_container_storage_type(oci_spec: &mut Spec) -> Result<()> {
for m in oci_spec.mounts.iter_mut() {
patchup_ephemeral_volume_type(m)?;
patchup_direct_volume_type(m)?;
}

Ok(())
}

// patchup_ephemeral_volume_type sets the mount type to 'ephemeral'
// if the mount source path is provisioned by k8s for ephemeral storage.
// For the given pod ephemeral volume is created only once
// backed by tmpfs inside the VM. For successive containers
// of the same pod the already existing volume is reused.
pub fn update_ephemeral_storage_type(oci_spec: &mut Spec) {
for m in oci_spec.mounts.iter_mut() {
if mount::is_kata_guest_mount_volume(&m.r#type) {
continue;
}
fn patchup_ephemeral_volume_type(mount: &mut Mount) -> Result<()> {
if mount::is_kata_guest_mount_volume(&mount.r#type) {
return Ok(());
}

if is_ephemeral_volume(&m.source) {
m.r#type = String::from(mount::KATA_EPHEMERAL_VOLUME_TYPE);
} else if is_host_empty_dir(&m.source) {
// FIXME support disable_guest_empty_dir
// https://github.com/kata-containers/kata-containers/blob/02a51e75a7e0c6fce5e8abe3b991eeac87e09645/src/runtime/pkg/katautils/create.go#L105
m.r#type = String::from(mount::KATA_HOST_DIR_VOLUME_TYPE);
if is_ephemeral_volume(&mount.source) {
mount.r#type = String::from(mount::KATA_EPHEMERAL_VOLUME_TYPE);
} else if is_host_empty_dir(&mount.source) {
// FIXME support disable_guest_empty_dir
// https://github.com/kata-containers/kata-containers/blob/02a51e75a7e0c6fce5e8abe3b991eeac87e09645/src/runtime/pkg/katautils/create.go#L105
mount.r#type = String::from(mount::KATA_HOST_DIR_VOLUME_TYPE);
}

Ok(())
}

// patchup_direct_volume_type tries to patch up the created direct volume mount for the container.
// Note: Not all mounts require patching; our focus is solely on direct volumes.
fn patchup_direct_volume_type(mount: &mut Mount) -> Result<()> {
// Only handle bind Mount
if mount.r#type != "bind" {
return Ok(());
}

match get_volume_mount_info(&mount.source) {
Ok(m) => {
mount.r#type = m.volume_type;
}
Err(e) => {
// In the direct volume scenario, we check if the source of a mount is in the
// /run/kata-containers/shared/direct-volumes/SID path by iterating over all the mounts.
// If the source is not in the path, we ignore the error (Just return Ok(())) instead
// of returning it.
if let Some(&error_kind) = e.downcast_ref::<std::io::ErrorKind>() {
match error_kind {
std::io::ErrorKind::NotFound => return Ok(()),
_ => {
return Err(anyhow!(format!(
"failed to parse volume mount info for {:?}, with error {:?}",
mount.source,
e.to_string()
)))
}
}
}
}
}

Ok(())
}
2 changes: 1 addition & 1 deletion src/libs/kata-types/src/mount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ impl<H> StorageHandlerManager<H> {
/// The `volume_path` is base64-url-encoded and then safely joined to the `prefix`
pub fn join_path(prefix: &str, volume_path: &str) -> Result<PathBuf> {
if volume_path.is_empty() {
return Err(anyhow!("volume path must not be empty"));
return Err(anyhow!(std::io::ErrorKind::NotFound));
}
let b64_url_encoded_path = base64::encode_config(volume_path.as_bytes(), base64::URL_SAFE);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use common::{
ProcessType,
},
};
use kata_sys_util::k8s::update_ephemeral_storage_type;
use kata_sys_util::k8s::patchup_container_storage_type;

use oci::{LinuxResources, Process as OCIProcess};
use resource::{ResourceManager, ResourceUpdateOp};
Expand Down Expand Up @@ -470,7 +470,7 @@ fn amend_spec(spec: &mut oci::Spec, disable_guest_seccomp: bool) -> Result<()> {
};

// special process K8s ephemeral volumes.
update_ephemeral_storage_type(spec);
patchup_container_storage_type(spec).context("patch up container storage type failed")?;

if let Some(linux) = spec.linux.as_mut() {
if disable_guest_seccomp {
Expand Down
2 changes: 1 addition & 1 deletion src/tools/kata-ctl/src/ops/volume_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ mod tests {
TestData {
rootfs: root_fs_str,
volume_path: "",
result: Err(anyhow!("volume path must not be empty")),
result: Err(anyhow!(std::io::ErrorKind::NotFound)),
},
TestData {
rootfs: root_fs_str,
Expand Down

0 comments on commit 791f2d9

Please sign in to comment.