Files
crete/src/main.rs
T

127 lines
3.7 KiB
Rust

mod cli;
mod error;
mod file;
mod http;
use std::net::SocketAddr;
use std::pin::pin;
use axum::Router;
use axum::routing::get;
use clap::{CommandFactory, Parser};
use clap_complete::{Shell, generate as generate_complete};
use crete::cluster::Cluster;
use crete::environment::PathEnvironment;
use crete::talosconfig::{get_current_context, set_context};
use crete::{get_configs_path, get_repo_path, set_repo_path, tftp};
use futures::StreamExt;
use futures::future::join_all;
use minijinja::context;
use crate::cli::{Cli, Commands, GlobalOpts};
use crate::error::Error;
use crate::file::get_file;
use crate::http::handler;
async fn generate(opts: &GlobalOpts) -> Result<(), Error> {
let clusters = Cluster::get_all().await;
if clusters.is_empty() {
return Err(Error::NoClustersFound);
}
let path = opts.repo.join("rendered");
// We don't really care if this fails, as that likely mean that the directory did not exist
tokio::fs::remove_dir_all(&path).await.ok();
tokio::fs::create_dir_all(&path).await.unwrap();
// Render templates
let template_env = PathEnvironment::new(&get_repo_path().join("templates"));
let mut stream = pin!(template_env.files());
while let Some(template_name) = stream.next().await {
let template = template_env.get_template(&template_name).unwrap();
let content = template
.render(context! {
clusters => clusters.values().collect::<Vec<_>>(),
root => opts.repo
})
.unwrap();
tokio::fs::write(path.join(template_name), content)
.await
.unwrap();
}
let context = get_current_context().await;
// Remove existing config files and create output directory
let path = get_configs_path();
tokio::fs::remove_dir_all(&path).await.ok();
tokio::fs::create_dir_all(&path).await.unwrap();
// Generate config files
join_all(clusters.values().map(|cluster| async move {
join_all(cluster.nodes().map(|node| {
let cluster = cluster.clone();
async move {
node.config_write(&cluster).await;
}
}))
.await;
// Run these commands in parallel with the the node commands
// NOTE: These do need to happen in the correct order
cluster.talosconfig_write().await;
}))
.await;
// Merge all the cluster talosconfig files into a single file
// Since this all modifies the same output file this has to happen sequentially
for (_, cluster) in clusters {
cluster.talosconfig_merge().await;
}
if let Some(context) = context {
set_context(context).await;
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Error> {
let cli = Cli::parse();
set_repo_path(&cli.global_opts.repo);
match cli.command {
Commands::Generate => generate(&cli.global_opts).await?,
Commands::ShellCompletions => generate_complete(
Shell::from_env().unwrap_or(Shell::Bash),
&mut Cli::command(),
"crete",
&mut std::io::stdout(),
),
Commands::Serve { port, ip } => {
tokio::spawn(async move {
let app = Router::new().fallback_service(get(handler));
let addr: SocketAddr = (ip, port).into();
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
println!("Http server started on {addr}");
axum::serve(listener, app).await.unwrap();
});
tftp::serve(ip, move |filename, _| {
let filename = filename.to_owned();
async move { get_file(filename).await.map(|(file, _)| file) }
})
.await?;
}
};
Ok(())
}