diff --git a/demo/spec/xyz/ex-core-r/xyz1-ex-core-r101.yaml b/demo/spec/xyz/ex-core-r/xyz1-ex-core-r101.yaml index 628c83c..19ab138 100644 --- a/demo/spec/xyz/ex-core-r/xyz1-ex-core-r101.yaml +++ b/demo/spec/xyz/ex-core-r/xyz1-ex-core-r101.yaml @@ -1,2 +1,2 @@ device: - hostname: xyz1-ex-edge-r201 + hostname: xyz1-ex-core-r101 diff --git a/demo/spec/xyz/ex-core-r/xyz1-ex-core-r102.yaml b/demo/spec/xyz/ex-core-r/xyz1-ex-core-r102.yaml index 247be03..2418059 100644 --- a/demo/spec/xyz/ex-core-r/xyz1-ex-core-r102.yaml +++ b/demo/spec/xyz/ex-core-r/xyz1-ex-core-r102.yaml @@ -1,2 +1,2 @@ device: - hostname: xyz1-ex-edge-r202 + hostname: xyz1-ex-core-r102 diff --git a/demo/spec/xyz/ex-core-r/xyz2-ex-core-r101.yaml b/demo/spec/xyz/ex-core-r/xyz2-ex-core-r101.yaml index 67217b6..46d492c 100644 --- a/demo/spec/xyz/ex-core-r/xyz2-ex-core-r101.yaml +++ b/demo/spec/xyz/ex-core-r/xyz2-ex-core-r101.yaml @@ -1,2 +1,2 @@ device: - hostname: xyz2-ex-edge-r201 + hostname: xyz2-ex-core-r101 diff --git a/demo/spec/xyz/ex-core-r/xyz2-ex-core-r102.yaml b/demo/spec/xyz/ex-core-r/xyz2-ex-core-r102.yaml index 43123bb..63858d2 100644 --- a/demo/spec/xyz/ex-core-r/xyz2-ex-core-r102.yaml +++ b/demo/spec/xyz/ex-core-r/xyz2-ex-core-r102.yaml @@ -1,2 +1,2 @@ device: - hostname: xyz2-ex-edge-r202 + hostname: xyz2-ex-core-r202 diff --git a/demo/spec/xyz/ex-edge-r/xyz1-ex-edge-r101.yaml b/demo/spec/xyz/ex-edge-r/xyz1-ex-edge-r101.yaml index cb67c3a..2cb94ee 100644 --- a/demo/spec/xyz/ex-edge-r/xyz1-ex-edge-r101.yaml +++ b/demo/spec/xyz/ex-edge-r/xyz1-ex-edge-r101.yaml @@ -1,2 +1,3 @@ device: hostname: xyz1-ex-edge-r101 + live: true diff --git a/demo/tmpl/ex-edge-r/policy-options.tera b/demo/tmpl/ex-edge-r/policy-options.tera new file mode 100644 index 0000000..7267934 --- /dev/null +++ b/demo/tmpl/ex-edge-r/policy-options.tera @@ -0,0 +1,29 @@ +policy-options { + policy-statement EXPORT-POLICY { + term ADVERTISE { + from protocol bgp; + then { + community add LOCAL-REGION; + accept; + } + } + } + policy-statement IMPORT-POLICY { + term ACCEPT-ALL { + then accept; + } + } + policy-statement SHIFTED { + term DEPRIORITIZE { + from { + protocol bgp; + } + then { + community add SHIFTED-OUT; + next policy; + } + } + } + community LOCAL-REGION members 64500:200; + community SHIFTED-OUT members [ 64500:200 64500:200 64500:200 ]; +} diff --git a/demo/tmpl/ex-edge-r/protocols.tera b/demo/tmpl/ex-edge-r/protocols.tera index 640f43b..ac07294 100644 --- a/demo/tmpl/ex-edge-r/protocols.tera +++ b/demo/tmpl/ex-edge-r/protocols.tera @@ -1,3 +1,14 @@ protocols { - {{ protocol }}; + bgp { + group UPSTREAM { + type external; + peer-as 64500; + import IMPORT-POLICY; +{%- if live %} + export EXPORT-POLICY; +{%- else %} + export [ SHIFTED EXPORT-POLICY ]; +{%- endif %} + } + } } diff --git a/demo/tmpl/ex-edge-r/structure.yaml b/demo/tmpl/ex-edge-r/structure.yaml index fb21b46..0ec20d0 100644 --- a/demo/tmpl/ex-edge-r/structure.yaml +++ b/demo/tmpl/ex-edge-r/structure.yaml @@ -2,3 +2,9 @@ files: - system - interfaces - protocols + - policy-options +platform: junos +variations: + - live + - shifted + - init diff --git a/demo/tmpl/ex-edge-r/system.tera b/demo/tmpl/ex-edge-r/system.tera index 382967f..15e7201 100644 --- a/demo/tmpl/ex-edge-r/system.tera +++ b/demo/tmpl/ex-edge-r/system.tera @@ -1,8 +1,18 @@ system { - hostname {{ hostname }}; - location "{{ location }}"; - zone {{ zone }}; - users { - {{ username }}; + /* location "{{ location }}" zone {{ zone }} */ + host-name {{ hostname }}; + system { + login { +{%- if init %} + user bootstrap { + uid 2000; + class super-user; + } +{%- endif %} + user {{ username }} { + uid 2001; + class super-user; + } + } } } diff --git a/src/main.rs b/src/main.rs index 8afc93b..cedb88b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,14 @@ mod cli; mod log; -mod specs; -mod tmpls; +mod render; +mod spec; +mod tmpl; use log::LogLevel; +use render::RenderedConfig; use std::fs::{self, File, OpenOptions, create_dir_all, write}; use std::io::Write; use std::path::Path; -use tmpls::RenderedConfig; use yaml_serde; fn main() { @@ -16,11 +17,14 @@ fn main() { dbug!(dbg, "{:#?}", &args); - let specifications: Vec = - specs::compile(&args.devices, &args.env.spec_path, dbg); + let specifications: Vec = + spec::compile(&args.devices, &args.env.spec_path, dbg); for spec in specifications { - let result = RenderedConfig::from_spec(&spec, dbg).ok().unwrap(); + let result = RenderedConfig::from_spec(&spec, dbg).unwrap_or_else(|e| { + eprintln!("{}", e); + std::process::exit(1); + }); output_rendered_configs(result, &args.env.out_path, dbg) } } diff --git a/src/tmpls.rs b/src/render.rs similarity index 83% rename from src/tmpls.rs rename to src/render.rs index e9a18ed..b7e2484 100644 --- a/src/tmpls.rs +++ b/src/render.rs @@ -1,14 +1,9 @@ -use crate::specs::Specification; +use crate::spec::Specification; +use crate::tmpl; use crate::{LogLevel, info, verb}; use serde_json::Value; use std::fs; use tera::{Context, Tera}; -use yaml_serde; - -#[derive(serde::Deserialize)] -struct TemplateConfig { - files: Vec, -} pub struct RenderedConfig { pub hostname: String, @@ -43,19 +38,16 @@ impl RenderedConfig { let base_dir = std::path::Path::new("./tmpl").join(spec.get_layer()); - // Read structure.yaml let structure_path = base_dir.join("structure.yaml"); - let structure_data = fs::read_to_string(&structure_path) - .map_err(|e| format!("Failed to read {}: {}", structure_path.display(), e))?; - - let config_meta: TemplateConfig = yaml_serde::from_str(&structure_data)?; + let structure = tmpl::Structure::from_file(&structure_path) + .map_err(|e| format!("Failed to parse {}: {}", structure_path.display(), e))?; let mut tera = Tera::default(); let mut configs = Vec::new(); info!(dbg, "Rendering {}", hostname); - let template_data: Vec<(String, String)> = config_meta + let template_data: Vec<(String, String)> = structure .files .iter() .filter_map(|name| { @@ -72,7 +64,7 @@ impl RenderedConfig { tera.add_raw_templates(template_data)?; - for template_name in &config_meta.files { + for template_name in &structure.files { verb!(dbg, " | {}", &template_name); if !tera.get_template_names().any(|n| n == template_name) { continue; diff --git a/src/specs.rs b/src/spec.rs similarity index 100% rename from src/specs.rs rename to src/spec.rs diff --git a/src/tmpl.rs b/src/tmpl.rs new file mode 100644 index 0000000..9b4969e --- /dev/null +++ b/src/tmpl.rs @@ -0,0 +1,19 @@ +use serde::Deserialize; +use yaml_serde; + +#[derive(Deserialize)] +pub struct Structure { + pub files: Vec, + #[allow(dead_code)] //todo + pub platform: String, + #[allow(dead_code)] //todo + pub variations: Vec, +} + +impl Structure { + pub fn from_file(path: &std::path::Path) -> Result> { + let data = + std::fs::read_to_string(path).map_err(|e| format!("{}: {}", path.display(), e))?; + Ok(yaml_serde::from_str(&data)?) + } +}