Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TK-05573] switch to yaml for conductor config #436

Merged
merged 10 commits into from
Oct 27, 2020
34 changes: 34 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/holochain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ predicates = "1.0.4"
rand = "0.7"
serde = { version = "1.0.104", features = [ "derive" ] }
serde_json = { version = "1.0.51", features = [ "preserve_order" ] }
serde_yaml = "0.8"
shrinkwraprs = "0.3.0"
structopt = "0.3.11"
strum = "0.18.0"
Expand Down
17 changes: 10 additions & 7 deletions crates/holochain/src/bin/holochain/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct Opt {
#[structopt(
short = "c",
long,
help = "Path to a TOML file containing conductor configuration"
help = "Path to a YAML file containing conductor configuration"
)]
config_path: Option<PathBuf>,

Expand Down Expand Up @@ -152,12 +152,12 @@ async fn conductor_handle_from_config_path(

/// Load config, throw friendly error on failure
fn load_config(config_path: &ConfigFilePath, config_path_default: bool) -> ConductorConfig {
match ConductorConfig::load_toml(config_path.as_ref()) {
match ConductorConfig::load_yaml(config_path.as_ref()) {
Err(ConductorError::ConfigMissing(_)) => {
display_friendly_missing_config_message(config_path, config_path_default);
std::process::exit(ERROR_CODE);
}
Err(ConductorError::DeserializationError(err)) => {
Err(ConductorError::SerializationError(err)) => {
display_friendly_malformed_config_message(config_path, err);
std::process::exit(ERROR_CODE);
}
Expand All @@ -177,7 +177,7 @@ Error: The conductor is set up to load its configuration from the default path:
{path}

but this file doesn't exist. If you meant to specify a path, run this command
again with the -c option. Otherwise, please either create a TOML config file at
again with the -c option. Otherwise, please either create a YAML config file at
this path yourself, or rerun the command with the '-i' flag, which will help you
automatically create a default config file.
",
Expand All @@ -190,7 +190,7 @@ Error: You asked to load configuration from the path:

{path}

but this file doesn't exist. Please either create a TOML config file at this
but this file doesn't exist. Please either create a YAML config file at this
path yourself, or rerun the command with the '-i' flag, which will help you
automatically create a default config file.
",
Expand All @@ -199,11 +199,14 @@ automatically create a default config file.
}
}

fn display_friendly_malformed_config_message(config_path: &ConfigFilePath, error: toml::de::Error) {
fn display_friendly_malformed_config_message(
config_path: &ConfigFilePath,
error: serde_yaml::Error,
) {
println!(
"
The specified config file ({})
could not be parsed, because it is not valid TOML. Please check and fix the
could not be parsed, because it is not valid YAML. Please check and fix the
file, or delete the file and run the conductor again with the -i flag to create
a valid default configuration. Details:

Expand Down
117 changes: 60 additions & 57 deletions crates/holochain/src/conductor/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![deny(missing_docs)]
//! This module is used to configure the conductor

use serde::{Deserialize, Serialize};
use serde::{de::DeserializeOwned, Deserialize, Serialize};

mod admin_interface_config;
mod dpki_config;
Expand Down Expand Up @@ -84,24 +84,24 @@ pub struct ConductorConfig {
// pub logger: LoggerConfig,
}

/// helper fnction function to load a `Config` from a toml string.
fn config_from_toml<'a, T>(toml: &'a str) -> ConductorResult<T>
/// helper fnction function to load a `Config` from a yaml string.
fn config_from_yaml<T>(yaml: &str) -> ConductorResult<T>
where
T: Deserialize<'a>,
T: DeserializeOwned,
{
toml::from_str::<T>(toml).map_err(ConductorError::DeserializationError)
serde_yaml::from_str(yaml).map_err(ConductorError::SerializationError)
}

impl ConductorConfig {
/// create a ConductorConfig struct from a toml file path
pub fn load_toml(path: &Path) -> ConductorResult<ConductorConfig> {
let config_toml = std::fs::read_to_string(path).map_err(|err| match err {
/// create a ConductorConfig struct from a yaml file path
pub fn load_yaml(path: &Path) -> ConductorResult<ConductorConfig> {
let config_yaml = std::fs::read_to_string(path).map_err(|err| match err {
e @ std::io::Error { .. } if e.kind() == std::io::ErrorKind::NotFound => {
ConductorError::ConfigMissing(path.into())
}
_ => err.into(),
})?;
config_from_toml(&config_toml)
config_from_yaml(&config_yaml)
}
}

Expand All @@ -112,9 +112,9 @@ pub mod tests {
use std::path::{Path, PathBuf};

#[test]
fn test_config_load_toml() {
fn test_config_load_yaml() {
let bad_path = Path::new("fake");
let result = ConductorConfig::load_toml(bad_path);
let result = ConductorConfig::load_yaml(bad_path);
assert_eq!(
"Err(ConfigMissing(\"fake\"))".to_string(),
format!("{:?}", result)
Expand All @@ -124,20 +124,20 @@ pub mod tests {
}

#[test]
fn test_config_bad_toml() {
let result: ConductorResult<ConductorConfig> = config_from_toml("this isn't toml");
assert_matches!(result, Err(ConductorError::DeserializationError(_)));
fn test_config_bad_yaml() {
let result: ConductorResult<ConductorConfig> = config_from_yaml("this isn't yaml");
assert_matches!(result, Err(ConductorError::SerializationError(_)));
}

#[test]
fn test_config_complete_minimal_config() {
let toml = r#"
environment_path = "/path/to/env"
let yaml = r#"---
environment_path: /path/to/env

[passphrase_service]
type = "cmd"
passphrase_service:
type: cmd
"#;
let result: ConductorConfig = config_from_toml(toml).unwrap();
let result: ConductorConfig = config_from_yaml(yaml).unwrap();
assert_eq!(
result,
ConductorConfig {
Expand All @@ -157,32 +157,37 @@ pub mod tests {

#[test]
fn test_config_complete_config() {
let toml = r#"
environment_path = "/path/to/env"
use_dangerous_test_keystore = true

[passphrase_service]
type = "cmd"

encryption_service_uri = "ws://localhost:9001"
decryption_service_uri = "ws://localhost:9002"
signing_service_uri = "ws://localhost:9003"

[dpki]
instance_id = "some_id"
init_params = "some_params"

[[admin_interfaces]]
driver.type = "websocket"
driver.port = 1234

[[network.transport_pool]]
type = 'proxy'
sub_transport = { type = 'quic', bind_to = 'kitsune-quic://0.0.0.0:0' }
proxy_config = { type = 'local_proxy_server', proxy_accept_config = 'reject_all' }
let yaml = r#"---
environment_path: /path/to/env
use_dangerous_test_keystore: true
signing_service_uri: ws://localhost:9001
encryption_service_uri: ws://localhost:9002
decryption_service_uri: ws://localhost:9003

passphrase_service:
type: cmd

dpki:
instance_id: some_id
init_params: some_params

admin_interfaces:
- driver:
type: websocket
port: 1234

network:
transport_pool:
- type: proxy
sub_transport:
type: quic
bind_to: kitsune-quic://0.0.0.0:0
proxy_config:
type: local_proxy_server
proxy_accept_config: reject_all

"#;
let result: ConductorResult<ConductorConfig> = config_from_toml(toml);
let result: ConductorResult<ConductorConfig> = config_from_yaml(yaml);
use holochain_p2p::kitsune_p2p::*;
let mut network_config = KitsuneP2pConfig::default();
network_config.transport_pool.push(TransportConfig::Proxy {
Expand All @@ -200,9 +205,9 @@ pub mod tests {
ConductorConfig {
environment_path: PathBuf::from("/path/to/env").into(),
use_dangerous_test_keystore: true,
signing_service_uri: None,
encryption_service_uri: None,
decryption_service_uri: None,
signing_service_uri: Some("ws://localhost:9001".into()),
encryption_service_uri: Some("ws://localhost:9002".into()),
decryption_service_uri: Some("ws://localhost:9003".into()),
dpki: Some(DpkiConfig {
instance_id: "some_id".into(),
init_params: "some_params".into()
Expand All @@ -219,18 +224,16 @@ pub mod tests {

#[test]
fn test_config_keystore() {
let toml = r#"
environment_path = "/path/to/env"
use_dangerous_test_keystore = true

keystore_path = "/path/to/keystore"

[passphrase_service]
type = "fromconfig"
passphrase = "foobar"

let yaml = r#"---
environment_path: /path/to/env
use_dangerous_test_keystore: true
keystore_path: /path/to/keystore

passphrase_service:
type: fromconfig
passphrase: foobar
"#;
let result: ConductorResult<ConductorConfig> = config_from_toml(toml);
let result: ConductorResult<ConductorConfig> = config_from_yaml(yaml);
assert_eq!(
result.unwrap(),
ConductorConfig {
Expand Down
5 changes: 1 addition & 4 deletions crates/holochain/src/conductor/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,8 @@ pub enum ConductorError {
#[error("Configuration consistency error: {0}")]
ConfigError(String),

#[error("Config serialization error: {0}")]
DeserializationError(#[from] toml::de::Error),

#[error("Config deserialization error: {0}")]
SerializationError(#[from] toml::ser::Error),
SerializationError(#[from] serde_yaml::Error),

#[error("Attempted to call into the conductor while it is shutting down")]
ShuttingDown,
Expand Down
20 changes: 10 additions & 10 deletions crates/holochain/src/conductor/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ pub fn prompt_for_environment_dir(path: &Path) -> std::io::Result<()> {
pub fn load_config_or_prompt_for_default(
config_path: ConfigFilePath,
) -> ConductorResult<Option<ConductorConfig>> {
ConductorConfig::load_toml(config_path.as_ref()).map(Some).or_else(|err| {
ConductorConfig::load_yaml(config_path.as_ref()).map(Some).or_else(|err| {
if let ConductorError::ConfigMissing(_) = err {
let prompt = format!(
"There is no conductor config TOML file at the path specified ({})\nWould you like to create a default config file at this location?",
"There is no conductor config YAML file at the path specified ({})\nWould you like to create a default config file at this location?",
config_path
);
if ask_yn(prompt, Some(true))? {
let config = save_default_config_toml(config_path.as_ref())?;
let config = save_default_config_yaml(config_path.as_ref())?;
println!("Conductor config written.");
Ok(Some(config))
} else {
Expand All @@ -83,30 +83,30 @@ pub fn load_config_or_prompt_for_default(
}

/// Save the default [ConductorConfig] to `path`
fn save_default_config_toml(path: &Path) -> ConductorResult<ConductorConfig> {
fn save_default_config_yaml(path: &Path) -> ConductorResult<ConductorConfig> {
let dir = path.parent().ok_or_else(|| {
ConductorError::ConfigError(format!("Bad path for conductor config: {}", path.display()))
})?;
std::fs::create_dir_all(dir)?;
let default = ConductorConfig::default();
let content_toml = toml::to_string(&default)?;
std::fs::write(path, content_toml)?;
let content_yaml = serde_yaml::to_string(&default)?;
std::fs::write(path, content_yaml)?;
Ok(default)
}

#[cfg(test)]
mod tests {

use super::save_default_config_toml;
use super::save_default_config_yaml;
use crate::conductor::config::ConductorConfig;
use tempdir::TempDir;

#[test]
fn test_save_default_config() {
let tmp = TempDir::new("test").unwrap();
let config_path = tmp.path().join("config.toml");
save_default_config_toml(&config_path).unwrap();
let config = ConductorConfig::load_toml(config_path.as_ref()).unwrap();
let config_path = tmp.path().join("config.yaml");
save_default_config_yaml(&config_path).unwrap();
let config = ConductorConfig::load_yaml(config_path.as_ref()).unwrap();
assert_eq!(config, ConductorConfig::default());
}
}
2 changes: 1 addition & 1 deletion crates/holochain/src/conductor/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const ORGANIZATION: &str = "holochain";
const APPLICATION: &str = "holochain";
const KEYS_DIRECTORY: &str = "keys";
const DATABASES_DIRECTORY: &str = "databases";
const CONFIG_FILENAME: &str = "conductor-config.toml";
const CONFIG_FILENAME: &str = "conductor-config.yml";

/// Returns the project root builder for holochain directories.
fn project_root() -> Option<directories::ProjectDirs> {
Expand Down