breakout tmpl from configgen; stage variations/platform feat

This commit is contained in:
2026-02-17 03:00:17 -07:00
parent bd91fe5b15
commit a813c4cb53
13 changed files with 102 additions and 30 deletions

View File

@@ -1,2 +1,2 @@
device:
hostname: xyz1-ex-edge-r201
hostname: xyz1-ex-core-r101

View File

@@ -1,2 +1,2 @@
device:
hostname: xyz1-ex-edge-r202
hostname: xyz1-ex-core-r102

View File

@@ -1,2 +1,2 @@
device:
hostname: xyz2-ex-edge-r201
hostname: xyz2-ex-core-r101

View File

@@ -1,2 +1,2 @@
device:
hostname: xyz2-ex-edge-r202
hostname: xyz2-ex-core-r202

View File

@@ -1,2 +1,3 @@
device:
hostname: xyz1-ex-edge-r101
live: true

View 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 ];
}

View File

@@ -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 %}
}
}
}

View File

@@ -2,3 +2,9 @@ files:
- system
- interfaces
- protocols
- policy-options
platform: junos
variations:
- live
- shifted
- init

View File

@@ -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;
}
}
}
}

View File

@@ -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)
}
}

View File

@@ -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
View 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)?)
}
}