mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-30 14:25:43 +00:00
Merge pull request #7698 from jiangliu/virtual-volume
kata-types: introduce KataVirtualVolume to support nydus, direct volume and image pull
This commit is contained in:
commit
a6921dd837
@ -4,7 +4,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use anyhow::{anyhow, Context, Error, Result};
|
||||
use std::convert::TryFrom;
|
||||
use std::{collections::HashMap, fs, path::PathBuf};
|
||||
|
||||
/// Prefix to mark a volume as Kata special.
|
||||
@ -34,6 +35,23 @@ pub const SANDBOX_BIND_MOUNTS_RO: &str = ":ro";
|
||||
/// SANDBOX_BIND_MOUNTS_RO is for sandbox bindmounts with readwrite
|
||||
pub const SANDBOX_BIND_MOUNTS_RW: &str = ":rw";
|
||||
|
||||
/// Directly assign a block volume to vm and mount it inside guest.
|
||||
pub const KATA_VIRTUAL_VOLUME_DIRECT_BLOCK: &str = "direct_block";
|
||||
/// Present a container image as a generic block device.
|
||||
pub const KATA_VIRTUAL_VOLUME_IMAGE_RAW_BLOCK: &str = "image_raw_block";
|
||||
/// Present each container image layer as a generic block device.
|
||||
pub const KATA_VIRTUAL_VOLUME_LAYER_RAW_BLOCK: &str = "layer_raw_block";
|
||||
/// Present a container image as a nydus block device.
|
||||
pub const KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_BLOCK: &str = "image_nydus_block";
|
||||
/// Present each container image layer as a nydus block device.
|
||||
pub const KATA_VIRTUAL_VOLUME_LAYER_NYDUS_BLOCK: &str = "layer_nydus_block";
|
||||
/// Present a container image as a nydus filesystem.
|
||||
pub const KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS: &str = "image_nydus_fs";
|
||||
/// Present each container image layer as a nydus filesystem.
|
||||
pub const KATA_VIRTUAL_VOLUME_LAYER_NYDUS_FS: &str = "layer_nydus_fs";
|
||||
/// Download and extra container image inside guest vm.
|
||||
pub const KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL: &str = "image_guest_pull";
|
||||
|
||||
/// Information about a mount.
|
||||
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Mount {
|
||||
@ -66,7 +84,7 @@ impl Mount {
|
||||
|
||||
/// DirectVolumeMountInfo contains the information needed by Kata
|
||||
/// to consume a host block device and mount it as a filesystem inside the guest VM.
|
||||
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct DirectVolumeMountInfo {
|
||||
/// The type of the volume (ie. block)
|
||||
pub volume_type: String,
|
||||
@ -80,47 +98,6 @@ pub struct DirectVolumeMountInfo {
|
||||
pub options: Vec<String>,
|
||||
}
|
||||
|
||||
/// join_path joins user provided volumepath with kata direct-volume root path
|
||||
/// the volume_path is base64-encoded and then safely joined to the end of path 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"));
|
||||
}
|
||||
let b64_encoded_path = base64::encode(volume_path.as_bytes());
|
||||
|
||||
Ok(safe_path::scoped_join(prefix, b64_encoded_path)?)
|
||||
}
|
||||
|
||||
/// get DirectVolume mountInfo from mountinfo.json.
|
||||
pub fn get_volume_mount_info(volume_path: &str) -> Result<DirectVolumeMountInfo> {
|
||||
let mount_info_file_path =
|
||||
join_path(KATA_DIRECT_VOLUME_ROOT_PATH, volume_path)?.join(KATA_MOUNT_INFO_FILE_NAME);
|
||||
let mount_info_file = fs::read_to_string(mount_info_file_path)?;
|
||||
let mount_info: DirectVolumeMountInfo = serde_json::from_str(&mount_info_file)?;
|
||||
|
||||
Ok(mount_info)
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata specific volume.
|
||||
pub fn is_kata_special_volume(ty: &str) -> bool {
|
||||
ty.len() > KATA_VOLUME_TYPE_PREFIX.len() && ty.starts_with(KATA_VOLUME_TYPE_PREFIX)
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata guest mount volume.
|
||||
pub fn is_kata_guest_mount_volume(ty: &str) -> bool {
|
||||
ty.len() > KATA_GUEST_MOUNT_PREFIX.len() && ty.starts_with(KATA_GUEST_MOUNT_PREFIX)
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata ephemeral volume.
|
||||
pub fn is_kata_ephemeral_volume(ty: &str) -> bool {
|
||||
ty == KATA_EPHEMERAL_VOLUME_TYPE
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata hostdir volume.
|
||||
pub fn is_kata_host_dir_volume(ty: &str) -> bool {
|
||||
ty == KATA_HOST_DIR_VOLUME_TYPE
|
||||
}
|
||||
|
||||
/// Nydus extra options
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct NydusExtraOptions {
|
||||
@ -159,6 +136,333 @@ impl NydusExtraOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration information for DmVerity device.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct DmVerityInfo {
|
||||
/// Hash algorithm for dm-verity.
|
||||
pub hashtype: String,
|
||||
/// Root hash for device verification or activation.
|
||||
pub hash: String,
|
||||
/// Size of data device used in verification.
|
||||
pub blocknum: u64,
|
||||
/// Used block size for the data device.
|
||||
pub blocksize: u64,
|
||||
/// Used block size for the hash device.
|
||||
pub hashsize: u64,
|
||||
/// Offset of hash area/superblock on hash_device.
|
||||
pub offset: u64,
|
||||
}
|
||||
|
||||
/// Information about directly assigned volume.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct DirectAssignedVolume {
|
||||
/// Meta information for directly assigned volume.
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub metadata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
/// Information about pulling image inside guest.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct ImagePullVolume {
|
||||
/// Meta information for pulling image inside guest.
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub metadata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
/// Information about nydus image volume.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct NydusImageVolume {
|
||||
/// Nydus configuration information.
|
||||
#[serde(default, skip_serializing_if = "String::is_empty")]
|
||||
pub config: String,
|
||||
|
||||
/// Nydus snapshot directory
|
||||
#[serde(default, skip_serializing_if = "String::is_empty")]
|
||||
pub snapshot_dir: String,
|
||||
}
|
||||
|
||||
/// Kata virtual volume to encapsulate information for extra mount options and direct volumes.
|
||||
///
|
||||
/// It's very expensive to build direct communication channels to pass information:
|
||||
/// - between snapshotters and kata-runtime/kata-agent/image-rs
|
||||
/// - between CSI drivers and kata-runtime/kata-agent
|
||||
///
|
||||
/// So `KataVirtualVolume` is introduced to encapsulate extra mount options and direct volume
|
||||
/// information, so we can build a common infrastructure to handle them.
|
||||
/// `KataVirtualVolume` is a superset of `NydusExtraOptions` and `DirectVolumeMountInfo`.
|
||||
///
|
||||
/// Value of `volume_type` determines how to interpret other fields in the structure.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IGNORE`
|
||||
/// -- all other fields should be ignored/unused.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_DIRECT_BLOCK`
|
||||
/// -- `source`: the directly assigned block device
|
||||
/// -- `fs_type`: filesystem type
|
||||
/// -- `options`: mount options
|
||||
/// -- `direct_volume`: additional metadata to pass to the agent regarding this volume.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_RAW_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_RAW_BLOCK`
|
||||
/// -- `source`: path to the raw block image for the container image or layer.
|
||||
/// -- `fs_type`: filesystem type
|
||||
/// -- `options`: mount options
|
||||
/// -- `dm_verity`: disk dm-verity information
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_BLOCK` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_BLOCK`
|
||||
/// -- `source`: path to nydus meta blob
|
||||
/// -- `fs_type`: filesystem type
|
||||
/// -- `nydus_image`: configuration information for nydus image.
|
||||
/// -- `dm_verity`: disk dm-verity information
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS` or `KATA_VIRTUAL_VOLUME_LAYER_NYDUS_FS`
|
||||
/// -- `source`: path to nydus meta blob
|
||||
/// -- `fs_type`: filesystem type
|
||||
/// -- `nydus_image`: configuration information for nydus image.
|
||||
///
|
||||
/// - `KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL`
|
||||
/// -- `source`: image reference
|
||||
/// -- `image_pull`: metadata for image pulling
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct KataVirtualVolume {
|
||||
/// Type of virtual volume.
|
||||
pub volume_type: String,
|
||||
/// Source/device path for the virtual volume.
|
||||
#[serde(default, skip_serializing_if = "String::is_empty")]
|
||||
pub source: String,
|
||||
/// Filesystem type.
|
||||
#[serde(default, skip_serializing_if = "String::is_empty")]
|
||||
pub fs_type: String,
|
||||
/// Mount options.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub options: Vec<String>,
|
||||
|
||||
/// Information about directly assigned volume.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub direct_volume: Option<DirectAssignedVolume>,
|
||||
/// Information about pulling image inside guest.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub image_pull: Option<ImagePullVolume>,
|
||||
/// Information about nydus image volume.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub nydus_image: Option<NydusImageVolume>,
|
||||
/// DmVerity: configuration information
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub dm_verity: Option<DmVerityInfo>,
|
||||
}
|
||||
|
||||
impl KataVirtualVolume {
|
||||
/// Create a new instance of `KataVirtualVolume` with specified type.
|
||||
pub fn new(volume_type: String) -> Self {
|
||||
Self {
|
||||
volume_type,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate virtual volume object.
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
match self.volume_type.as_str() {
|
||||
KATA_VIRTUAL_VOLUME_DIRECT_BLOCK => {
|
||||
if self.source.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"missing source device for directly assigned block volume"
|
||||
));
|
||||
} else if self.fs_type.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"missing filesystem for directly assigned block volume"
|
||||
));
|
||||
}
|
||||
}
|
||||
KATA_VIRTUAL_VOLUME_IMAGE_RAW_BLOCK | KATA_VIRTUAL_VOLUME_LAYER_RAW_BLOCK => {
|
||||
if self.source.is_empty() {
|
||||
return Err(anyhow!("missing source device for raw block volume"));
|
||||
} else if self.fs_type.is_empty() {
|
||||
return Err(anyhow!("missing filesystem for raw block volume"));
|
||||
}
|
||||
}
|
||||
KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_BLOCK | KATA_VIRTUAL_VOLUME_LAYER_NYDUS_BLOCK => {
|
||||
if self.source.is_empty() {
|
||||
return Err(anyhow!("missing meta blob for nydus block volume"));
|
||||
} else if self.fs_type.as_str() != "rafsv6" {
|
||||
return Err(anyhow!("invalid filesystem for nydus block volume"));
|
||||
}
|
||||
match self.nydus_image.as_ref() {
|
||||
None => {
|
||||
return Err(anyhow!(
|
||||
"missing nydus configuration info for nydus block volume"
|
||||
))
|
||||
}
|
||||
Some(nydus) => {
|
||||
if nydus.config.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"missing configuration info for nydus block volume"
|
||||
));
|
||||
} else if nydus.snapshot_dir.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"missing snapshot directory for nydus block volume"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS | KATA_VIRTUAL_VOLUME_LAYER_NYDUS_FS => {
|
||||
if self.source.is_empty() {
|
||||
return Err(anyhow!("missing meta blob for nydus fs volume"));
|
||||
} else if self.fs_type.as_str() != "rafsv6" && self.fs_type.as_str() != "rafsv5" {
|
||||
return Err(anyhow!("invalid filesystem for nydus fs volume"));
|
||||
}
|
||||
match self.nydus_image.as_ref() {
|
||||
None => {
|
||||
return Err(anyhow!(
|
||||
"missing nydus configuration info for nydus block volume"
|
||||
))
|
||||
}
|
||||
Some(nydus) => {
|
||||
if nydus.config.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"missing configuration info for nydus block volume"
|
||||
));
|
||||
} else if nydus.snapshot_dir.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"missing snapshot directory for nydus block volume"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
KATA_VIRTUAL_VOLUME_IMAGE_GUEST_PULL => {
|
||||
if self.source.is_empty() {
|
||||
return Err(anyhow!("missing image reference for guest pulling volume"));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Serialize the virtual volume object to json.
|
||||
pub fn to_json(&self) -> Result<String> {
|
||||
Ok(serde_json::to_string(self)?)
|
||||
}
|
||||
|
||||
/// Deserialize a virtual volume object from json string.
|
||||
pub fn from_json(value: &str) -> Result<Self> {
|
||||
let volume: KataVirtualVolume = serde_json::from_str(value)?;
|
||||
volume.validate()?;
|
||||
Ok(volume)
|
||||
}
|
||||
|
||||
/// Serialize the virtual volume object to json and encode the string with base64.
|
||||
pub fn to_base64(&self) -> Result<String> {
|
||||
let json = self.to_json()?;
|
||||
Ok(base64::encode(json))
|
||||
}
|
||||
|
||||
/// Decode and deserialize a virtual volume object from base64 encoded json string.
|
||||
pub fn from_base64(value: &str) -> Result<Self> {
|
||||
let json = base64::decode(value)?;
|
||||
let volume: KataVirtualVolume = serde_json::from_slice(&json)?;
|
||||
volume.validate()?;
|
||||
Ok(volume)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&DirectVolumeMountInfo> for KataVirtualVolume {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &DirectVolumeMountInfo) -> std::result::Result<Self, Self::Error> {
|
||||
let volume_type = match value.volume_type.as_str() {
|
||||
"block" => KATA_VIRTUAL_VOLUME_DIRECT_BLOCK.to_string(),
|
||||
_ => {
|
||||
return Err(anyhow!(
|
||||
"unknown directly assigned volume type: {}",
|
||||
value.volume_type
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(KataVirtualVolume {
|
||||
volume_type,
|
||||
source: value.device.clone(),
|
||||
fs_type: value.fs_type.clone(),
|
||||
options: value.options.clone(),
|
||||
direct_volume: Some(DirectAssignedVolume {
|
||||
metadata: value.metadata.clone(),
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&NydusExtraOptions> for KataVirtualVolume {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &NydusExtraOptions) -> std::result::Result<Self, Self::Error> {
|
||||
let fs_type = match value.fs_version.as_str() {
|
||||
"v6" => "rafsv6".to_string(),
|
||||
"rafsv6" => "rafsv6".to_string(),
|
||||
"v5" => "rafsv5".to_string(),
|
||||
"rafsv5" => "rafsv5".to_string(),
|
||||
_ => return Err(anyhow!("unknown RAFS version: {}", value.fs_version)),
|
||||
};
|
||||
|
||||
Ok(KataVirtualVolume {
|
||||
volume_type: KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS.to_string(),
|
||||
source: value.source.clone(),
|
||||
fs_type,
|
||||
options: vec![],
|
||||
nydus_image: Some(NydusImageVolume {
|
||||
config: value.config.clone(),
|
||||
snapshot_dir: value.snapshot_dir.clone(),
|
||||
}),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Join user provided volume path with kata direct-volume root path.
|
||||
///
|
||||
/// The `volume_path` is base64-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"));
|
||||
}
|
||||
let b64_encoded_path = base64::encode(volume_path.as_bytes());
|
||||
|
||||
Ok(safe_path::scoped_join(prefix, b64_encoded_path)?)
|
||||
}
|
||||
|
||||
/// get DirectVolume mountInfo from mountinfo.json.
|
||||
pub fn get_volume_mount_info(volume_path: &str) -> Result<DirectVolumeMountInfo> {
|
||||
let volume_path = join_path(KATA_DIRECT_VOLUME_ROOT_PATH, volume_path)?;
|
||||
let mount_info_file_path = volume_path.join(KATA_MOUNT_INFO_FILE_NAME);
|
||||
let mount_info_file = fs::read_to_string(mount_info_file_path)?;
|
||||
let mount_info: DirectVolumeMountInfo = serde_json::from_str(&mount_info_file)?;
|
||||
|
||||
Ok(mount_info)
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata specific volume.
|
||||
pub fn is_kata_special_volume(ty: &str) -> bool {
|
||||
ty.len() > KATA_VOLUME_TYPE_PREFIX.len() && ty.starts_with(KATA_VOLUME_TYPE_PREFIX)
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata guest mount volume.
|
||||
pub fn is_kata_guest_mount_volume(ty: &str) -> bool {
|
||||
ty.len() > KATA_GUEST_MOUNT_PREFIX.len() && ty.starts_with(KATA_GUEST_MOUNT_PREFIX)
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata ephemeral volume.
|
||||
pub fn is_kata_ephemeral_volume(ty: &str) -> bool {
|
||||
ty == KATA_EPHEMERAL_VOLUME_TYPE
|
||||
}
|
||||
|
||||
/// Check whether a mount type is a marker for Kata hostdir volume.
|
||||
pub fn is_kata_host_dir_volume(ty: &str) -> bool {
|
||||
ty == KATA_HOST_DIR_VOLUME_TYPE
|
||||
}
|
||||
|
||||
/// sandbox bindmount format: /path/to/dir, or /path/to/dir:ro[:rw]
|
||||
/// the real path is without suffix ":ro" or ":rw".
|
||||
pub fn split_bind_mounts(bindmount: &str) -> (&str, &str) {
|
||||
@ -242,4 +546,111 @@ mod tests {
|
||||
);
|
||||
assert_eq!(extra_option.fs_version, "v6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kata_virtual_volume() {
|
||||
let mut volume = KataVirtualVolume::new(KATA_VIRTUAL_VOLUME_DIRECT_BLOCK.to_string());
|
||||
assert_eq!(
|
||||
volume.volume_type.as_str(),
|
||||
KATA_VIRTUAL_VOLUME_DIRECT_BLOCK
|
||||
);
|
||||
assert!(volume.fs_type.is_empty());
|
||||
|
||||
let value = serde_json::to_string(&volume).unwrap();
|
||||
assert_eq!(&value, "{\"volume_type\":\"direct_block\"}");
|
||||
|
||||
volume.source = "/tmp".to_string();
|
||||
volume.fs_type = "ext4".to_string();
|
||||
volume.options = vec!["rw".to_string()];
|
||||
volume.nydus_image = Some(NydusImageVolume {
|
||||
config: "test".to_string(),
|
||||
snapshot_dir: "/var/lib/nydus.dir".to_string(),
|
||||
});
|
||||
let mut metadata = HashMap::new();
|
||||
metadata.insert("mode".to_string(), "rw".to_string());
|
||||
volume.direct_volume = Some(DirectAssignedVolume { metadata });
|
||||
|
||||
let value = serde_json::to_string(&volume).unwrap();
|
||||
let volume2: KataVirtualVolume = serde_json::from_str(&value).unwrap();
|
||||
assert_eq!(volume.volume_type, volume2.volume_type);
|
||||
assert_eq!(volume.source, volume2.source);
|
||||
assert_eq!(volume.fs_type, volume2.fs_type);
|
||||
assert_eq!(volume.nydus_image, volume2.nydus_image);
|
||||
assert_eq!(volume.direct_volume, volume2.direct_volume);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kata_virtual_volume_serde() {
|
||||
let mut volume = KataVirtualVolume::new(KATA_VIRTUAL_VOLUME_DIRECT_BLOCK.to_string());
|
||||
volume.source = "/tmp".to_string();
|
||||
volume.fs_type = "ext4".to_string();
|
||||
volume.options = vec!["rw".to_string()];
|
||||
volume.nydus_image = Some(NydusImageVolume {
|
||||
config: "test".to_string(),
|
||||
snapshot_dir: "/var/lib/nydus.dir".to_string(),
|
||||
});
|
||||
let mut metadata = HashMap::new();
|
||||
metadata.insert("mode".to_string(), "rw".to_string());
|
||||
volume.direct_volume = Some(DirectAssignedVolume { metadata });
|
||||
|
||||
let value = volume.to_base64().unwrap();
|
||||
let volume2: KataVirtualVolume = KataVirtualVolume::from_base64(value.as_str()).unwrap();
|
||||
assert_eq!(volume.volume_type, volume2.volume_type);
|
||||
assert_eq!(volume.source, volume2.source);
|
||||
assert_eq!(volume.fs_type, volume2.fs_type);
|
||||
assert_eq!(volume.nydus_image, volume2.nydus_image);
|
||||
assert_eq!(volume.direct_volume, volume2.direct_volume);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_from_direct_volume() {
|
||||
let mut metadata = HashMap::new();
|
||||
metadata.insert("mode".to_string(), "rw".to_string());
|
||||
let mut direct = DirectVolumeMountInfo {
|
||||
volume_type: "unknown".to_string(),
|
||||
device: "/dev/vda".to_string(),
|
||||
fs_type: "ext4".to_string(),
|
||||
metadata,
|
||||
options: vec!["ro".to_string()],
|
||||
};
|
||||
KataVirtualVolume::try_from(&direct).unwrap_err();
|
||||
|
||||
direct.volume_type = "block".to_string();
|
||||
let volume = KataVirtualVolume::try_from(&direct).unwrap();
|
||||
assert_eq!(
|
||||
volume.volume_type.as_str(),
|
||||
KATA_VIRTUAL_VOLUME_DIRECT_BLOCK
|
||||
);
|
||||
assert_eq!(volume.source, direct.device);
|
||||
assert_eq!(volume.fs_type, direct.fs_type);
|
||||
assert_eq!(
|
||||
volume.direct_volume.as_ref().unwrap().metadata,
|
||||
direct.metadata
|
||||
);
|
||||
assert_eq!(volume.options, direct.options);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_from_nydus_extra_options() {
|
||||
let mut nydus = NydusExtraOptions {
|
||||
source: "/test/nydus".to_string(),
|
||||
config: "test".to_string(),
|
||||
snapshot_dir: "/var/lib/nydus".to_string(),
|
||||
fs_version: "rafsvx".to_string(),
|
||||
};
|
||||
KataVirtualVolume::try_from(&nydus).unwrap_err();
|
||||
|
||||
nydus.fs_version = "v6".to_string();
|
||||
let volume = KataVirtualVolume::try_from(&nydus).unwrap();
|
||||
assert_eq!(
|
||||
volume.volume_type.as_str(),
|
||||
KATA_VIRTUAL_VOLUME_IMAGE_NYDUS_FS
|
||||
);
|
||||
assert_eq!(volume.nydus_image.as_ref().unwrap().config, nydus.config);
|
||||
assert_eq!(
|
||||
volume.nydus_image.as_ref().unwrap().snapshot_dir,
|
||||
nydus.snapshot_dir
|
||||
);
|
||||
assert_eq!(volume.fs_type.as_str(), "rafsv6")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user