breakout tmpl from configgen; stage variations/platform feat
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
device:
|
||||
hostname: xyz1-ex-edge-r201
|
||||
hostname: xyz1-ex-core-r101
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
device:
|
||||
hostname: xyz1-ex-edge-r202
|
||||
hostname: xyz1-ex-core-r102
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
device:
|
||||
hostname: xyz2-ex-edge-r201
|
||||
hostname: xyz2-ex-core-r101
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
device:
|
||||
hostname: xyz2-ex-edge-r202
|
||||
hostname: xyz2-ex-core-r202
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
device:
|
||||
hostname: xyz1-ex-edge-r101
|
||||
live: true
|
||||
|
||||
29
demo/tmpl/ex-edge-r/policy-options.tera
Normal file
29
demo/tmpl/ex-edge-r/policy-options.tera
Normal file
@@ -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 ];
|
||||
}
|
||||
@@ -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 %}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,3 +2,9 @@ files:
|
||||
- system
|
||||
- interfaces
|
||||
- protocols
|
||||
- policy-options
|
||||
platform: junos
|
||||
variations:
|
||||
- live
|
||||
- shifted
|
||||
- init
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
src/main.rs
16
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::Specification> =
|
||||
specs::compile(&args.devices, &args.env.spec_path, dbg);
|
||||
let specifications: Vec<spec::Specification> =
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String>,
|
||||
}
|
||||
|
||||
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;
|
||||
19
src/tmpl.rs
Normal file
19
src/tmpl.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
use serde::Deserialize;
|
||||
use yaml_serde;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Structure {
|
||||
pub files: Vec<String>,
|
||||
#[allow(dead_code)] //todo
|
||||
pub platform: String,
|
||||
#[allow(dead_code)] //todo
|
||||
pub variations: Vec<String>,
|
||||
}
|
||||
|
||||
impl Structure {
|
||||
pub fn from_file(path: &std::path::Path) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let data =
|
||||
std::fs::read_to_string(path).map_err(|e| format!("{}: {}", path.display(), e))?;
|
||||
Ok(yaml_serde::from_str(&data)?)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user