feat: Generate talos configs
This commit is contained in:
+67
-5
@@ -1,5 +1,6 @@
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use minijinja::Environment;
|
use minijinja::Environment;
|
||||||
@@ -9,9 +10,9 @@ use serde::{Deserialize, Serialize};
|
|||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::environment::PathEnvironment;
|
use crate::environment::PathEnvironment;
|
||||||
use crate::get_talos_path;
|
|
||||||
use crate::node::{Node, OptionalNodeDeserialize};
|
use crate::node::{Node, OptionalNodeDeserialize};
|
||||||
use crate::patch::Patches;
|
use crate::patch::Patches;
|
||||||
|
use crate::{get_configs_path, get_talos_path};
|
||||||
|
|
||||||
#[optional_struct]
|
#[optional_struct]
|
||||||
#[derive(Debug, Deserialize, JsonSchema, Clone)]
|
#[derive(Debug, Deserialize, JsonSchema, Clone)]
|
||||||
@@ -31,6 +32,16 @@ pub struct Version {
|
|||||||
talos: semver::Version,
|
talos: semver::Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Version {
|
||||||
|
pub(crate) fn kubernetes(&self) -> String {
|
||||||
|
format!("v{}", self.kubernetes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn talos(&self) -> String {
|
||||||
|
format!("v{}", self.talos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Copy, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
||||||
pub enum ClusterEnv {
|
pub enum ClusterEnv {
|
||||||
@@ -60,12 +71,12 @@ struct ClusterDeserialize {
|
|||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Cluster {
|
pub struct Cluster {
|
||||||
name: String,
|
pub(crate) name: String,
|
||||||
version: Version,
|
pub(crate) version: Version,
|
||||||
nodes: Vec<Node>,
|
nodes: Vec<Node>,
|
||||||
cluster_env: ClusterEnv,
|
cluster_env: ClusterEnv,
|
||||||
control_plane_ip: Ipv4Addr,
|
pub(crate) control_plane_ip: Ipv4Addr,
|
||||||
secrets_file: PathBuf,
|
pub(crate) secrets_file: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cluster {
|
impl Cluster {
|
||||||
@@ -142,6 +153,57 @@ impl Cluster {
|
|||||||
pub fn nodes(&self) -> &[Node] {
|
pub fn nodes(&self) -> &[Node] {
|
||||||
&self.nodes
|
&self.nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn talosctl_gen_config_command(&self) -> Command {
|
||||||
|
let path = get_configs_path().join(&self.name).join("talosconfig");
|
||||||
|
|
||||||
|
let mut command = Command::new("talosctl");
|
||||||
|
command.args([
|
||||||
|
"gen",
|
||||||
|
"config",
|
||||||
|
&self.name,
|
||||||
|
&format!("https://{}:6443", self.control_plane_ip),
|
||||||
|
"--with-secrets",
|
||||||
|
self.secrets_file.to_str().expect("Path should be valid"),
|
||||||
|
"--output-types",
|
||||||
|
"talosconfig",
|
||||||
|
"-o",
|
||||||
|
path.to_str().expect("Path should be valid utf-8"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
command
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn talosctl_add_endpoint_command(&self) -> Command {
|
||||||
|
let path = get_configs_path().join(&self.name).join("talosconfig");
|
||||||
|
|
||||||
|
let mut command = Command::new("talosctl");
|
||||||
|
command.args([
|
||||||
|
"config",
|
||||||
|
"--talosconfig",
|
||||||
|
path.to_str().expect("Path should be valid utf-8"),
|
||||||
|
"endpoint",
|
||||||
|
&self.control_plane_ip.to_string(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
command
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn talosctl_merge_command(&self) -> Command {
|
||||||
|
let cluster_path = get_configs_path().join(&self.name).join("talosconfig");
|
||||||
|
let path = get_configs_path().join("talosconfig");
|
||||||
|
|
||||||
|
let mut command = Command::new("talosctl");
|
||||||
|
command.args([
|
||||||
|
"config",
|
||||||
|
"--talosconfig",
|
||||||
|
path.to_str().expect("Path should be valid utf-8"),
|
||||||
|
"merge",
|
||||||
|
cluster_path.to_str().expect("Path should be valid utf-8"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
command
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JsonSchema for Cluster {
|
impl JsonSchema for Cluster {
|
||||||
|
|||||||
+31
-1
@@ -1,10 +1,12 @@
|
|||||||
mod cli;
|
mod cli;
|
||||||
|
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use clap::{CommandFactory, Parser};
|
use clap::{CommandFactory, Parser};
|
||||||
use clap_complete::{Shell, generate as generate_complete};
|
use clap_complete::{Shell, generate as generate_complete};
|
||||||
use crete::cluster::Cluster;
|
use crete::cluster::Cluster;
|
||||||
use crete::environment::PathEnvironment;
|
use crete::environment::PathEnvironment;
|
||||||
use crete::{get_repo_path, set_repo_path};
|
use crete::{get_configs_path, get_repo_path, set_repo_path};
|
||||||
use minijinja::context;
|
use minijinja::context;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@@ -16,6 +18,16 @@ enum Error {
|
|||||||
NoClustersFound,
|
NoClustersFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_command(mut command: Command) {
|
||||||
|
let output = command.output().unwrap();
|
||||||
|
if !output.stdout.is_empty() {
|
||||||
|
println!("{}", String::from_utf8_lossy(&output.stdout).trim_end());
|
||||||
|
}
|
||||||
|
if !output.stderr.is_empty() {
|
||||||
|
println!("{}", String::from_utf8_lossy(&output.stderr).trim_end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn generate(opts: &GlobalOpts) -> Result<(), Error> {
|
fn generate(opts: &GlobalOpts) -> Result<(), Error> {
|
||||||
set_repo_path(&opts.repo);
|
set_repo_path(&opts.repo);
|
||||||
|
|
||||||
@@ -46,6 +58,24 @@ fn generate(opts: &GlobalOpts) -> Result<(), Error> {
|
|||||||
std::fs::write(path.join(template_name), content).unwrap();
|
std::fs::write(path.join(template_name), content).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove existing config files and create output directory
|
||||||
|
let path = get_configs_path();
|
||||||
|
if path.exists() {
|
||||||
|
std::fs::remove_dir_all(&path).unwrap();
|
||||||
|
}
|
||||||
|
std::fs::create_dir(&path).unwrap();
|
||||||
|
|
||||||
|
// Generate config files
|
||||||
|
for cluster in clusters {
|
||||||
|
for node in cluster.nodes() {
|
||||||
|
run_command(node.talosctl_gen_config_command(&cluster));
|
||||||
|
}
|
||||||
|
|
||||||
|
run_command(cluster.talosctl_gen_config_command());
|
||||||
|
run_command(cluster.talosctl_add_endpoint_command());
|
||||||
|
run_command(cluster.talosctl_merge_command());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+46
-1
@@ -1,4 +1,5 @@
|
|||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use minijinja::Environment;
|
use minijinja::Environment;
|
||||||
use optional_struct::{Applicable, optional_struct};
|
use optional_struct::{Applicable, optional_struct};
|
||||||
@@ -6,10 +7,10 @@ use schemars::JsonSchema;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::cluster::{Base, Cluster};
|
use crate::cluster::{Base, Cluster};
|
||||||
use crate::get_talos_path;
|
|
||||||
use crate::patch::{OptionalPatches, OptionalPatchesString, Patches};
|
use crate::patch::{OptionalPatches, OptionalPatchesString, Patches};
|
||||||
use crate::schematic::Schematic;
|
use crate::schematic::Schematic;
|
||||||
use crate::secret::Secret;
|
use crate::secret::Secret;
|
||||||
|
use crate::{get_configs_path, get_talos_path};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Copy, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@@ -167,6 +168,50 @@ impl Node {
|
|||||||
|
|
||||||
Node { patches, ..node }
|
Node { patches, ..node }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn talosctl_gen_config_command(&self, cluster: &Cluster) -> Command {
|
||||||
|
let mut path = get_configs_path().join(&cluster.name).join(&self.hostname);
|
||||||
|
path.add_extension("yaml");
|
||||||
|
|
||||||
|
let mut command = Command::new("talosctl");
|
||||||
|
command.args([
|
||||||
|
"gen",
|
||||||
|
"config",
|
||||||
|
&cluster.name,
|
||||||
|
&format!("https://{}:6443", cluster.control_plane_ip),
|
||||||
|
"--with-secrets",
|
||||||
|
cluster.secrets_file.to_str().expect("Path should be valid"),
|
||||||
|
"--talos-version",
|
||||||
|
&cluster.version.talos(),
|
||||||
|
"--kubernetes-version",
|
||||||
|
&cluster.version.kubernetes(),
|
||||||
|
"--output-types",
|
||||||
|
self.r#type.into(),
|
||||||
|
"--install-image",
|
||||||
|
&format!(
|
||||||
|
"factory.talos.dev/metal-installer/{}:{}",
|
||||||
|
self.schematic,
|
||||||
|
cluster.version.talos()
|
||||||
|
),
|
||||||
|
"--with-docs=false",
|
||||||
|
"--with-examples=false",
|
||||||
|
"-o",
|
||||||
|
path.to_str().expect("Path should be valid utf-8"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
for patch in &self.patches.all {
|
||||||
|
command.args(["--config-patch", &serde_json::to_string(&patch).unwrap()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for patch in &self.patches.control_plane {
|
||||||
|
command.args([
|
||||||
|
"--config-patch-control-plane",
|
||||||
|
&serde_json::to_string(&patch).unwrap(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
command
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JsonSchema for Node {
|
impl JsonSchema for Node {
|
||||||
|
|||||||
Reference in New Issue
Block a user