git.delta.rocks / jrsonnet / refs/commits / 4e7930a0a457

difftreelog

feat build specializations

Yaroslav Bolyukin2022-12-09parent: #38d1791.patch.diff
in: trunk

2 files changed

modifiedcmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth
after · cmds/fleet/src/cmds/build_systems.rs
1use std::{env::current_dir, process::Stdio, time::Duration};23use crate::{command::CommandExt, host::Config};4use anyhow::Result;5use clap::Parser;6use tokio::{process::Command, task::LocalSet, time::sleep};7use tracing::{error, field, info, info_span, warn, Instrument};89#[derive(Parser, Clone)]10pub struct BuildSystems {11	/// Jobs to run locally12	#[clap(long)]13	jobs: Option<usize>,14	/// Do not continue on error15	#[clap(long)]16	fail_fast: bool,17	/// Run builds as sudo18	#[clap(long)]19	privileged_build: bool,20	#[clap(subcommand)]21	subcommand: Subcommand,2223	/// --builders arg for nix24	#[clap(long)]25	builders: Option<String>,26	/// --show-trace arg for nix27	#[structopt(long)]28	show_trace: bool,29}3031enum UploadAction {32	Test,33	Boot,34	Switch,35}36impl UploadAction {37	fn name(&self) -> &'static str {38		match self {39			UploadAction::Test => "test",40			UploadAction::Boot => "boot",41			UploadAction::Switch => "switch",42		}43	}4445	pub(crate) fn should_switch_profile(&self) -> bool {46		matches!(self, Self::Switch | Self::Test)47	}48}4950enum PackageAction {51	SdImage,52	InstallationCd,53}54impl PackageAction {55	fn build_attr(&self) -> String {56		match self {57			PackageAction::SdImage => "sdImage".to_owned(),58			PackageAction::InstallationCd => "installationCd".to_owned(),59		}60	}61}6263enum Action {64	Upload { action: Option<UploadAction> },65	Package(PackageAction),66}67impl Action {68	fn build_attr(&self) -> String {69		match self {70			Action::Upload { .. } => "toplevel".to_owned(),71			Action::Package(p) => p.build_attr(),72		}73	}74}7576impl From<Subcommand> for Action {77	fn from(s: Subcommand) -> Self {78		match s {79			Subcommand::Upload => Self::Upload { action: None },80			Subcommand::Test => Self::Upload {81				action: Some(UploadAction::Test),82			},83			Subcommand::Boot => Self::Upload {84				action: Some(UploadAction::Boot),85			},86			Subcommand::Switch => Self::Upload {87				action: Some(UploadAction::Switch),88			},89			Subcommand::SdImage => Self::Package(PackageAction::SdImage),90			Subcommand::InstallationCd => Self::Package(PackageAction::InstallationCd),91		}92	}93}9495#[derive(Parser, Clone)]96enum Subcommand {97	/// Upload, but do not switch98	Upload,99	/// Upload + switch to built system until reboot100	Test,101	/// Upload + switch to built system after reboot102	Boot,103	/// Upload + test + boot104	Switch,105106	/// Build SD .img image107	SdImage,108	/// Build an installation cd ISO image109	InstallationCd,110}111112impl BuildSystems {113	async fn build_task(self, config: Config, host: String) -> Result<()> {114		info!("building");115		let action = Action::from(self.subcommand.clone());116		let built = {117			let dir = tempfile::tempdir()?;118			dir.path().to_owned()119		};120121		let mut nix_build = if self.privileged_build {122			let mut out = Command::new("sudo");123			out.arg("nix");124			out125		} else {126			Command::new("nix")127		};128		nix_build129			.args(&[130				"build",131				"--impure",132				"--json",133				// "--show-trace",134				"--no-link",135				"--out-link",136			])137			.arg(&built)138			.arg(139				config.configuration_attr_name(&format!(140					"buildSystems.{}.{host}",141					action.build_attr()142				)),143			);144145		if self.show_trace {146			nix_build.arg("--show-trace");147		}148		if let Some(builders) = &self.builders {149			nix_build.arg("--builders").arg(builders);150		}151		if let Some(jobs) = &self.jobs {152			nix_build.arg("--max-jobs");153			nix_build.arg(format!("{}", jobs));154		}155		if !self.fail_fast {156			nix_build.arg("--keep-going");157		}158159		nix_build.run_nix().await?;160		let built = std::fs::canonicalize(built)?;161162		match action {163			Action::Upload { action } => {164				if !config.is_local(&host) {165					info!("uploading system closure");166					let mut tries = 0;167					loop {168						match Command::new("nix")169							.args(&["copy", "--to"])170							.arg(format!("ssh://root@{}", host))171							.arg(&built)172							.inherit_stdio()173							.run_nix()174							.await175						{176							Ok(()) => break,177							Err(e) if tries < 3 => {178								tries += 1;179								warn!("Copy failure ({}/3): {}", tries, e);180								sleep(Duration::from_millis(5000)).await;181							}182							Err(e) => return Err(e),183						}184					}185				}186				if let Some(action) = action {187					if action.should_switch_profile() {188						info!("switching generation");189						config190							.command_on(&host, "nix-env", true)191							.args(&["-p", "/nix/var/nix/profiles/system", "--set"])192							.arg(&built)193							.inherit_stdio()194							.run()195							.await?;196					}197					info!("executing activation script");198					let mut switch_script = built.clone();199					switch_script.push("bin");200					switch_script.push("switch-to-configuration");201					config202						.command_on(&host, switch_script, true)203						.arg(action.name())204						.stdout(Stdio::inherit())205						.run()206						.await?;207				}208			}209			Action::Package(PackageAction::SdImage) => {210				let mut out = current_dir()?;211				out.push(format!("sd-image-{}", host));212213				info!("building sd image to {:?}", out);214				let mut nix_build = if self.privileged_build {215					let mut out = Command::new("sudo");216					out.arg("nix");217					out218				} else {219					Command::new("nix")220				};221				nix_build222					.args(&["build", "--impure", "--no-link", "--out-link"])223					.arg(&out)224					.arg(225						config.configuration_attr_name(&format!("buildSystems.sdImage.{}", host,)),226					);227				if let Some(builders) = &self.builders {228					nix_build.arg("--builders").arg(builders);229				}230				if let Some(jobs) = &self.jobs {231					nix_build.arg("--max-jobs");232					nix_build.arg(format!("{}", jobs));233				}234				if !self.fail_fast {235					nix_build.arg("--keep-going");236				}237238				nix_build.inherit_stdio().run_nix().await?;239			}240			Action::Package(PackageAction::InstallationCd) => {241				let mut out = current_dir()?;242				out.push(format!("installation-cd-{}", host));243244				info!("building sd image to {:?}", out);245				let mut nix_build = if self.privileged_build {246					let mut out = Command::new("sudo");247					out.arg("nix");248					out249				} else {250					Command::new("nix")251				};252				nix_build253					.args(&["build", "--impure", "--no-link", "--out-link"])254					.arg(&out)255					.arg(256						config.configuration_attr_name(&format!(257							"buildSystems.installationCd.{}",258							host,259						)),260					);261				if let Some(builders) = &self.builders {262					nix_build.arg("--builders").arg(builders);263				}264				if let Some(jobs) = &self.jobs {265					nix_build.arg("--max-jobs");266					nix_build.arg(format!("{}", jobs));267				}268				if !self.fail_fast {269					nix_build.arg("--keep-going");270				}271272				nix_build.inherit_stdio().run_nix().await?;273			}274		};275		Ok(())276	}277278	pub async fn run(self, config: &Config) -> Result<()> {279		let hosts = config.list_hosts().await?;280		let set = LocalSet::new();281		let this = &self;282		for host in hosts.iter() {283			if config.should_skip(host) {284				continue;285			}286			let config = config.clone();287			let host = host.clone();288			let this = this.clone();289			let span = info_span!("deployment", host = field::display(&host));290			set.spawn_local(291				(async move {292					match this.build_task(config, host).await {293						Ok(_) => {}294						Err(e) => {295							error!("failed to deploy host: {}", e)296						}297					}298				})299				.instrument(span),300			);301		}302		set.await;303		Ok(())304	}305}
modifiedlib/default.nixdiffbeforeafterboth
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -20,21 +20,17 @@
           if failedAssertions != [ ]
           then throw "Failed assertions:\n${nixpkgs.lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}"
           else nixpkgs.lib.showWarnings root.config.warnings root;
