Skip to content

Commit

Permalink
Merge pull request #1139 from jiangliu/block-nbd
Browse files Browse the repository at this point in the history
Export Nydus images as block devices by using NBD
  • Loading branch information
imeoer authored Mar 7, 2023
2 parents 6b1998f + f9b051e commit 3ef8489
Show file tree
Hide file tree
Showing 20 changed files with 1,855 additions and 222 deletions.
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ virtiofs = [
"virtio-queue",
"vm-memory",
]
block-nbd = [
"nydus-service/block-nbd"
]

backend-http-proxy = ["nydus-storage/backend-http-proxy"]
backend-localdisk = ["nydus-storage/backend-localdisk"]
Expand Down
145 changes: 144 additions & 1 deletion api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -890,11 +890,54 @@ pub struct BlobCacheEntryConfigV2 {
/// Configuration information for local cache system.
#[serde(default)]
pub cache: CacheConfigV2,
/// Optional file path for metadata blobs.
/// Optional file path for metadata blob.
#[serde(default)]
pub metadata_path: Option<String>,
}

impl BlobCacheEntryConfigV2 {
/// Read configuration information from a file.
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
let md = fs::metadata(path.as_ref())?;
if md.len() > 0x100000 {
return Err(eother!("configuration file size is too big"));
}
let content = fs::read_to_string(path)?;
Self::from_str(&content)
}

/// Validate the configuration object.
pub fn validate(&self) -> bool {
if self.version != 2 {
return false;
}
let config: ConfigV2 = self.into();
config.validate()
}
}

impl FromStr for BlobCacheEntryConfigV2 {
type Err = Error;

fn from_str(s: &str) -> Result<BlobCacheEntryConfigV2> {
if let Ok(v) = serde_json::from_str::<BlobCacheEntryConfigV2>(s) {
return if v.validate() {
Ok(v)
} else {
Err(einval!("invalid configuration"))
};
}
if let Ok(v) = toml::from_str::<BlobCacheEntryConfigV2>(s) {
return if v.validate() {
Ok(v)
} else {
Err(einval!("invalid configuration"))
};
}
Err(einval!("failed to parse configuration information"))
}
}

impl From<&BlobCacheEntryConfigV2> for ConfigV2 {
fn from(c: &BlobCacheEntryConfigV2) -> Self {
ConfigV2 {
Expand Down Expand Up @@ -943,6 +986,106 @@ impl ConfigV2Internal {
}
}

/// Blob cache object type for nydus/rafs bootstrap blob.
pub const BLOB_CACHE_TYPE_META_BLOB: &str = "bootstrap";
/// Blob cache object type for nydus/rafs data blob.
pub const BLOB_CACHE_TYPE_DATA_BLOB: &str = "datablob";

/// Configuration information for a cached blob.
#[derive(Debug, Deserialize, Serialize)]
pub struct BlobCacheEntry {
/// Type of blob object, bootstrap or data blob.
#[serde(rename = "type")]
pub blob_type: String,
/// Blob id.
#[serde(rename = "id")]
pub blob_id: String,
/// Configuration information to generate blob cache object.
#[serde(default, rename = "config")]
pub(crate) blob_config_legacy: Option<BlobCacheEntryConfig>,
/// Configuration information to generate blob cache object.
#[serde(default, rename = "config_v2")]
pub blob_config: Option<BlobCacheEntryConfigV2>,
/// Domain id for the blob, which is used to group cached blobs into management domains.
#[serde(default)]
pub domain_id: String,
}

impl BlobCacheEntry {
pub fn prepare_configuration_info(&mut self) -> bool {
if self.blob_config.is_none() {
if let Some(legacy) = self.blob_config_legacy.as_ref() {
match legacy.try_into() {
Err(_) => return false,
Ok(v) => self.blob_config = Some(v),
}
}
}

match self.blob_config.as_ref() {
None => false,
Some(cfg) => cfg.cache.validate() && cfg.backend.validate(),
}
}
}

impl BlobCacheEntry {
/// Read configuration information from a file.
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
let md = fs::metadata(path.as_ref())?;
if md.len() > 0x100000 {
return Err(eother!("configuration file size is too big"));
}
let content = fs::read_to_string(path)?;
Self::from_str(&content)
}

/// Validate the configuration object.
pub fn validate(&self) -> bool {
if self.blob_type != BLOB_CACHE_TYPE_META_BLOB
&& self.blob_type != BLOB_CACHE_TYPE_DATA_BLOB
{
warn!("invalid blob type {} for blob cache entry", self.blob_type);
return false;
}
if let Some(config) = self.blob_config.as_ref() {
if !config.validate() {
return false;
}
}
true
}
}

impl FromStr for BlobCacheEntry {
type Err = Error;

fn from_str(s: &str) -> Result<BlobCacheEntry> {
if let Ok(v) = serde_json::from_str::<BlobCacheEntry>(s) {
return if v.validate() {
Ok(v)
} else {
Err(einval!("invalid configuration"))
};
}
if let Ok(v) = toml::from_str::<BlobCacheEntry>(s) {
return if v.validate() {
Ok(v)
} else {
Err(einval!("invalid configuration"))
};
}
Err(einval!("failed to parse configuration information"))
}
}

/// Configuration information for a list of cached blob objects.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct BlobCacheList {
/// List of blob configuration information.
pub blobs: Vec<BlobCacheEntry>,
}

