From f59b0688ddd0e64982becd4c23266a3c9de8f45b Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sun, 01 Sep 2024 22:16:30 +0000 Subject: [PATCH] feat: fleet tf now executes terraform by itself --- --- a/cmds/fleet/src/cmds/tf.rs +++ b/cmds/fleet/src/cmds/tf.rs @@ -1,17 +1,23 @@ use std::{ collections::{BTreeMap, HashMap}, + ffi::OsString, path::PathBuf, }; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; use clap::Parser; use fleet_base::host::Config; use nix_eval::nix_go; use serde::Deserialize; use serde_json::Value; -use tokio::{fs::copy, process::Command}; +use tempfile::NamedTempFile; +use tokio::{ + fs::{self, create_dir_all}, + process::Command, +}; +use tracing::debug; -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] pub struct TfData { // Dummy #[allow(dead_code)] @@ -23,44 +29,56 @@ } #[derive(Parser)] -pub enum Tf { - /// Generate fleet.tf.json file for running terraform. - Generate, - /// Fetch data from terraform to fleet. - Refresh, +pub struct Tf { + args: Vec, } impl Tf { pub async fn run(&self, config: &Config) -> Result<()> { - match self { - Tf::Generate => { - let system = &config.local_system; - let config = &config.config_field; - let data: HashMap = nix_go!(config.tf({ system })).build().await?; - let data = &data["out"]; + let dir = config.directory.join(".fleet/tf/default"); + // TODO: consider postponing fleet init until this step, as it might be + // highly preferred to extract terraform configuration using multithreaded nix or + // lazy-trees nix. lazy-trees nix is very fast and perfect for this task. + { + debug!("generating terraform configs"); + let system = &config.local_system; + let config = &config.config_field; + let data: HashMap = nix_go!(config.tf({ system })).build().await?; + let data = &data["out"]; + let data = fs::read(&data).await?; + + create_dir_all(&dir).await?; - copy(data, "fleet.tf.json").await?; - } - Tf::Refresh => { - let cmd = Command::new("terraform").arg("refresh").status().await?; - if !cmd.success() { - bail!("terraform refresh failed") - } + let tmp = NamedTempFile::new_in(&dir)?; + fs::write(tmp.path(), data).await?; + tmp.persist(dir.join("fleet.tf.json"))?; + } - let data = Command::new("terraform") - .arg("output") - .arg("-json") - .arg("fleet") - .output() - .await?; - let tf_data: TfData = serde_json::from_slice(&data.stdout) - .context("failed to parse terraform fleet output")?; + { + debug!("running terraform command"); + Command::new("terraform") + .current_dir(&dir) + .args(&self.args) + .status() + .await?; + } + { + debug!("syncing terraform data"); + let data = Command::new("terraform") + .current_dir(dir) + .arg("output") + .arg("-json") + .arg("fleet") + .output() + .await?; + let tf_data: TfData = serde_json::from_slice(&data.stdout) + .context("failed to parse terraform fleet output")?; - let mut data = config.data(); - data.extra.insert( - "terraformHosts".to_owned(), - serde_json::to_value(tf_data.hosts).expect("should be valid extra"), - ); - } + let mut data = config.data(); + debug!("synchronized done = {tf_data:?}"); + data.extra.insert( + "terraformHosts".to_owned(), + serde_json::to_value(tf_data.hosts).expect("should be valid extra"), + ); } Ok(()) --- a/cmds/fleet/src/main.rs +++ b/cmds/fleet/src/main.rs @@ -82,7 +82,6 @@ #[clap(hide(true))] Complete(Complete), /// Compile and evaluate terranix configuration - #[clap(subcommand)] Tf(Tf), } --- /dev/null +++ b/cmds/terraform-provider-fleet/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "terraform-provider-fleet" +edition = "2021" +version.workspace = true + +[dependencies] +anyhow.workspace = true +async-trait = "0.1.81" +serde = { workspace = true, features = ["derive"] } +tf-provider = "0.2.2" +tokio.workspace = true -- gitstuff