support docker runtime in dfinit with ut (#868)

Signed-off-by: cormick <cormick1080@gmail.com>
This commit is contained in:
KennyMcCormick 2024-11-26 20:33:40 +08:00 committed by GitHub
parent 62c62f7ec6
commit c93e01b005
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 206 additions and 5 deletions

1
Cargo.lock generated
View File

@ -1016,6 +1016,7 @@ dependencies = [
"dragonfly-client",
"dragonfly-client-config",
"dragonfly-client-core",
"serde_json",
"tempfile",
"tokio",
"toml",

View File

@ -91,6 +91,7 @@ bytesize-serde = "0.2.1"
percent-encoding = "2.3.1"
tempfile = "3.14.0"
tokio-rustls = "0.25.0-alpha.4"
serde_json = "1.0.132"
[profile.release]
opt-level = "z"

View File

@ -26,3 +26,4 @@ toml_edit.workspace = true
toml.workspace = true
url.workspace = true
tempfile.workspace = true
serde_json.workspace = true

View File

@ -15,8 +15,14 @@
*/
use dragonfly_client_config::dfinit;
use dragonfly_client_core::{Error, Result};
use dragonfly_client_core::{
error::{ErrorType, OrErr},
Error, Result,
};
use serde_json::{json, Value};
use tokio::{self, fs};
use tracing::{info, instrument};
use url::Url;
/// Docker represents the docker runtime manager.
#[derive(Debug, Clone)]
@ -40,8 +46,6 @@ impl Docker {
}
}
/// TODO: Implement the run method for Docker.
///
/// run runs the docker runtime to initialize
/// runtime environment for the dfdaemon.
#[instrument(skip_all)]
@ -50,6 +54,200 @@ impl Docker {
"docker feature is enabled, proxy_addr: {}, config_path: {:?}",
self.proxy_config.addr, self.config.config_path,
);
Err(Error::Unimplemented)
// Parse proxy address to get host and port.
let proxy_url = Url::parse(&self.proxy_config.addr).or_err(ErrorType::ParseError)?;
let proxy_host = proxy_url
.host_str()
.ok_or(Error::Unknown("host not found".to_string()))?;
let proxy_port = proxy_url
.port_or_known_default()
.ok_or(Error::Unknown("port not found".to_string()))?;
let proxy_location = format!("{}:{}", proxy_host, proxy_port);
// Prepare proxies configuration.
let mut proxies_map = serde_json::Map::new();
proxies_map.insert(
"http-proxy".to_string(),
json!(format!("http://{}", proxy_location)),
);
proxies_map.insert(
"https-proxy".to_string(),
json!(format!("http://{}", proxy_location)),
);
let config_path = &self.config.config_path;
let mut docker_config: serde_json::Map<String, Value> = if config_path.exists() {
let contents = fs::read_to_string(config_path).await?;
if contents.trim().is_empty() {
serde_json::Map::new()
} else {
serde_json::from_str(&contents).or_err(ErrorType::ParseError)?
}
} else {
serde_json::Map::new()
};
// Insert or update proxies configuration.
docker_config.insert("proxies".to_string(), Value::Object(proxies_map));
// Create config directory if it doesn't exist.
let config_dir = config_path
.parent()
.ok_or(Error::Unknown("invalid config path".to_string()))?;
fs::create_dir_all(config_dir).await?;
// Write configuration to file.
fs::write(
config_path,
serde_json::to_string_pretty(&Value::Object(docker_config))
.or_err(ErrorType::SerializeError)?,
)
.await?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::NamedTempFile;
use tokio::fs;
#[tokio::test]
async fn test_docker_config_empty() {
let docker_config_file = NamedTempFile::new().unwrap();
let docker = Docker::new(
dfinit::Docker {
config_path: docker_config_file.path().to_path_buf(),
},
dfinit::Proxy {
addr: "http://127.0.0.1:5000".into(),
},
);
let result = docker.run().await;
println!("{:?}", result);
assert!(result.is_ok());
// Read and verify configuration.
let contents = fs::read_to_string(docker_config_file.path()).await.unwrap();
let config: serde_json::Value = serde_json::from_str(&contents).unwrap();
// Verify proxies configuration.
assert_eq!(config["proxies"]["http-proxy"], "http://127.0.0.1:5000");
assert_eq!(config["proxies"]["https-proxy"], "http://127.0.0.1:5000");
}
#[tokio::test]
async fn test_docker_config_existing() {
let docker_config_file = NamedTempFile::new().unwrap();
let initial_config = r#"
{
"log-driver": "json-file",
"experimental": true
}
"#;
fs::write(docker_config_file.path(), initial_config)
.await
.unwrap();
let docker = Docker::new(
dfinit::Docker {
config_path: docker_config_file.path().to_path_buf(),
},
dfinit::Proxy {
addr: "http://127.0.0.1:5000".into(),
},
);
let result = docker.run().await;
assert!(result.is_ok());
// Read and verify configuration.
let contents = fs::read_to_string(docker_config_file.path()).await.unwrap();
let config: serde_json::Value = serde_json::from_str(&contents).unwrap();
// Verify existing configurations.
assert_eq!(config["log-driver"], "json-file");
assert_eq!(config["experimental"], true);
// Verify proxies configuration.
assert_eq!(config["proxies"]["http-proxy"], "http://127.0.0.1:5000");
assert_eq!(config["proxies"]["https-proxy"], "http://127.0.0.1:5000");
}
#[tokio::test]
async fn test_docker_config_invalid_json() {
let docker_config_file = NamedTempFile::new().unwrap();
let invalid_config = r#"
{
"log-driver": "json-file",
"experimental": true,
}
"#;
fs::write(docker_config_file.path(), invalid_config)
.await
.unwrap();
let docker = Docker::new(
dfinit::Docker {
config_path: docker_config_file.path().to_path_buf(),
},
dfinit::Proxy {
addr: "http://127.0.0.1:5000".into(),
},
);
let result = docker.run().await;
assert!(result.is_err());
if let Err(e) = result {
assert_eq!(
format!("{}", e),
"ParseError cause: trailing comma at line 5 column 9"
);
}
}
#[tokio::test]
async fn test_docker_config_proxies_existing() {
let docker_config_file = NamedTempFile::new().unwrap();
let existing_proxies = r#"
{
"proxies": {
"http-proxy": "http://old-proxy:3128",
"https-proxy": "https://old-proxy:3129",
"no-proxy": "old-no-proxy"
},
"log-driver": "json-file"
}
"#;
fs::write(docker_config_file.path(), existing_proxies)
.await
.unwrap();
let docker = Docker::new(
dfinit::Docker {
config_path: docker_config_file.path().to_path_buf(),
},
dfinit::Proxy {
addr: "http://127.0.0.1:5000".into(),
},
);
let result = docker.run().await;
assert!(result.is_ok());
// Read and verify configuration.
let contents = fs::read_to_string(docker_config_file.path()).await.unwrap();
let config: serde_json::Value = serde_json::from_str(&contents).unwrap();
// Verify existing configurations.
assert_eq!(config["log-driver"], "json-file");
// Verify proxies configuration.
assert_eq!(config["proxies"]["http-proxy"], "http://127.0.0.1:5000");
assert_eq!(config["proxies"]["https-proxy"], "http://127.0.0.1:5000");
}
}

View File

@ -62,8 +62,8 @@ bytesize.workspace = true
uuid.workspace = true
percent-encoding.workspace = true
tokio-rustls.workspace = true
serde_json.workspace = true
lazy_static = "1.5"
serde_json = "1.0"
tracing-log = "0.2"
tracing-subscriber = { version = "0.3", features = ["env-filter", "time", "chrono"] }
tracing-appender = "0.2.3"