difftreelog
feat parallel host builds
in: trunk
6 files changed
cmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/build_systems.rs
+++ b/cmds/fleet/src/cmds/build_systems.rs
@@ -1,6 +1,6 @@
use std::{env::current_dir, time::Duration};
-use crate::{command::CommandExt, host::Config, nix::SYSTEMS_ATTRIBUTE};
+use crate::{command::CommandExt, host::Config};
use anyhow::Result;
use structopt::StructOpt;
use tokio::{process::Command, task::LocalSet, time::sleep};
@@ -21,6 +21,8 @@
privileged_build: bool,
#[structopt(subcommand)]
subcommand: Subcommand,
+ #[structopt(long)]
+ show_trace: bool,
}
enum UploadAction {
@@ -79,6 +81,137 @@
}
impl BuildSystems {
+ async fn build_task(self, config: Config, host: String) -> Result<()> {
+ info!("building");
+ let built = {
+ let dir = tempfile::tempdir()?;
+ dir.path().to_owned()
+ };
+
+ let mut nix_build = if self.privileged_build {
+ let mut out = Command::new("sudo");
+ out.arg("nix");
+ out
+ } else {
+ Command::new("nix")
+ };
+ nix_build
+ .args(&[
+ "build",
+ "--impure",
+ "--json",
+ // "--show-trace",
+ "--no-link",
+ "--out-link",
+ ])
+ .arg(&built)
+ .arg(config.configuration_attr_name(&format!(
+ "configuredSystems.{}.config.system.build.toplevel",
+ host
+ )));
+
+ if self.show_trace {
+ nix_build.arg("--show-trace");
+ }
+ if let Some(builders) = &self.builders {
+ nix_build.arg("--builders").arg(builders);
+ }
+ if let Some(jobs) = &self.jobs {
+ nix_build.arg("--max-jobs");
+ nix_build.arg(format!("{}", jobs));
+ }
+ if !self.fail_fast {
+ nix_build.arg("--keep-going");
+ }
+
+ nix_build.run_nix().await?;
+ let built = std::fs::canonicalize(built)?;
+
+ let action = Action::from(self.subcommand.clone());
+
+ match action {
+ Action::Upload(action) => {
+ if !config.is_local(&host) {
+ info!("uploading system closure");
+ let mut tries = 0;
+ loop {
+ match Command::new("nix")
+ .args(&["copy", "--to"])
+ .arg(format!("ssh://root@{}", host))
+ .arg(&built)
+ .inherit_stdio()
+ .run_nix()
+ .await
+ {
+ Ok(()) => break,
+ Err(e) if tries < 3 => {
+ tries += 1;
+ warn!("Copy failure ({}/3): {}", tries, e);
+ sleep(Duration::from_millis(5000)).await;
+ }
+ Err(e) => return Err(e),
+ }
+ }
+ }
+ if let Some(action) = action {
+ if action.should_switch_profile() {
+ info!("switching generation");
+ config
+ .command_on(&host, "nix-env", true)
+ .args(&["-p", "/nix/var/nix/profiles/system", "--set"])
+ .arg(&built)
+ .inherit_stdio()
+ .run()
+ .await?;
+ }
+ info!("executing activation script");
+ let mut switch_script = built.clone();
+ switch_script.push("bin");
+ switch_script.push("switch-to-configuration");
+ config
+ .command_on(&host, switch_script, true)
+ .arg(action.name())
+ .inherit_stdio()
+ .run()
+ .await?;
+ }
+ }
+ Action::Package(PackageAction::SdImage) => {
+ let mut out = current_dir()?;
+ out.push(format!("sd-image-{}", host));
+
+ info!("building sd image to {:?}", out);
+ let mut nix_build = if self.privileged_build {
+ let mut out = Command::new("sudo");
+ out.arg("nix");
+ out
+ } else {
+ Command::new("nix")
+ };
+ nix_build
+ .args(&["build", "--impure", "--no-link", "--out-link"])
+ .arg(&out)
+ .arg(config.configuration_attr_name(&format!(
+ "configuredSystems.{}.config.system.build.sdImage",
+ host,
+ )));
+ if let Some(builders) = &self.builders {
+ nix_build.arg("--builders").arg(builders);
+ }
+ if let Some(jobs) = &self.jobs {
+ nix_build.arg("--max-jobs");
+ nix_build.arg(format!("{}", jobs));
+ }
+ if !self.fail_fast {
+ nix_build.arg("--keep-going");
+ }
+
+ nix_build.inherit_stdio().run_nix().await?;
+ }
+ };
+ Ok(())
+ }
+
pub async fn run(self, config: &Config) -> Result<()> {
let hosts = config.list_hosts().await?;
let set = LocalSet::new();
@@ -93,139 +226,12 @@
let span = info_span!("deployment", host = field::display(&host));
set.spawn_local(
(async move {
- let res: Result<()> = try {
- info!("building");
- let built = {
- let dir = tempfile::tempdir()?;
- dir.path().to_owned()
- };
-
- let mut nix_build = if this.privileged_build {
- let mut out = Command::new("sudo");
- out.arg("nix");
- out
- } else {
- Command::new("nix")
- };
- nix_build
- .args(&[
- "build",
- "--impure",
- "--json",
- // "--show-trace",
- "--no-link",
- "--out-link",
- ])
- .arg(&built)
- .arg(format!(
- "{}.{}.config.system.build.toplevel",
- SYSTEMS_ATTRIBUTE, host,
- ));
-
- if let Some(builders) = &this.builders {
- nix_build.arg("--builders").arg(builders);
- }
- if let Some(jobs) = &this.jobs {
- nix_build.arg("--max-jobs");
- nix_build.arg(format!("{}", jobs));
- }
- if !this.fail_fast {
- nix_build.arg("--keep-going");
- }
-
- nix_build.run_nix().await?;
- let built = std::fs::canonicalize(built)?;
-
- let action = Action::from(this.subcommand.clone());
-
- match action {
- Action::Upload(action) => {
- if !config.is_local(&host) {
- info!("uploading system closure");
- let mut tries = 0;
- loop {
- match Command::new("nix")
- .args(&["copy", "--to"])
- .arg(format!("ssh://root@{}", host))
- .arg(&built)
- .inherit_stdio()
- .run_nix()
- .await
- {
- Ok(()) => break,
- Err(e) if tries < 3 => {
- tries += 1;
- warn!("Copy failure ({}/3): {}", tries, e);
- sleep(Duration::from_millis(5000)).await;
- }
- Err(e) => return Err(e),
- }
- }
- }
- if let Some(action) = action {
- if action.should_switch_profile() {
- info!("switching generation");
- config
- .command_on(&host, "nix-env", true)
- .args(&["-p", "/nix/var/nix/profiles/system", "--set"])
- .arg(&built)
- .inherit_stdio()
- .run()
- .await?;
- }
- info!("executing activation script");
- let mut switch_script = built.clone();
- switch_script.push("bin");
- switch_script.push("switch-to-configuration");
- config
- .command_on(&host, switch_script, true)
- .arg(action.name())
- .inherit_stdio()
- .run()
- .await?;
- }
- }
- Action::Package(PackageAction::SdImage) => {
- let mut out = current_dir()?;
- out.push(format!("sd-image-{}", host));
-
- info!("building sd image to {:?}", out);
- let mut nix_build = if this.privileged_build {
- let mut out = Command::new("sudo");
- out.arg("nix");
- out
- } else {
- Command::new("nix")
- };
- nix_build
- .args(&["build", "--impure", "--no-link", "--out-link"])
- .arg(&out)
- .arg(format!(
- "{}.{}.config.system.build.sdImage",
- SYSTEMS_ATTRIBUTE, host,
- ));
- if let Some(builders) = &this.builders {
- nix_build.arg("--builders").arg(builders);
- }
- if let Some(jobs) = &this.jobs {
- nix_build.arg("--max-jobs");
- nix_build.arg(format!("{}", jobs));
- }
- if !this.fail_fast {
- nix_build.arg("--keep-going");
- }
-
- nix_build.inherit_stdio().run_nix().await?;
- }
- };
- };
- match res {
+ match this.build_task(config, host).await {
Ok(_) => {}
Err(e) => {
error!("failed to deploy host: {}", e)
}
}
- Ok(())
})
.instrument(span),
);
cmds/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.rsdiffbeforeafterbothno changes
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);
+ };
};
}
)