fn default_true() -> bool {
true
}
Expand Down
53 changes: 1 addition & 52 deletions api/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
//
// SPDX-License-Identifier: Apache-2.0

use std::convert::TryInto;
use std::io;
use std::sync::mpsc::{RecvError, SendError};

use nydus_error::error::MetricsError;
use serde::Deserialize;
use serde_json::Error as SerdeError;

use crate::{BlobCacheEntryConfig, BlobCacheEntryConfigV2};
use crate::BlobCacheEntry;

/// Mount a filesystem.
#[derive(Clone, Deserialize, Debug)]
Expand Down Expand Up @@ -43,56 +42,6 @@ pub struct DaemonConf {
pub log_level: String,
}

/// Blob cache object type for nydus/rafs bootstrap blob.
pub const BLOB_CACHE_TYPE_META_BLOB: &str = "bootstrap";
/// Blob cache object type for nydus/rafs data blob.
pub const BLOB_CACHE_TYPE_DATA_BLOB: &str = "datablob";

/// Configuration information for a cached blob.
#[derive(Debug, Deserialize, Serialize)]
pub struct BlobCacheEntry {
/// Type of blob object, bootstrap or data blob.
#[serde(rename = "type")]
pub blob_type: String,
/// Blob id.
#[serde(rename = "id")]
pub blob_id: String,
/// Configuration information to generate blob cache object.
#[serde(default, rename = "config")]
pub(crate) blob_config_legacy: Option<BlobCacheEntryConfig>,
/// Configuration information to generate blob cache object.
#[serde(default, rename = "config_v2")]
pub blob_config: Option<BlobCacheEntryConfigV2>,
/// Domain id for the blob, which is used to group cached blobs into management domains.
#[serde(default)]
pub domain_id: String,
}

impl BlobCacheEntry {
pub fn prepare_configuration_info(&mut self) -> bool {
if self.blob_config.is_none() {
if let Some(legacy) = self.blob_config_legacy.as_ref() {
match legacy.try_into() {
Err(_) => return false,
Ok(v) => self.blob_config = Some(v),
}
}
}

match self.blob_config.as_ref() {
None => false,
Some(cfg) => cfg.cache.validate() && cfg.backend.validate(),
}
}
}

/// Configuration information for a list of cached blob objects.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct BlobCacheList {
/// List of blob configuration information.
pub blobs: Vec<BlobCacheEntry>,
}

/// Identifier for cached blob objects.
///
/// Domains are used to control the blob sharing scope. All blobs associated with the same domain
Expand Down
Loading

0 comments on commit 3ef8489

Please sign in to comment.