git.delta.rocks / jrsonnet / refs/commits / f59b0688ddd0

difftreelog

feat fleet tf now executes terraform by itself

Yaroslav Bolyukin2024-09-01parent: #87c4900.patch.diff
in: trunk

3 files changed

modifiedcmds/fleet/src/cmds/tf.rsdiffbeforeafterboth
--- 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<OsString>,
 }
 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<String, PathBuf> = 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<String, PathBuf> = 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(())
modifiedcmds/fleet/src/main.rsdiffbeforeafterboth
82 #[clap(hide(true))]82 #[clap(hide(true))]
83 Complete(Complete),83 Complete(Complete),
84 /// Compile and evaluate terranix configuration84 /// Compile and evaluate terranix configuration
85 #[clap(subcommand)]
86 Tf(Tf),85 Tf(Tf),
87}86}
8887
addedcmds/terraform-provider-fleet/Cargo.tomldiffbeforeafterboth
--- /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