feat: Initial rewrite of python render tool

This commit is contained in:
2026-03-16 03:14:33 +01:00
commit e4d39de2f0
24 changed files with 4453 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
use std::net::Ipv4Addr;
use std::path::PathBuf;
use std::str::FromStr;
use minijinja::Environment;
use optional_struct::{Applicable, optional_struct};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use walkdir::WalkDir;
use crate::get_talos_config_path;
use crate::node::{Node, OptionalNode};
use crate::patch::Patches;
#[optional_struct]
#[derive(Debug, Deserialize, JsonSchema, Clone)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Base {
#[serde(default)]
pub(crate) kernel_args: Vec<String>,
#[serde(default)]
pub(crate) patches: Patches,
}
#[optional_struct]
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Version {
kubernetes: semver::Version,
talos: semver::Version,
}
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub enum ClusterEnv {
Production,
Staging,
}
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, PartialEq, Eq)]
#[serde(untagged)]
pub enum NodeEntry {
Name(String),
#[serde(skip_deserializing)]
Node(Box<Node>),
}
#[optional_struct]
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Cluster {
#[serde(skip_deserializing)]
name: String,
#[optional_rename(OptionalVersion)]
#[optional_wrap]
version: Version,
nodes: Vec<NodeEntry>,
cluster_env: ClusterEnv,
control_plane_ip: Ipv4Addr,
secrets_file: PathBuf,
#[serde(default, skip_serializing)]
#[optional_skip_wrap]
pub(crate) default: OptionalNode,
#[optional_rename(OptionalBase)]
#[optional_wrap]
#[serde(skip_serializing)]
pub(crate) base: Base,
// pub secrets_file: PathBuf,
}
impl Cluster {
pub fn get(cluster_name: &str, env: &Environment) -> Self {
let path = get_talos_config_path()
.join("clusters")
.join("default.yaml");
let default: OptionalCluster = if path.exists() {
let content = std::fs::read_to_string(path).unwrap();
serde_yaml::from_str(&content).unwrap()
} else {
Default::default()
};
let mut path = get_talos_config_path().join("clusters").join(cluster_name);
path.add_extension("yaml");
let content = std::fs::read_to_string(path).unwrap();
let mut cluster: OptionalCluster = serde_yaml::from_str(&content).unwrap();
cluster.name = Some(cluster_name.to_string());
// For some reason apply on the cluster does not properly apply to the default settings...
// So we manually apply it here first
cluster.default = default.default.clone().apply(cluster.default);
let mut cluster: Self = default.apply(cluster).try_into().unwrap();
cluster.nodes = cluster
.nodes
.clone()
.into_iter()
.map(|node_entry| {
if let NodeEntry::Name(name) = node_entry {
NodeEntry::Node(Box::new(Node::get(&name, env, &cluster)))
} else {
node_entry
}
})
.collect();
cluster.secrets_file = get_talos_config_path()
.join("secrets")
.join(cluster.secrets_file)
.absolute()
.unwrap();
cluster
}
}
pub fn get_clusters(env: &Environment) -> Vec<Cluster> {
WalkDir::new(get_talos_config_path().join("clusters"))
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.metadata().unwrap().is_file())
.filter_map(|e| {
let mut path = PathBuf::from_str(&e.file_name().to_string_lossy()).unwrap();
path.set_extension("");
let name = path.to_string_lossy().to_string();
if name == "default" {
return None;
}
Some(Cluster::get(&name, env))
})
.collect()
}