git.delta.rocks / jrsonnet / refs/commits / 1aab6a2e63b6

difftreelog

refactor provide cross system using argument

Yaroslav Bolyukin2023-12-24parent: #89d3567.patch.diff
in: trunk

5 files changed

modifiedcmds/fleet/src/better_nix_eval.rsdiffbeforeafterboth
--- a/cmds/fleet/src/better_nix_eval.rs
+++ b/cmds/fleet/src/better_nix_eval.rs
@@ -16,7 +16,7 @@
 use tokio::select;
 use tokio::sync::{mpsc, oneshot};
 use tokio_util::codec::{FramedRead, LinesCodec};
-use tracing::{debug, error, warn};
+use tracing::{debug, error, warn, Level};
 
 use crate::command::{ClonableHandler, Handler, NixHandler, NoopHandler};
 
@@ -247,6 +247,10 @@
 		Ok(())
 	}
 	async fn send_command(&mut self, cmd: impl AsRef<[u8]>) -> Result<()> {
+		if tracing::enabled!(Level::DEBUG) {
+			let cmd_str = String::from_utf8_lossy(cmd.as_ref());
+			tracing::debug!("{cmd_str}");
+		};
 		self.stdin.write_all(cmd.as_ref()).await?;
 		self.stdin.write_all(b"\n").await?;
 		Ok(())
@@ -420,7 +424,7 @@
 	}
 	pub fn apply(v: impl Serialize) -> Self {
 		let serialized = nixlike::serialize(v).expect("invalid value for apply");
-		Self::Apply(serialized)
+		Self::Apply(serialized.trim_end().to_owned())
 	}
 }
 impl Display for Index {
@@ -434,8 +438,7 @@
 				write!(f, ".{v}")
 			}
 			Index::Apply(o) => {
-				let v = nixlike::serialize(o).map_err(|_| fmt::Error)?;
-				write!(f, "<apply>({v})")
+				write!(f, "<apply>({o})")
 			}
 			Index::Idx(i) => {
 				write!(f, "[{i}]")
@@ -451,7 +454,6 @@
 struct PathDisplay<'i>(&'i [Index]);
 impl Display for PathDisplay<'_> {
 	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-		write!(f, "flake")?;
 		for i in self.0 {
 			write!(f, "{i}")?;
 		}