-      in
-      rec {
         configuredHosts = rootAssertWarn.config.hosts;
         configuredSecrets = rootAssertWarn.config.secrets;
-        configuredSystems = nixpkgs.lib.listToAttrs (
+        configuredSystems = configuredSystemsWithExtraModules [ ];
+        configuredSystemsWithExtraModules = extraModules: nixpkgs.lib.listToAttrs (
           map
             (
               name: {
                 inherit name;
                 value = nixpkgs.lib.nixosSystem {
                   system = configuredHosts.${name}.system;
-                  modules = configuredHosts.${name}.modules ++ (
-                    if configuredHosts.${name}.system == "aarch64-linux" then [ (nixpkgs + "/nixos/modules/installer/sd-card/sd-image-aarch64-installer.nix") ]
-                    else [ ]
-                  ) ++ [
+                  modules = configuredHosts.${name}.modules ++ extraModules ++ [
                     ({ ... }: {
                       nixpkgs.system = system;
                       nixpkgs.localSystem.system = system;
@@ -51,6 +47,22 @@
               }
             )
             (builtins.attrNames rootAssertWarn.config.hosts)
-        ); #nixpkgs.lib.nixosSystem {}
+        );
+      in
+      rec {
+        inherit configuredHosts configuredSecrets configuredSystems;
+        buildSystems = {
+          toplevel = builtins.mapAttrs (_name: value: value.config.system.build.toplevel) (configuredSystemsWithExtraModules [ ]);
+          sdImage = builtins.mapAttrs (_name: value: value.config.system.build.sdImage) (configuredSystemsWithExtraModules [
+            (nixpkgs + "/nixos/modules/installer/sd-card/sd-image-aarch64-installer.nix")
+          ]);
+          installationCd = builtins.mapAttrs (_name: value: value.config.system.build.isoImage) (configuredSystemsWithExtraModules [
+            (nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix")
+            ({ lib, ... }: {
+              # Needed for https://github.com/NixOS/nixpkgs/issues/58959
+              boot.supportedFilesystems = lib.mkForce [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs" ];
+            })
+          ]);
+        };
       });
 }