use crate::run::parser::identities::Identities;
use crate::run::parser::nodes::Nodes;
use crate::run::parser::policies::Policies;
use crate::run::parser::projects::Projects;
use crate::run::parser::relays::Relays;
use crate::run::parser::tcp_inlets::TcpInlets;
use crate::run::parser::tcp_outlets::TcpOutlets;
use crate::run::parser::variables::Variables;
use crate::run::parser::vaults::Vaults;
use crate::run::parser::version::Version;
use miette::IntoDiagnostic;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Config {
#[serde(flatten)]
pub version: Version,
#[serde(flatten)]
pub vaults: Vaults,
#[serde(flatten)]
pub identities: Identities,
#[serde(flatten)]
pub projects: Projects,
#[serde(flatten)]
pub nodes: Nodes,
#[serde(flatten)]
pub policies: Policies,
#[serde(flatten)]
pub tcp_outlets: TcpOutlets,
#[serde(flatten)]
pub tcp_inlets: TcpInlets,
#[serde(flatten)]
pub relays: Relays,
}
impl Config {
pub fn parse(contents: &str) -> miette::Result<Self> {
let resolved = Variables::resolve(contents)?;
serde_yaml::from_str(&resolved).into_diagnostic()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::run::parser::resources::*;
use crate::run::parser::version::VersionValue;
use std::collections::BTreeMap;
#[test]
fn can_parse_base_config() {
let config = r#"
vaults:
- v1
- v2
identities:
- i1
- i2:
vault: v2
ticket: ./path/to/ticket
nodes:
- n1
- n2
policies:
- at: n1
resource: r1
expression: (= subject.component "c1")
- at: n2
resource: r2
expression: (= subject.component "c2")
tcp-outlets:
to1:
to: 6060
at: n
to2:
to: 6061
tcp-inlets:
ti1:
from: 6060
at: n
ti2:
from: 6061
relays:
- r1
- r2
"#;
let parsed = Config::parse(config).unwrap();
let expected = Config {
version: Version {
version: VersionValue::latest(),
},
vaults: Vaults {
vaults: Some(ResourcesContainer::List(vec![
ResourceNameOrMap::Name("v1".to_string()),
ResourceNameOrMap::Name("v2".to_string()),
])),
},
identities: Identities {
identities: Some(ResourcesContainer::List(vec![
ResourceNameOrMap::Name("i1".to_string()),
ResourceNameOrMap::NamedMap(NamedResources {
items: vec![(
"i2".to_string(),
Args {
args: vec![("vault".to_string(), "v2".into())]
.into_iter()
.collect(),
},
)]
.into_iter()
.collect::<BTreeMap<_, _>>(),
}),
])),
},
projects: Projects {
ticket: Some("./path/to/ticket".to_string()),
},
nodes: Nodes {
nodes: Some(ResourcesContainer::List(vec![
ResourceNameOrMap::Name("n1".to_string()),
ResourceNameOrMap::Name("n2".to_string()),
])),
},
policies: Policies {
policies: Some(UnnamedResources::List(vec![
Args {
args: vec![
("at".to_string(), "n1".into()),
("resource".to_string(), "r1".into()),
(
"expression".to_string(),
"(= subject.component \"c1\")".into(),
),
]
.into_iter()
.collect(),
},
Args {
args: vec![
("at".to_string(), "n2".into()),
("resource".to_string(), "r2".into()),
(
"expression".to_string(),
"(= subject.component \"c2\")".into(),
),
]
.into_iter()
.collect(),
},
])),
},
tcp_outlets: TcpOutlets {
tcp_outlets: Some(ResourceNameOrMap::NamedMap(NamedResources {
items: vec![
(
"to1".to_string(),
Args {
args: vec![
("to".to_string(), "6060".into()),
("at".to_string(), "n".into()),
]
.into_iter()
.collect(),
},
),
(
"to2".to_string(),
Args {
args: vec![("to".to_string(), "6061".into())]
.into_iter()
.collect(),
},
),
]
.into_iter()
.collect::<BTreeMap<_, _>>(),
})),
},
tcp_inlets: TcpInlets {
tcp_inlets: Some(ResourceNameOrMap::NamedMap(NamedResources {
items: vec![
(
"ti1".to_string(),
Args {
args: vec![
("from".to_string(), "6060".into()),
("at".to_string(), "n".into()),
]
.into_iter()
.collect(),
},
),
(
"ti2".to_string(),
Args {
args: vec![("from".to_string(), "6061".into())]
.into_iter()
.collect(),
},
),
]
.into_iter()
.collect::<BTreeMap<_, _>>(),
})),
},
relays: Relays {
relays: Some(ResourcesContainer::List(vec![
ResourceNameOrMap::Name("r1".to_string()),
ResourceNameOrMap::Name("r2".to_string()),
])),
},
};
assert_eq!(expected, parsed);
}
#[test]
fn resolve_variables() {
std::env::set_var("SUFFIX", "node");
let config = r#"
variables:
prefix: ockam
ticket_path: ./path/to/ticket
ticket: ${ticket_path}
nodes:
- ${prefix}_n1_${SUFFIX}
- ${prefix}_n2_${SUFFIX}
"#;
let parsed = Config::parse(config).unwrap();
let expected = Config {
version: Version {
version: VersionValue::latest(),
},
vaults: Vaults { vaults: None },
identities: Identities { identities: None },
projects: Projects {
ticket: Some("./path/to/ticket".to_string()),
},
nodes: Nodes {
nodes: Some(ResourcesContainer::List(vec![
ResourceNameOrMap::Name("ockam_n1_node".to_string()),
ResourceNameOrMap::Name("ockam_n2_node".to_string()),
])),
},
policies: Policies { policies: None },
tcp_outlets: TcpOutlets { tcp_outlets: None },
tcp_inlets: TcpInlets { tcp_inlets: None },
relays: Relays { relays: None },
};
assert_eq!(expected, parsed);
}
}