use crate::error::ConnectError;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub const BUILTIN_TEMPLATES: &[&str] = &[
"cisco",
"huawei",
"h3c",
"hillstone",
"juniper",
"array",
"linux",
"arista",
"fortinet",
"paloalto",
"topsec",
"venustech",
"dptech",
"chaitin",
"qianxin",
"maipu",
"checkpoint",
];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum TemplateCapability {
LoginMode,
EnableMode,
ConfigMode,
SysContext,
InteractiveInput,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct TemplateMetadata {
pub name: String,
pub vendor: String,
pub family: String,
pub template_version: String,
pub capabilities: Vec<TemplateCapability>,
}
pub(crate) fn metadata_for(name: &str) -> Option<TemplateMetadata> {
let meta = match name {
"cisco" => TemplateMetadata {
name: "cisco".to_string(),
vendor: "Cisco".to_string(),
family: "IOS/IOS-XE".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::LoginMode,
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
TemplateCapability::InteractiveInput,
],
},
"huawei" => TemplateMetadata {
name: "huawei".to_string(),
vendor: "Huawei".to_string(),
family: "VRP".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
TemplateCapability::InteractiveInput,
],
},
"h3c" => TemplateMetadata {
name: "h3c".to_string(),
vendor: "H3C".to_string(),
family: "Comware".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
],
},
"hillstone" => TemplateMetadata {
name: "hillstone".to_string(),
vendor: "Hillstone".to_string(),
family: "SG".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
TemplateCapability::InteractiveInput,
],
},
"juniper" => TemplateMetadata {
name: "juniper".to_string(),
vendor: "Juniper".to_string(),
family: "JunOS".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
TemplateCapability::InteractiveInput,
],
},
"array" => TemplateMetadata {
name: "array".to_string(),
vendor: "Array Networks".to_string(),
family: "APV".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::LoginMode,
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
TemplateCapability::SysContext,
TemplateCapability::InteractiveInput,
],
},
"linux" => TemplateMetadata {
name: "linux".to_string(),
vendor: "Generic".to_string(),
family: "Linux".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::LoginMode,
TemplateCapability::EnableMode,
TemplateCapability::InteractiveInput,
],
},
"arista" => TemplateMetadata {
name: "arista".to_string(),
vendor: "Arista".to_string(),
family: "EOS".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::LoginMode,
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
TemplateCapability::InteractiveInput,
],
},
"fortinet" => TemplateMetadata {
name: "fortinet".to_string(),
vendor: "Fortinet".to_string(),
family: "FortiGate".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![TemplateCapability::EnableMode],
},
"paloalto" => TemplateMetadata {
name: "paloalto".to_string(),
vendor: "Palo Alto Networks".to_string(),
family: "PA".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
],
},
"topsec" => TemplateMetadata {
name: "topsec".to_string(),
vendor: "Topsec".to_string(),
family: "NGFW".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![TemplateCapability::EnableMode],
},
"venustech" => TemplateMetadata {
name: "venustech".to_string(),
vendor: "Venustech".to_string(),
family: "USG".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::LoginMode,
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
TemplateCapability::InteractiveInput,
],
},
"dptech" => TemplateMetadata {
name: "dptech".to_string(),
vendor: "DPTech".to_string(),
family: "FW".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
],
},
"chaitin" => TemplateMetadata {
name: "chaitin".to_string(),
vendor: "Chaitin".to_string(),
family: "SafeLine".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::LoginMode,
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
TemplateCapability::InteractiveInput,
],
},
"qianxin" => TemplateMetadata {
name: "qianxin".to_string(),
vendor: "QiAnXin".to_string(),
family: "NSG".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
],
},
"maipu" => TemplateMetadata {
name: "maipu".to_string(),
vendor: "Maipu".to_string(),
family: "NSS".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![
TemplateCapability::LoginMode,
TemplateCapability::EnableMode,
TemplateCapability::ConfigMode,
TemplateCapability::InteractiveInput,
],
},
"checkpoint" => TemplateMetadata {
name: "checkpoint".to_string(),
vendor: "Check Point".to_string(),
family: "Security Gateway".to_string(),
template_version: "1.0.0".to_string(),
capabilities: vec![TemplateCapability::EnableMode],
},
_ => return None,
};
Some(meta)
}
pub fn available_templates() -> &'static [&'static str] {
BUILTIN_TEMPLATES
}
pub fn template_catalog() -> Vec<TemplateMetadata> {
BUILTIN_TEMPLATES
.iter()
.filter_map(|name| metadata_for(name))
.collect()
}
pub fn template_metadata(name: &str) -> Result<TemplateMetadata, ConnectError> {
let key = name.to_ascii_lowercase();
metadata_for(&key).ok_or_else(|| ConnectError::TemplateNotFound(name.to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn available_templates_contains_expected_names() {
let names = available_templates();
assert!(names.contains(&"cisco"));
assert!(names.contains(&"juniper"));
assert!(names.contains(&"array"));
assert!(names.contains(&"linux"));
assert!(names.contains(&"arista"));
}
#[test]
fn template_catalog_has_metadata_for_all_builtin_templates() {
let catalog = template_catalog();
assert_eq!(catalog.len(), BUILTIN_TEMPLATES.len());
assert!(catalog.iter().any(|m| m.name == "cisco"));
assert!(catalog.iter().any(|m| m.name == "array"));
assert!(catalog.iter().any(|m| m.name == "linux"));
}
#[test]
fn template_metadata_is_case_insensitive() {
let meta = template_metadata("JuNiPeR").expect("metadata should resolve");
assert_eq!(meta.name, "juniper");
assert_eq!(meta.vendor, "Juniper");
}
}