Skip to content

Commit f9b051e

Browse files
committed
api: add method to load BlobCacheConfigV2 from file
Add method to load BlobCacheConfigV2 from configuration file. Signed-off-by: Jiang Liu <[email protected]>
1 parent eceeefd commit f9b051e

File tree

6 files changed

+313
-65
lines changed

6 files changed

+313
-65
lines changed

api/src/config.rs

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,11 +890,54 @@ pub struct BlobCacheEntryConfigV2 {
890890
/// Configuration information for local cache system.
891891
#[serde(default)]
892892
pub cache: CacheConfigV2,
893-
/// Optional file path for metadata blobs.
893+
/// Optional file path for metadata blob.
894894
#[serde(default)]
895895
pub metadata_path: Option<String>,
896896
}
897897

898+
impl BlobCacheEntryConfigV2 {
899+
/// Read configuration information from a file.
900+
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
901+
let md = fs::metadata(path.as_ref())?;
902+
if md.len() > 0x100000 {
903+
return Err(eother!("configuration file size is too big"));
904+
}
905+
let content = fs::read_to_string(path)?;
906+
Self::from_str(&content)
907+
}
908+
909+
/// Validate the configuration object.
910+
pub fn validate(&self) -> bool {
911+
if self.version != 2 {
912+
return false;
913+
}
914+
let config: ConfigV2 = self.into();
915+
config.validate()
916+
}
917+
}
918+
919+
impl FromStr for BlobCacheEntryConfigV2 {
920+
type Err = Error;
921+
922+
fn from_str(s: &str) -> Result<BlobCacheEntryConfigV2> {
923+
if let Ok(v) = serde_json::from_str::<BlobCacheEntryConfigV2>(s) {
924+
return if v.validate() {
925+
Ok(v)
926+
} else {
927+
Err(einval!("invalid configuration"))
928+
};
929+
}
930+
if let Ok(v) = toml::from_str::<BlobCacheEntryConfigV2>(s) {
931+
return if v.validate() {
932+
Ok(v)
933+
} else {
934+
Err(einval!("invalid configuration"))
935+
};
936+
}
937+
Err(einval!("failed to parse configuration information"))
938+
}
939+
}
940+
898941
impl From<&BlobCacheEntryConfigV2> for ConfigV2 {
899942
fn from(c: &BlobCacheEntryConfigV2) -> Self {
900943
ConfigV2 {
@@ -943,6 +986,106 @@ impl ConfigV2Internal {
943986
}
944987
}
945988

989+
/// Blob cache object type for nydus/rafs bootstrap blob.
990+
pub const BLOB_CACHE_TYPE_META_BLOB: &str = "bootstrap";
991+
/// Blob cache object type for nydus/rafs data blob.
992+
pub const BLOB_CACHE_TYPE_DATA_BLOB: &str = "datablob";
993+
994+
/// Configuration information for a cached blob.
995+
#[derive(Debug, Deserialize, Serialize)]
996+
pub struct BlobCacheEntry {
997+
/// Type of blob object, bootstrap or data blob.
998+
#[serde(rename = "type")]
999+
pub blob_type: String,
1000+
/// Blob id.
1001+
#[serde(rename = "id")]
1002+
pub blob_id: String,
1003+
/// Configuration information to generate blob cache object.
1004+
#[serde(default, rename = "config")]
1005+
pub(crate) blob_config_legacy: Option<BlobCacheEntryConfig>,
1006+
/// Configuration information to generate blob cache object.
1007+
#[serde(default, rename = "config_v2")]
1008+
pub blob_config: Option<BlobCacheEntryConfigV2>,
1009+
/// Domain id for the blob, which is used to group cached blobs into management domains.
1010+
#[serde(default)]
1011+
pub domain_id: String,
1012+
}
1013+
1014+
impl BlobCacheEntry {
1015+
pub fn prepare_configuration_info(&mut self) -> bool {
1016+
if self.blob_config.is_none() {
1017+
if let Some(legacy) = self.blob_config_legacy.as_ref() {
1018+
match legacy.try_into() {
1019+
Err(_) => return false,
1020+
Ok(v) => self.blob_config = Some(v),
1021+
}
1022+
}
1023+
}
1024+
1025+
match self.blob_config.as_ref() {
1026+
None => false,
1027+
Some(cfg) => cfg.cache.validate() && cfg.backend.validate(),
1028+
}
1029+
}
1030+
}
1031+
1032+
impl BlobCacheEntry {
1033+
/// Read configuration information from a file.
1034+
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
1035+
let md = fs::metadata(path.as_ref())?;
1036+
if md.len() > 0x100000 {
1037+
return Err(eother!("configuration file size is too big"));
1038+
}
1039+
let content = fs::read_to_string(path)?;
1040+
Self::from_str(&content)
1041+
}
1042+
1043+
/// Validate the configuration object.
1044+
pub fn validate(&self) -> bool {
1045+
if self.blob_type != BLOB_CACHE_TYPE_META_BLOB
1046+
&& self.blob_type != BLOB_CACHE_TYPE_DATA_BLOB
1047+
{
1048+
warn!("invalid blob type {} for blob cache entry", self.blob_type);
1049+
return false;
1050+
}
1051+
if let Some(config) = self.blob_config.as_ref() {
1052+
if !config.validate() {
1053+
return false;
1054+
}
1055+
}
1056+
true
1057+
}
1058+
}
1059+
1060+
impl FromStr for BlobCacheEntry {
1061+
type Err = Error;
1062+
1063+
fn from_str(s: &str) -> Result<BlobCacheEntry> {
1064+
if let Ok(v) = serde_json::from_str::<BlobCacheEntry>(s) {
1065+
return if v.validate() {
1066+
Ok(v)
1067+
} else {
1068+
Err(einval!("invalid configuration"))
1069+
};
1070+
}
1071+
if let Ok(v) = toml::from_str::<BlobCacheEntry>(s) {
1072+
return if v.validate() {
1073+
Ok(v)
1074+
} else {
1075+
Err(einval!("invalid configuration"))
1076+
};
1077+
}
1078+
Err(einval!("failed to parse configuration information"))
1079+
}
1080+
}
1081+
1082+
/// Configuration information for a list of cached blob objects.
1083+
#[derive(Debug, Default, Deserialize, Serialize)]
1084+
pub struct BlobCacheList {
1085+
/// List of blob configuration information.
1086+
pub blobs: Vec<BlobCacheEntry>,
1087+
}
1088+
9461089
fn default_true() -> bool {
9471090
true
9481091
}

api/src/http.rs

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
//
55
// SPDX-License-Identifier: Apache-2.0
66

7-
use std::convert::TryInto;
87
use std::io;
98
use std::sync::mpsc::{RecvError, SendError};
109

1110
use nydus_error::error::MetricsError;
1211
use serde::Deserialize;
1312
use serde_json::Error as SerdeError;
1413

15-
use crate::{BlobCacheEntryConfig, BlobCacheEntryConfigV2};
14+
use crate::BlobCacheEntry;
1615

1716
/// Mount a filesystem.
1817
#[derive(Clone, Deserialize, Debug)]
@@ -43,56 +42,6 @@ pub struct DaemonConf {
4342
pub log_level: String,
4443
}
4544

46-
/// Blob cache object type for nydus/rafs bootstrap blob.
47-
pub const BLOB_CACHE_TYPE_META_BLOB: &str = "bootstrap";
48-
/// Blob cache object type for nydus/rafs data blob.
49-
pub const BLOB_CACHE_TYPE_DATA_BLOB: &str = "datablob";
50-
51-
/// Configuration information for a cached blob.
52-
#[derive(Debug, Deserialize, Serialize)]
53-
pub struct BlobCacheEntry {
54-
/// Type of blob object, bootstrap or data blob.
55-
#[serde(rename = "type")]
56-
pub blob_type: String,
57-
/// Blob id.
58-
#[serde(rename = "id")]
59-
pub blob_id: String,
60-
/// Configuration information to generate blob cache object.
61-
#[serde(default, rename = "config")]
62-
pub(crate) blob_config_legacy: Option<BlobCacheEntryConfig>,
63-
/// Configuration information to generate blob cache object.
64-
#[serde(default, rename = "config_v2")]
65-
pub blob_config: Option<BlobCacheEntryConfigV2>,
66-
/// Domain id for the blob, which is used to group cached blobs into management domains.
67-
#[serde(default)]
68-
pub domain_id: String,
69-
}
70-
71-
impl BlobCacheEntry {
72-
pub fn prepare_configuration_info(&mut self) -> bool {
73-
if self.blob_config.is_none() {
74-
if let Some(legacy) = self.blob_config_legacy.as_ref() {
75-
match legacy.try_into() {
76-
Err(_) => return false,
77-
Ok(v) => self.blob_config = Some(v),
78-
}
79-
}
80-
}
81-
82-
match self.blob_config.as_ref() {
83-
None => false,
84-
Some(cfg) => cfg.cache.validate() && cfg.backend.validate(),
85-
}
86-
}
87-
}
88-
89-
/// Configuration information for a list of cached blob objects.
90-
#[derive(Debug, Default, Deserialize, Serialize)]
91-
pub struct BlobCacheList {
92-
/// List of blob configuration information.
93-
pub blobs: Vec<BlobCacheEntry>,
94-
}
95-
9645
/// Identifier for cached blob objects.
9746
///
9847
/// Domains are used to control the blob sharing scope. All blobs associated with the same domain

docs/samples/blob_cache_entry.toml

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# Configuration file for Nydus Image Service
2+
3+
type = "bootstrap"
4+
id = "image1"
5+
domain_id = "domain1"
6+
7+
# Configuration file format version number, must be 2.
8+
[config_v2]
9+
version = 2
10+
# Identifier for the instance.
11+
id = "my_id"
12+
# Optional file path for metadata blobs, for BlobCacheEntry only.
13+
metadata_path = "/path/to/rafs/meta/data/blob"
14+
15+
[config_v2.backend]
16+
# Type of storage backend, valid values: "localfs", "oss", "registry"
17+
type = "localfs"
18+
19+
[config_v2.backend.localfs]
20+
blob_file = "/tmp/nydus.blob.data"
21+
dir = "/tmp"
22+
alt_dirs = ["/var/nydus/cache"]
23+
24+
[config_v2.backend.oss]
25+
# Oss http scheme, either 'http' or 'https'
26+
scheme = "http"
27+
# Oss endpoint
28+
endpoint = "my_endpoint"
29+
# Oss bucket name
30+
bucket_name = "my_bucket_name"
31+
# Prefix object_prefix to OSS object key, for example the simulation of subdirectory:
32+
object_prefix = "my_object_prefix"
33+
# Oss access key
34+
access_key_id = "my_access_key_id"
35+
# Oss secret
36+
access_key_secret = "my_access_key_secret"
37+
# Skip SSL certificate validation for HTTPS scheme.
38+
skip_verify = true
39+
# Drop the read request once http request timeout, in seconds.
40+
timeout = 10
41+
# Drop the read request once http connection timeout, in seconds.
42+
connect_timeout = 10
43+
# Retry count when read request failed.
44+
retry_limit = 5
45+
46+
[config_v2.backend.oss.proxy]
47+
# Access remote storage backend via proxy, e.g. Dragonfly dfdaemon server URL.
48+
url = "localhost:6789"
49+
# Proxy health checking endpoint.
50+
ping_url = "localhost:6789/ping"
51+
# Fallback to remote storage backend if proxy ping failed.
52+
fallback = true
53+
# Interval for proxy health checking, in seconds.
54+
check_interval = 5
55+
# Replace URL to http to request source registry with proxy, and allow fallback to https if the proxy is unhealthy.
56+
use_http = false
57+
58+
[[config_v2.backend.oss.mirrors]]
59+
# Mirror server URL, for example http://127.0.0.1:65001.
60+
host = "http://127.0.0.1:65001"
61+
# Ping URL to check mirror server health.
62+
ping_url = "http://127.0.0.1:65001/ping"
63+
# HTTP request headers to be passed to mirror server.
64+
# headers =
65+
# Whether the authorization process is through mirror, default to false.
66+
auth_through = true
67+
# Interval for mirror health checking, in seconds.
68+
health_check_interval = 5
69+
# Maximum number of failures before marking a mirror as unusable.
70+
failure_limit = 5
71+
72+
[config_v2.backend.registry]
73+
# Registry http scheme, either 'http' or 'https'
74+
scheme = "https"
75+
# Registry url host
76+
host = "my.registry.com"
77+
# Registry image name, like 'library/ubuntu'
78+
repo = "nydus"
79+
# Base64_encoded(username:password), the field should be sent to registry auth server to get a bearer token.
80+
auth = "base64_encoded"
81+
# Skip SSL certificate validation for HTTPS scheme.
82+
skip_verify = true
83+
# Drop the read request once http request timeout, in seconds.
84+
timeout = 10
85+
# Drop the read request once http connection timeout, in seconds.
86+
connect_timeout = 10
87+
# Retry count when read request failed.
88+
retry_limit = 5
89+
# The field is a bearer token to be sent to registry to authorize registry requests.
90+
registry_token = "bear_token"
91+
# The http scheme to access blobs.
92+
# It is used to workaround some P2P subsystem that requires a different scheme than the registry.
93+
blob_url_scheme = "https"
94+
# Redirect blob access to a different host regardless of the one specified in 'host'.
95+
blob_redirected_host = "redirect.registry.com"
96+
97+
[config_v2.backend.registry.proxy]
98+
# Access remote storage backend via proxy, e.g. Dragonfly dfdaemon server URL.
99+
url = "localhost:6789"
100+
# Proxy health checking endpoint.
101+
ping_url = "localhost:6789/ping"
102+
# Fallback to remote storage backend if proxy ping failed.
103+
fallback = true
104+
# Interval for proxy health checking, in seconds.
105+
check_interval = 5
106+
# Replace URL to http to request source registry with proxy, and allow fallback to https if the proxy is unhealthy.
107+
use_http = false
108+
109+
[[config_v2.backend.registry.mirrors]]
110+
# Mirror server URL, for example http://127.0.0.1:65001.
111+
host = "http://127.0.0.1:65001"
112+
# Ping URL to check mirror server health.
113+
ping_url = "http://127.0.0.1:65001/ping"
114+
# HTTP request headers to be passed to mirror server.
115+
# headers =
116+
# Whether the authorization process is through mirror, default to false.
117+
auth_through = true
118+
# Interval for mirror health checking, in seconds.
119+
health_check_interval = 5
120+
# Maximum number of failures before marking a mirror as unusable.
121+
failure_limit = 5
122+
123+
[config_v2.cache]
124+
# Type of blob cache: "blobcache", "filecache", "fscache", "dummycache" or ""
125+
type = "filecache"
126+
# Whether to cache compressed or uncompressed data.
127+
compressed = true
128+
# Whether to validate data read from the cache.
129+
validate = true
130+
131+
[config_v2.cache.filecache]
132+
work_dir = "."
133+
134+
[config_v2.cache.fscache]
135+
work_dir = "."
136+
137+
[config_v2.cache.prefetch]
138+
# Whether to enable blob data prefetching.
139+
enable = true
140+
# Number of data prefetching working threads, valid values: 1-1024.
141+
threads = 8
142+
# The batch size to prefetch data from backend, valid values: 0-0x10000000.
143+
batch_size = 1000000
144+
# Network bandwidth rate limit in unit of Bytes and Zero means no limit.
145+
bandwidth_limit = 10000000

service/src/blob_cache.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,12 @@ impl BlobCacheMgr {
328328
"blob_cache: `config.metadata_path` for meta blob is empty"
329329
));
330330
}
331-
let path = Path::new(&path)
332-
.canonicalize()
333-
.map_err(|_e| einval!("blob_cache: `config.metadata_path` for meta blob is invalid"))?;
331+
let path = Path::new(&path).canonicalize().map_err(|_e| {
332+
einval!(format!(
333+
"blob_cache: `config.metadata_path={}` for meta blob is invalid",
334+
path
335+
))
336+
})?;
334337
if !path.is_file() {
335338
return Err(einval!(
336339
"blob_cache: `config.metadata_path` for meta blob is not a file"

0 commit comments

Comments
 (0)