@@ -508,8 +510,8 @@
 					query.push_str(escaped.trim());
 				}
 				Index::Apply(a) => {
-					query.push(' ');
-					query.push_str(&a);
+					// In cases like `a {}.b` first `{}.b` will be evaluated, so `a {}` should be encased in `()`
+					query = format!("({query} {a})");
 				}
 				Index::Idx(idx) => {
 					query = format!("builtins.elemAt ({query}) {idx}");
@@ -560,7 +562,7 @@
 			.await
 			.execute_expression_raw(&format!(":b sess_field_{id}"), &mut NixHandler::default())
 			.await?;
-		ensure!(!vid.is_empty(), "build failed");
+		ensure!(!vid.is_empty(), "build failed: {}", PathDisplay(&self.full_path));
 		let Some(vid) = vid.strip_prefix("This derivation produced the following outputs:\n")
 		else {
 			panic!("unexpected build output: {vid:?}");
modifiedcmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth
--- a/cmds/fleet/src/cmds/build_systems.rs
+++ b/cmds/fleet/src/cmds/build_systems.rs
@@ -5,7 +5,7 @@
 use crate::command::MyCommand;
 use crate::host::Config;
 use crate::nix_path;
-use anyhow::{anyhow, Result};
+use anyhow::{anyhow, Result, Context};
 use clap::Parser;
 use itertools::Itertools;
 use tokio::{task::LocalSet, time::sleep};
@@ -292,13 +292,14 @@
 		let action = Action::from(self.subcommand.clone());
 		let drv = config
 			.fleet_field
-			.select(nix_path!(.buildSystems.{action.build_attr()}.{&host}))
-			.await?;
+			.select(nix_path!(.buildSystems((serde_json::json!({
+				"localSystem": config.local_system.clone(),
+			}))).{action.build_attr()}.{&host}))
+			.await.context("system attribute")?;
 		let outputs = drv.build().await.map_err(|e| {
 			if action.build_attr() == "sdImage" {
 				info!("sd-image build failed");
 				info!("Make sure you have imported modulesPath/installer/sd-card/sd-image-<arch>[-installer].nix (For installer, you may want to check config)");
-				info!("This module was automatically imported before, but was removed for better customization")
 			}
 			e
 		})?;
@@ -311,6 +312,10 @@
 				if !config.is_local(&host) {
 					info!("uploading system closure");
 					{
+						// Alternatively, nix store make-content-addressed can be used,
+						// at least for the first deployment, to provide trusted store key.
+						//
+						// It is much slower, yet doesn't require root on the deployer machine.
 						let mut sign = MyCommand::new("nix");
 						// Private key for host machine is registered in nix-sign.nix
 						sign.arg("store")
modifiedcmds/fleet/src/host.rsdiffbeforeafterboth
before · cmds/fleet/src/host.rs
1use std::{2	env::current_dir,3	ffi::OsString,4	io::Write,5	ops::Deref,6	path::PathBuf,7	sync::{Arc, Mutex, MutexGuard},8};910use anyhow::{anyhow, bail, Context, Result};11use clap::{ArgGroup, Parser};12use openssh::SessionBuilder;13use tempfile::NamedTempFile;1415use crate::{16	better_nix_eval::{Field, Index, NixSessionPool},17	command::MyCommand,18	fleetdata::{FleetData, FleetSecret, FleetSharedSecret},19	nix_path,20};2122pub struct FleetConfigInternals {23	pub local_system: String,24	pub directory: PathBuf,25	pub opts: FleetOpts,26	pub data: Mutex<FleetData>,27	pub nix_args: Vec<OsString>,28	/// fleetConfigurations.<name>.<localSystem>29	pub fleet_field: Field,30	/// fleet_config.configUnchecked31	pub config_field: Field,32}3334#[derive(Clone)]35pub struct Config(Arc<FleetConfigInternals>);3637impl Deref for Config {38	type Target = FleetConfigInternals;3940	fn deref(&self) -> &Self::Target {41		&self.042	}43}4445pub struct ConfigHost {46	pub name: String,47}48impl ConfigHost {49	async fn open_session(&self) -> Result<openssh::Session> {50		let mut session = SessionBuilder::default();5152		session53			.connect(&self.name)54			.await55			.map_err(|e| anyhow!("ssh error: {e}"))56	}57}5859impl Config {60	pub fn should_skip(&self, host: &str) -> bool {61		if !self.opts.skip.is_empty() {62			self.opts.skip.iter().any(|h| h as &str == host)63		} else if !self.opts.only.is_empty() {64			!self.opts.only.iter().any(|h| h as &str == host)65		} else {66			false67		}68	}69	pub fn is_local(&self, host: &str) -> bool {70		self.opts.localhost.as_ref().map(|s| s as &str) == Some(host)71	}7273	pub async fn run_on(&self, host: &str, mut command: MyCommand, sudo: bool) -> Result<()> {74		if sudo {75			command = command.sudo();76		}77		if !self.is_local(host) {78			command = command.ssh(host);79		}80		command.run().await81	}82	pub async fn run_string_on(83		&self,84		host: &str,85		mut command: MyCommand,86		sudo: bool,87	) -> Result<String> {88		if sudo {89			command = command.sudo();90		}91		if !self.is_local(host) {92			command = command.ssh(host);93		}94		command.run_string().await95	}9697	pub async fn list_hosts(&self) -> Result<Vec<ConfigHost>> {98		let names = self99			.fleet_field100			.select(nix_path!(.configuredHosts))101			.await?102			.list_fields()103			.await?;104		let mut out = vec![];105		for name in names {106			out.push(ConfigHost { name })107		}108		Ok(out)109	}110	pub async fn system_config(&self, host: &str) -> Result<Field> {111		self.fleet_field112			.select(nix_path!(.configuredSystems.{host}.config))113			.await114	}115116	pub(super) fn data(&self) -> MutexGuard<FleetData> {117		self.data.lock().unwrap()118	}119	pub(super) fn data_mut(&self) -> MutexGuard<FleetData> {120		self.data.lock().unwrap()121	}122	/// Shared secrets configured in fleet.nix or in flake123	pub async fn list_configured_shared(&self) -> Result<Vec<String>> {124		self.config_field125			.select(nix_path!(.sharedSecrets))126			.await?127			.list_fields()128			.await129	}130	/// Shared secrets configured in fleet.nix131	pub fn list_shared(&self) -> Vec<String> {132		let data = self.data();133		data.shared_secrets.keys().cloned().collect()134	}135	pub fn has_shared(&self, name: &str) -> bool {136		let data = self.data();137		data.shared_secrets.contains_key(name)138	}139	pub fn replace_shared(&self, name: String, shared: FleetSharedSecret) {140		let mut data = self.data_mut();141		data.shared_secrets.insert(name.to_owned(), shared);142	}143	pub fn remove_shared(&self, secret: &str) {144		let mut data = self.data_mut();145		data.shared_secrets.remove(secret);146	}147148	pub fn has_secret(&self, host: &str, secret: &str) -> bool {149		let data = self.data();150		let Some(host_secrets) = data.host_secrets.get(host) else {151			return false;152		};153		host_secrets.contains_key(secret)154	}155	pub fn insert_secret(&self, host: &str, secret: String, value: FleetSecret) {156		let mut data = self.data_mut();157		let host_secrets = data.host_secrets.entry(host.to_owned()).or_default();158		host_secrets.insert(secret, value);159	}160161	pub async fn decrypt_on_host(&self, host: &str, data: Vec<u8>) -> Result<Vec<u8>> {162		let data = z85::encode(&data);163		let mut cmd = MyCommand::new("fleet-install-secrets");164		cmd.arg("decrypt").eqarg("--secret", data);165		cmd = cmd.sudo().ssh(host);166		let encoded = cmd167			.run_string()168			.await169			.context("failed to call remote host for decrypt")?170			.trim()171			.to_owned();172		z85::decode(encoded).context("bad encoded data? outdated host?")173	}174	pub async fn reencrypt_on_host(175		&self,176		host: &str,177		data: Vec<u8>,178		targets: Vec<String>,179	) -> Result<Vec<u8>> {180		let data = z85::encode(&data);181		let mut recmd = MyCommand::new("fleet-install-secrets");182		recmd.arg("reencrypt").eqarg("--secret", data);183		for target in targets {184			recmd.eqarg("--targets", target);185		}186		recmd = recmd.sudo().ssh(host);187		let encoded = recmd188			.run_string()189			.await190			.context("failed to call remote host for decrypt")?191			.trim()192			.to_owned();193		z85::decode(encoded).context("bad encoded data? outdated host?")194	}195196	pub fn host_secret(&self, host: &str, secret: &str) -> Result<FleetSecret> {197		let data = self.data();198		let Some(host_secrets) = data.host_secrets.get(host) else {199			bail!("no secrets for machine {host}");200		};201		let Some(secret) = host_secrets.get(secret) else {202			bail!("machine {host} has no secret {secret}");203		};204		Ok(secret.clone())205	}206	pub fn shared_secret(&self, secret: &str) -> Result<FleetSharedSecret> {207		let data = self.data();208		let Some(secret) = data.shared_secrets.get(secret) else {209			bail!("no shared secret {secret}");210		};211		Ok(secret.clone())212	}213	pub async fn shared_secret_expected_owners(&self, secret: &str) -> Result<Vec<String>> {214		self.config_field215			.select(nix_path!(.sharedSecrets.{secret}.expectedOwners))216			.await?217			.as_json()218			.await219	}220221	pub fn save(&self) -> Result<()> {222		let mut tempfile = NamedTempFile::new_in(self.directory.clone())?;223		let data = nixlike::serialize(&self.data() as &FleetData)?;224		tempfile.write_all(225			format!(226				"# This file contains fleet state and shouldn't be edited by hand\n\n{}\n\n# vim: ts=2 et nowrap\n",227				data228			)229			.as_bytes(),230		)?;231		let mut fleet_data_path = self.directory.clone();232		fleet_data_path.push("fleet.nix");233		tempfile.persist(fleet_data_path)?;234		Ok(())235	}236}237238#[derive(Parser, Clone)]239#[clap(group = ArgGroup::new("target_hosts"))]240pub struct FleetOpts {241	/// All hosts except those would be skipped242	#[clap(long, number_of_values = 1, group = "target_hosts")]243	only: Vec<String>,244245	/// Hosts to skip246	#[clap(long, number_of_values = 1, group = "target_hosts")]247	skip: Vec<String>,248249	/// Host, which should be threaten as current machine250	#[clap(long)]251	pub localhost: Option<String>,252253	// TODO: unhardcode x86_64-linux254	/// Override detected system for host, to perform builds via255	/// binfmt-declared qemu instead of trying to crosscompile256	#[clap(long, default_value = "detect")]257	pub local_system: String,258}259260impl FleetOpts {261	pub async fn build(mut self, nix_args: Vec<OsString>) -> Result<Config> {262		if self.localhost.is_none() {263			self.localhost264				.replace(hostname::get().unwrap().to_str().unwrap().to_owned());265		}266		let directory = current_dir()?;267268		let pool = NixSessionPool::new(directory.as_os_str().to_owned(), nix_args.clone()).await?;269		let root_field = pool.get().await?;270271		if self.local_system == "detect" {272			let builtins_field = Field::field(root_field.clone(), "builtins").await?;273			let system = builtins_field274				.select(nix_path!(.currentSystem))275				.await?;276			self.local_system = system.as_json().await?;277		}278		let local_system = self.local_system.clone();279280		let fleet_root = Field::field(root_field, "fleetConfigurations").await?;281282		let fleet_field = fleet_root283			.select(nix_path!(.default.{&local_system}))284			.await?;285		let config_field = fleet_field286			.select(nix_path!(.configUnchecked))287			.await?;288289		let mut fleet_data_path = directory.clone();290		fleet_data_path.push("fleet.nix");291		let bytes = std::fs::read_to_string(fleet_data_path)?;292		let data = nixlike::parse_str(&bytes)?;293294		Ok(Config(Arc::new(FleetConfigInternals {295			opts: self,296			directory,297			data,298			local_system,299			nix_args,300			fleet_field,301			config_field,302		})))303	}304}
after · cmds/fleet/src/host.rs
1use std::{2	env::current_dir,3	ffi::OsString,4	io::Write,5	ops::Deref,6	path::PathBuf,7	sync::{Arc, Mutex, MutexGuard},8};910use anyhow::{anyhow, bail, Context, Result};11use clap::{ArgGroup, Parser};12use openssh::SessionBuilder;13use tempfile::NamedTempFile;1415use crate::{16	better_nix_eval::{Field, NixSessionPool},17	command::MyCommand,18	fleetdata::{FleetData, FleetSecret, FleetSharedSecret},19	nix_path,20};2122pub struct FleetConfigInternals {23	pub local_system: String,24	pub directory: PathBuf,25	pub opts: FleetOpts,26	pub data: Mutex<FleetData>,27	pub nix_args: Vec<OsString>,28	/// fleetConfigurations.<name>.<localSystem>29	pub fleet_field: Field,30	/// fleet_config.configUnchecked31	pub config_field: Field,32}3334#[derive(Clone)]35pub struct Config(Arc<FleetConfigInternals>);3637impl Deref for Config {38	type Target = FleetConfigInternals;3940	fn deref(&self) -> &Self::Target {41		&self.042	}43}4445pub struct ConfigHost {46	pub name: String,47}48impl ConfigHost {49	async fn open_session(&self) -> Result<openssh::Session> {50		let mut session = SessionBuilder::default();5152		session53			.connect(&self.name)54			.await55			.map_err(|e| anyhow!("ssh error: {e}"))56	}57}5859impl Config {60	pub fn should_skip(&self, host: &str) -> bool {61		if !self.opts.skip.is_empty() {62			self.opts.skip.iter().any(|h| h as &str == host)63		} else if !self.opts.only.is_empty() {64			!self.opts.only.iter().any(|h| h as &str == host)65		} else {66			false67		}68	}69	pub fn is_local(&self, host: &str) -> bool {70		self.opts.localhost.as_ref().map(|s| s as &str) == Some(host)71	}7273	pub async fn run_on(&self, host: &str, mut command: MyCommand, sudo: bool) -> Result<()> {74		if sudo {75			command = command.sudo();76		}77		if !self.is_local(host) {78			command = command.ssh(host);79		}80		command.run().await81	}82	pub async fn run_string_on(83		&self,84		host: &str,85		mut command: MyCommand,86		sudo: bool,87	) -> Result<String> {88		if sudo {89			command = command.sudo();90		}91		if !self.is_local(host) {92			command = command.ssh(host);93		}94		command.run_string().await95	}9697	pub async fn list_hosts(&self) -> Result<Vec<ConfigHost>> {98		let names = self99			.fleet_field100			.select(nix_path!(.configuredHosts))101			.await?102			.list_fields()103			.await?;104		let mut out = vec![];105		for name in names {106			out.push(ConfigHost { name })107		}108		Ok(out)109	}110	pub async fn system_config(&self, host: &str) -> Result<Field> {111		self.fleet_field112			.select(nix_path!(.configuredSystems.{host}.config))113			.await114	}115116	pub(super) fn data(&self) -> MutexGuard<FleetData> {117		self.data.lock().unwrap()118	}119	pub(super) fn data_mut(&self) -> MutexGuard<FleetData> {120		self.data.lock().unwrap()121	}122	/// Shared secrets configured in fleet.nix or in flake123	pub async fn list_configured_shared(&self) -> Result<Vec<String>> {124		self.config_field125			.select(nix_path!(.sharedSecrets))126			.await?127			.list_fields()128			.await129	}130	/// Shared secrets configured in fleet.nix131	pub fn list_shared(&self) -> Vec<String> {132		let data = self.data();133		data.shared_secrets.keys().cloned().collect()134	}135	pub fn has_shared(&self, name: &str) -> bool {136		let data = self.data();137		data.shared_secrets.contains_key(name)138	}139	pub fn replace_shared(&self, name: String, shared: FleetSharedSecret) {140		let mut data = self.data_mut();141		data.shared_secrets.insert(name.to_owned(), shared);142	}143	pub fn remove_shared(&self, secret: &str) {144		let mut data = self.data_mut();145		data.shared_secrets.remove(secret);146	}147148	pub fn has_secret(&self, host: &str, secret: &str) -> bool {149		let data = self.data();150		let Some(host_secrets) = data.host_secrets.get(host) else {151			return false;152		};153		host_secrets.contains_key(secret)154	}155	pub fn insert_secret(&self, host: &str, secret: String, value: FleetSecret) {156		let mut data = self.data_mut();157		let host_secrets = data.host_secrets.entry(host.to_owned()).or_default();158		host_secrets.insert(secret, value);159	}160161	pub async fn decrypt_on_host(&self, host: &str, data: Vec<u8>) -> Result<Vec<u8>> {162		let data = z85::encode(&data);163		let mut cmd = MyCommand::new("fleet-install-secrets");164		cmd.arg("decrypt").eqarg("--secret", data);165		cmd = cmd.sudo().ssh(host);166		let encoded = cmd167			.run_string()168			.await169			.context("failed to call remote host for decrypt")?170			.trim()171			.to_owned();172		z85::decode(encoded).context("bad encoded data? outdated host?")173	}174	pub async fn reencrypt_on_host(175		&self,176		host: &str,177		data: Vec<u8>,178		targets: Vec<String>,179	) -> Result<Vec<u8>> {180		let data = z85::encode(&data);181		let mut recmd = MyCommand::new("fleet-install-secrets");182		recmd.arg("reencrypt").eqarg("--secret", data);183		for target in targets {184			recmd.eqarg("--targets", target);185		}186		recmd = recmd.sudo().ssh(host);187		let encoded = recmd188			.run_string()189			.await190			.context("failed to call remote host for decrypt")?191			.trim()192			.to_owned();193		z85::decode(encoded).context("bad encoded data? outdated host?")194	}195196	pub fn host_secret(&self, host: &str, secret: &str) -> Result<FleetSecret> {197		let data = self.data();198		let Some(host_secrets) = data.host_secrets.get(host) else {199			bail!("no secrets for machine {host}");200		};201		let Some(secret) = host_secrets.get(secret) else {202			bail!("machine {host} has no secret {secret}");203		};204		Ok(secret.clone())205	}206	pub fn shared_secret(&self, secret: &str) -> Result<FleetSharedSecret> {207		let data = self.data();208		let Some(secret) = data.shared_secrets.get(secret) else {209			bail!("no shared secret {secret}");210		};211		Ok(secret.clone())212	}213	pub async fn shared_secret_expected_owners(&self, secret: &str) -> Result<Vec<String>> {214		self.config_field215			.select(nix_path!(.sharedSecrets.{secret}.expectedOwners))216			.await?217			.as_json()218			.await219	}220221	pub fn save(&self) -> Result<()> {222		let mut tempfile = NamedTempFile::new_in(self.directory.clone())?;223		let data = nixlike::serialize(&self.data() as &FleetData)?;224		tempfile.write_all(225			format!(226				"# This file contains fleet state and shouldn't be edited by hand\n\n{}\n\n# vim: ts=2 et nowrap\n",227				data228			)229			.as_bytes(),230		)?;231		let mut fleet_data_path = self.directory.clone();232		fleet_data_path.push("fleet.nix");233		tempfile.persist(fleet_data_path)?;234		Ok(())235	}236}237238#[derive(Parser, Clone)]239#[clap(group = ArgGroup::new("target_hosts"))]240pub struct FleetOpts {241	/// All hosts except those would be skipped242	#[clap(long, number_of_values = 1, group = "target_hosts")]243	only: Vec<String>,244245	/// Hosts to skip246	#[clap(long, number_of_values = 1, group = "target_hosts")]247	skip: Vec<String>,248249	/// Host, which should be threaten as current machine250	#[clap(long)]251	pub localhost: Option<String>,252253	/// Override detected system for host, to perform builds via254	/// binfmt-declared qemu instead of trying to crosscompile255	#[clap(long, default_value = "detect")]256	pub local_system: String,257}258259impl FleetOpts {260	pub async fn build(mut self, nix_args: Vec<OsString>) -> Result<Config> {261		if self.localhost.is_none() {262			self.localhost263				.replace(hostname::get().unwrap().to_str().unwrap().to_owned());264		}265		let directory = current_dir()?;266267		let pool = NixSessionPool::new(directory.as_os_str().to_owned(), nix_args.clone()).await?;268		let root_field = pool.get().await?;269270		if self.local_system == "detect" {271			let builtins_field = Field::field(root_field.clone(), "builtins").await?;272			let system = builtins_field273				.select(nix_path!(.currentSystem))274				.await?;275			self.local_system = system.as_json().await?;276		}277		let local_system = self.local_system.clone();278279		let fleet_root = Field::field(root_field, "fleetConfigurations").await?;280281		let fleet_field = fleet_root282			.select(nix_path!(.default))283			.await?;284		let config_field = fleet_field285			.select(nix_path!(.configUnchecked))286			.await?;287288		let mut fleet_data_path = directory.clone();289		fleet_data_path.push("fleet.nix");290		let bytes = std::fs::read_to_string(fleet_data_path)?;291		let data = nixlike::parse_str(&bytes)?;292293		Ok(Config(Arc::new(FleetConfigInternals {294			opts: self,295			directory,296			data,297			local_system,298			nix_args,299			fleet_field,300			config_field,301		})))302	}303}
modifiedcmds/fleet/src/main.rsdiffbeforeafterboth
--- a/cmds/fleet/src/main.rs
+++ b/cmds/fleet/src/main.rs
@@ -24,7 +24,7 @@
 use host::{Config, FleetOpts};
 use human_repr::HumanCount;
 use indicatif::{ProgressState, ProgressStyle};
-use tracing::{info, metadata::LevelFilter};
+use tracing::info;
 use tracing::{info_span, Instrument};
 use tracing_indicatif::IndicatifLayer;
 use tracing_subscriber::{prelude::*, EnvFilter};
@@ -99,27 +99,6 @@
 	Ok(())
 }
 
-// fn main() -> Result<()> {
-// 	let pool = r2d2::Builder::<NixSessionPool>::new()
-// 		.min_idle(Some(1))
-// 		.max_lifetime(Some(Duration::from_secs(10)))
-// 		.build(NixSessionPool {
-// 			flake: ".".to_owned(),
-// 			nix_args: vec![],
-// 		})?;
-// 	let conn = pool.get()?;
-// 	let field = Field::root(conn);
-// 	// let builtins = field.get_field("builtins")?;
-// 	let cur_sys: String = field.get_field("builtins")?.as_json()?;
-// 	eprintln!("current system = {cur_sys}");
-// 	let v = field.get_field("fleetConfigurations")?;
-// 	eprintln!("configs = {:?}", v.list_fields()?);
-// 	let d = v.get_field("default")?;
-// 	dbg!(d.list_fields());
-// 	Ok(())
-// }
-//
-
 fn setup_logging() {
 	let indicatif_layer = IndicatifLayer::new().with_progress_style(
 		ProgressStyle::with_template(
@@ -157,7 +136,7 @@
 		),
 	);
 
-	let filter = EnvFilter::from_default_env().add_directive(LevelFilter::INFO.into());
+	let filter = EnvFilter::from_default_env();
 
 	tracing_subscriber::registry()
 		.with(
modifiedlib/default.nixdiffbeforeafterboth
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -11,8 +11,7 @@
       inherit nixpkgs hostNames;
     };
   in
-    # Top-level arg is the builder system (not the target system!)
-    nixpkgs.lib.genAttrs flake-utils.lib.defaultSystems (system: let
+    let
       withData = data: rec {
         root = nixpkgs.lib.evalModules {
           modules = (import ../modules/fleet/_modules.nix) ++ [config data];
@@ -36,21 +35,7 @@
                 inherit name;
                 value = nixpkgs.lib.nixosSystem {
                   system = configuredHosts.${name}.system;
-                  modules =
-                    configuredHosts.${name}.modules
-                    ++ extraModules
-                    ++ [
-                      ({...}: {
-                        nixpkgs.system = system;
-                        nixpkgs.localSystem.system = system;
-                        nixpkgs.crossSystem =
-                          if system == configuredHosts.${name}.system
-                          then null
-                          else {
-                            system = configuredHosts.${name}.system;
-                          };
-                      })
-                    ];
+                  modules = configuredHosts.${name}.modules ++ extraModules;
                   specialArgs = {
                     inherit fleetLib;
                     fleet = fleetLib.hostsToAttrs (host: configuredSystems.${host}.config);
@@ -60,19 +45,28 @@
             )
             (builtins.attrNames rootAssertWarn.config.hosts)
           );
-        buildSystems = {
+        buildSystems = {localSystem}: let
+          buildConfigurationModule = {config, ...}: {
+            # Equivalent to nixpkgs.localSystem
+            # nixpkgs.system = localSystem;
+            nixpkgs.buildPlatform.system = localSystem;
+          };
+        in {
           toplevel = builtins.mapAttrs (_name: value: value.config.system.build.toplevel) (configuredSystemsWithExtraModules [
+            buildConfigurationModule
             ({...}: {
               buildTarget = "toplevel";
             })
           ]);
           sdImage = builtins.mapAttrs (_name: value: value.config.system.build.sdImage) (configuredSystemsWithExtraModules [
+            buildConfigurationModule
             #(nixpkgs + "/nixos/modules/installer/sd-card/sd-image-aarch64-installer.nix")
             ({...}: {
               buildTarget = "sd-image";
             })
           ]);
           installationCd = builtins.mapAttrs (_name: value: value.config.system.build.isoImage) (configuredSystemsWithExtraModules [
+            buildConfigurationModule
             (nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix")
             ({lib, ...}: {
               buildTarget = "installation-cd";
@@ -91,5 +85,5 @@
       in {
         inherit (injectedData) configuredHosts configuredSecrets configuredSystems buildSystems configUnchecked;
       };
-    });
+    };
 }