difftreelog
feat parallel host builds
in: trunk
6 files changed
cmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth1use std::{env::current_dir, time::Duration};1use std::{env::current_dir, time::Duration};223use crate::{command::CommandExt, host::Config, nix::SYSTEMS_ATTRIBUTE};3use crate::{command::CommandExt, host::Config};4use anyhow::Result;4use anyhow::Result;5use structopt::StructOpt;5use structopt::StructOpt;6use tokio::{process::Command, task::LocalSet, time::sleep};6use tokio::{process::Command, task::LocalSet, time::sleep};21 privileged_build: bool,21 privileged_build: bool,22 #[structopt(subcommand)]22 #[structopt(subcommand)]23 subcommand: Subcommand,23 subcommand: Subcommand,24 #[structopt(long)]25 show_trace: bool,24}26}252726enum UploadAction {28enum UploadAction {79}81}808281impl BuildSystems {83impl BuildSystems {82 pub async fn run(self, config: &Config) -> Result<()> {84 async fn build_task(self, config: Config, host: String) -> Result<()> {83 let hosts = config.list_hosts().await?;84 let set = LocalSet::new();85 let this = &self;86 for host in hosts.iter() {87 if config.should_skip(host) {88 continue;89 }90 let config = config.clone();91 let host = host.clone();92 let this = this.clone();93 let span = info_span!("deployment", host = field::display(&host));94 set.spawn_local(95 (async move {96 let res: Result<()> = try {97 info!("building");85 info!("building");98 let built = {86 let built = {99 let dir = tempfile::tempdir()?;87 let dir = tempfile::tempdir()?;100 dir.path().to_owned()88 dir.path().to_owned()101 };89 };10290103 let mut nix_build = if this.privileged_build {91 let mut nix_build = if self.privileged_build {104 let mut out = Command::new("sudo");92 let mut out = Command::new("sudo");105 out.arg("nix");93 out.arg("nix");106 out94 out117 "--out-link",105 "--out-link",118 ])106 ])119 .arg(&built)107 .arg(&built)120 .arg(format!(108 .arg(config.configuration_attr_name(&format!(121 "{}.{}.config.system.build.toplevel",109 "configuredSystems.{}.config.system.build.toplevel",122 SYSTEMS_ATTRIBUTE, host,110 host123 ));111 )));124112113 if self.show_trace {114 nix_build.arg("--show-trace");115 }125 if let Some(builders) = &this.builders {116 if let Some(builders) = &self.builders {126 nix_build.arg("--builders").arg(builders);117 nix_build.arg("--builders").arg(builders);127 }118 }128 if let Some(jobs) = &this.jobs {119 if let Some(jobs) = &self.jobs {129 nix_build.arg("--max-jobs");120 nix_build.arg("--max-jobs");130 nix_build.arg(format!("{}", jobs));121 nix_build.arg(format!("{}", jobs));131 }122 }132 if !this.fail_fast {123 if !self.fail_fast {133 nix_build.arg("--keep-going");124 nix_build.arg("--keep-going");134 }125 }135126136 nix_build.run_nix().await?;127 nix_build.run_nix().await?;137 let built = std::fs::canonicalize(built)?;128 let built = std::fs::canonicalize(built)?;138129139 let action = Action::from(this.subcommand.clone());130 let action = Action::from(self.subcommand.clone());140131141 match action {132 match action {142 Action::Upload(action) => {133 Action::Upload(action) => {190 out.push(format!("sd-image-{}", host));181 out.push(format!("sd-image-{}", host));191182192 info!("building sd image to {:?}", out);183 info!("building sd image to {:?}", out);193 let mut nix_build = if this.privileged_build {184 let mut nix_build = if self.privileged_build {194 let mut out = Command::new("sudo");185 let mut out = Command::new("sudo");195 out.arg("nix");186 out.arg("nix");196 out187 out200 nix_build191 nix_build201 .args(&["build", "--impure", "--no-link", "--out-link"])192 .args(&["build", "--impure", "--no-link", "--out-link"])202 .arg(&out)193 .arg(&out)203 .arg(format!(194 .arg(config.configuration_attr_name(&format!(204 "{}.{}.config.system.build.sdImage",195 "configuredSystems.{}.config.system.build.sdImage",205 SYSTEMS_ATTRIBUTE, host,196 host,206 ));197 )));207 if let Some(builders) = &this.builders {198 if let Some(builders) = &self.builders {208 nix_build.arg("--builders").arg(builders);199 nix_build.arg("--builders").arg(builders);209 }200 }210 if let Some(jobs) = &this.jobs {201 if let Some(jobs) = &self.jobs {211 nix_build.arg("--max-jobs");202 nix_build.arg("--max-jobs");212 nix_build.arg(format!("{}", jobs));203 nix_build.arg(format!("{}", jobs));213 }204 }214 if !this.fail_fast {205 if !self.fail_fast {215 nix_build.arg("--keep-going");206 nix_build.arg("--keep-going");216 }207 }217208218 nix_build.inherit_stdio().run_nix().await?;209 nix_build.inherit_stdio().run_nix().await?;219 }210 }220 };211 };221 };222 match res {223 Ok(_) => {}224 Err(e) => {225 error!("failed to deploy host: {}", e)226 }227 }228 Ok(())229 })230 .instrument(span),231 );232 }233 set.await;234 Ok(())212 Ok(())235 }213 }214215 pub async fn run(self, config: &Config) -> Result<()> {216 let hosts = config.list_hosts().await?;217 let set = LocalSet::new();218 let this = &self;219 for host in hosts.iter() {220 if config.should_skip(host) {221 continue;222 }223 let config = config.clone();224 let host = host.clone();225 let this = this.clone();226 let span = info_span!("deployment", host = field::display(&host));227 set.spawn_local(228 (async move {229 match this.build_task(config, host).await {230 Ok(_) => {}231 Err(e) => {232 error!("failed to deploy host: {}", e)233 }234 }235 })236 .instrument(span),237 );238 }239 set.await;240 Ok(())241 }236}242}237243cmds/fleet/src/command.rsdiffbeforeafterboth--- a/cmds/fleet/src/command.rs
+++ b/cmds/fleet/src/command.rs
@@ -150,6 +150,12 @@
info!(target: "nix", "{}", text)
}
},
+ NixLog::Start { text, level: 0, typ: 108, .. } if text == "" => {
+ // Cache lookup? Coupled with copy log
+ },
+ NixLog::Start { text, level: 4, typ: 101, .. } if text.starts_with("downloading ") => {
+ // NAR downloading, coupled with copy log
+ }
NixLog::Stop { .. } => {},
NixLog::Result { .. } => {},
_ => warn!("unknown log: {:?}", log)
cmds/fleet/src/host.rsdiffbeforeafterboth--- a/cmds/fleet/src/host.rs
+++ b/cmds/fleet/src/host.rs
@@ -16,6 +16,7 @@
use crate::{command::CommandExt, fleetdata::FleetData};
pub struct FleetConfigInternals {
+ pub local_system: String,
pub directory: PathBuf,
pub opts: FleetOpts,
pub data: RefCell<FleetData>,
@@ -66,17 +67,21 @@
}
}
- pub fn full_attr_name(&self, attr_name: &str) -> OsString {
+ pub fn configuration_attr_name(&self, name: &str) -> OsString {
let mut str = self.directory.as_os_str().to_owned();
str.push("#");
- str.push(attr_name);
+ str.push(&format!(
+ "fleetConfigurations.default.{}.{}",
+ self.local_system,
+ name
+ ));
str
}
pub async fn list_hosts(&self) -> Result<Vec<String>> {
Command::new("nix")
.arg("eval")
- .arg(self.full_attr_name("fleetConfigurations.default.configuredHosts"))
+ .arg(self.configuration_attr_name("configuredHosts"))
.args(&["--apply", "builtins.attrNames", "--json", "--show-trace"])
.run_nix_json()
.await
@@ -84,10 +89,7 @@
pub async fn config_attr<T: DeserializeOwned>(&self, host: &str, attr: &str) -> Result<T> {
Command::new("nix")
.arg("eval")
- .arg(self.full_attr_name(&format!(
- "fleetConfigurations.default.configuredSystems.{}.config.{}",
- host, attr
- )))
+ .arg(self.configuration_attr_name(&format!("configuredSystems.{}.config.{}", host, attr)))
.args(&["--json", "--show-trace"])
.run_nix_json()
.await
@@ -129,10 +131,14 @@
/// Host, which should be threaten as current machine
#[structopt(long)]
pub localhost: Option<String>,
+
+ #[structopt(long, default_value = "x86_64-linux")]
+ pub local_system: String,
}
impl FleetOpts {
pub fn build(mut self) -> Result<Config> {
+ let local_system = self.local_system.clone();
if self.localhost.is_none() {
self.localhost
.replace(hostname::get().unwrap().to_str().unwrap().to_owned());
@@ -148,6 +154,7 @@
opts: self,
directory,
data,
+ local_system,
})))
}
}
cmds/fleet/src/main.rsdiffbeforeafterboth--- a/cmds/fleet/src/main.rs
+++ b/cmds/fleet/src/main.rs
@@ -1,11 +1,7 @@
-#![feature(try_blocks)]
-
pub mod command;
pub mod host;
pub mod keys;
-
pub mod cmds;
-pub mod nix;
mod fleetdata;
cmds/fleet/src/nix.rsdiffbeforeafterboth--- a/cmds/fleet/src/nix.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-pub const HOSTS_ATTRIBUTE: &str = ".#fleetConfigurations.default.configuredHosts";
-pub const SECRETS_ATTRIBUTE: &str = ".#fleetConfigurations.default.configuredSecrets";
-pub const SYSTEMS_ATTRIBUTE: &str = ".#fleetConfigurations.default.configuredSystems";
lib/default.nixdiffbeforeafterboth--- a/lib/default.nix
+++ b/lib/default.nix
@@ -2,15 +2,16 @@
fleetConfiguration = { data, nixpkgs, hosts, ... }@allConfig:
let
config = builtins.removeAttrs allConfig [ "nixpkgs" "data" ];
+ fleetLib = import ./fleetLib.nix {
+ inherit nixpkgs hosts;
+ };
in
- flake-utils.lib.eachDefaultSystem (system: rec {
+ nixpkgs.lib.genAttrs flake-utils.lib.defaultSystems (system: rec {
root = nixpkgs.lib.evalModules {
modules = (import ../modules/fleet/_modules.nix) ++ [ config data ];
specialArgs = {
inherit nixpkgs;
- fleet = import ./fleetLib.nix {
- inherit nixpkgs hosts;
- };
+ fleet = fleetLib;
};
};
configuredHosts = root.config.hosts;
@@ -27,12 +28,16 @@
else [ ]
) ++ [
({ ... }: {
+ nixpkgs.system = system;
nixpkgs.localSystem.system = system;
nixpkgs.crossSystem = if system == configuredHosts.${name}.system then null else {
system = configuredHosts.${name}.system;
};
})
];
+ specialArgs = {
+ fleet = fleetLib.hostsToAttrs (host: configuredSystems.${host}.config);
+ };
};
}
)