git.delta.rocks / jrsonnet / refs/commits / 8d4a7a16f575

difftreelog

source

cmds/fleet/src/host.rs3.7 KiBsourcehistory
1use std::{2	cell::{Ref, RefCell, RefMut},3	env::current_dir,4	ffi::{OsStr, OsString},5	ops::Deref,6	path::PathBuf,7	sync::Arc,8};910use anyhow::Result;11use serde::de::DeserializeOwned;12use structopt::clap::ArgGroup;13use structopt::StructOpt;14use tokio::process::Command;1516use crate::{command::CommandExt, fleetdata::FleetData};1718pub struct FleetConfigInternals {19	pub local_system: String,20	pub directory: PathBuf,21	pub opts: FleetOpts,22	pub data: RefCell<FleetData>,23}2425#[derive(Clone)]26pub struct Config(Arc<FleetConfigInternals>);2728impl Deref for Config {29	type Target = FleetConfigInternals;3031	fn deref(&self) -> &Self::Target {32		&self.033	}34}3536impl Config {37	pub fn should_skip(&self, host: &str) -> bool {38		if !self.opts.skip.is_empty() {39			self.opts.skip.iter().any(|h| h as &str == host)40		} else if !self.opts.only.is_empty() {41			!self.opts.only.iter().any(|h| h as &str == host)42		} else {43			false44		}45	}46	pub fn is_local(&self, host: &str) -> bool {47		self.opts.localhost.as_ref().map(|s| s as &str) == Some(host)48	}4950	pub fn command_on(&self, host: &str, program: impl AsRef<OsStr>, sudo: bool) -> Command {51		if self.is_local(host) {52			if sudo {53				let mut cmd = Command::new("sudo");54				cmd.arg(program);55				cmd56			} else {57				Command::new(program)58			}59		} else {60			let mut cmd = Command::new("ssh");61			cmd.arg(host).arg("--");62			if sudo {63				cmd.arg("sudo");64			}65			cmd.arg(program);66			cmd67		}68	}6970	pub fn configuration_attr_name(&self, name: &str) -> OsString {71		let mut str = self.directory.as_os_str().to_owned();72		str.push("#");73		str.push(&format!(74			"fleetConfigurations.default.{}.{}",75			self.local_system, name76		));77		str78	}7980	pub async fn list_hosts(&self) -> Result<Vec<String>> {81		Command::new("nix")82			.arg("eval")83			.arg(self.configuration_attr_name("configuredHosts"))84			.args(&["--apply", "builtins.attrNames", "--json", "--show-trace"])85			.run_nix_json()86			.await87	}88	pub async fn config_attr<T: DeserializeOwned>(&self, host: &str, attr: &str) -> Result<T> {89		Command::new("nix")90			.arg("eval")91			.arg(92				self.configuration_attr_name(&format!(93					"configuredSystems.{}.config.{}",94					host, attr95				)),96			)97			.args(&["--json", "--show-trace"])98			.run_nix_json()99			.await100	}101102	pub fn data(&self) -> Ref<FleetData> {103		self.data.borrow()104	}105	pub fn data_mut(&self) -> RefMut<FleetData> {106		self.data.borrow_mut()107	}108109	pub fn save(&self) -> Result<()> {110		let mut fleet_data_path = self.directory.clone();111		fleet_data_path.push("fleet.nix");112		let data = nixlike::serialize(&self.data() as &FleetData)?;113		std::fs::write(114			fleet_data_path,115			format!(116				"# This file contains fleet state and shouldn't be edited by hand\n\n{}\n",117				data118			),119		)?;120		Ok(())121	}122}123124#[derive(StructOpt, Clone)]125#[structopt(group = ArgGroup::with_name("target_hosts"))]126pub struct FleetOpts {127	/// All hosts except those would be skipped128	#[structopt(long, number_of_values = 1, group = "target_hosts")]129	only: Vec<String>,130131	/// Hosts to skip132	#[structopt(long, number_of_values = 1, group = "target_hosts")]133	skip: Vec<String>,134135	/// Host, which should be threaten as current machine136	#[structopt(long)]137	pub localhost: Option<String>,138139	#[structopt(long, default_value = "x86_64-linux")]140	pub local_system: String,141}142143impl FleetOpts {144	pub fn build(mut self) -> Result<Config> {145		let local_system = self.local_system.clone();146		if self.localhost.is_none() {147			self.localhost148				.replace(hostname::get().unwrap().to_str().unwrap().to_owned());149		}150		let directory = current_dir()?;151152		let mut fleet_data_path = directory.clone();153		fleet_data_path.push("fleet.nix");154		let bytes = std::fs::read_to_string(fleet_data_path)?;155		let data = nixlike::parse_str(&bytes)?;156157		Ok(Config(Arc::new(FleetConfigInternals {158			opts: self,159			directory,160			data,161			local_system,162		})))163	}164}