git.delta.rocks / jrsonnet / refs/commits / 81e3c77f96ff

difftreelog

feat parallel host builds

Yaroslav Bolyukin2021-12-26parent: #6a5196a.patch.diff
in: trunk

6 files changed

modifiedcmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth
1use std::{env::current_dir, time::Duration};1use std::{env::current_dir, time::Duration};
22
3use 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}
2527
26enum UploadAction {28enum UploadAction {
79}81}
8082
81impl 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 };
10290
103 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 out
117 "--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 host
123 ));111 )));
124112
113 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 }
135126
136 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)?;
138129
139 let action = Action::from(this.subcommand.clone());130 let action = Action::from(self.subcommand.clone());
140131
141 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));
191182
192 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 out
200 nix_build191 nix_build
201 .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 }
217208
218 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 }
214
215 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}
237243
modifiedcmds/fleet/src/command.rsdiffbeforeafterboth
150 info!(target: "nix", "{}", text)150 info!(target: "nix", "{}", text)
151 }151 }
152 },152 },
153 NixLog::Start { text, level: 0, typ: 108, .. } if text == "" => {
154 // Cache lookup? Coupled with copy log
155 },
156 NixLog::Start { text, level: 4, typ: 101, .. } if text.starts_with("downloading ") => {
157 // NAR downloading, coupled with copy log
158 }
153 NixLog::Stop { .. } => {},159 NixLog::Stop { .. } => {},
154 NixLog::Result { .. } => {},160 NixLog::Result { .. } => {},
155 _ => warn!("unknown log: {:?}", log)161 _ => warn!("unknown log: {:?}", log)
modifiedcmds/fleet/src/host.rsdiffbeforeafterboth
16use crate::{command::CommandExt, fleetdata::FleetData};16use crate::{command::CommandExt, fleetdata::FleetData};
1717
18pub struct FleetConfigInternals {18pub struct FleetConfigInternals {
19 pub local_system: String,
19 pub directory: PathBuf,20 pub directory: PathBuf,
20 pub opts: FleetOpts,21 pub opts: FleetOpts,
21 pub data: RefCell<FleetData>,22 pub data: RefCell<FleetData>,
66 }67 }
67 }68 }
6869
69 pub fn full_attr_name(&self, attr_name: &str) -> OsString {70 pub fn configuration_attr_name(&self, name: &str) -> OsString {
70 let mut str = self.directory.as_os_str().to_owned();71 let mut str = self.directory.as_os_str().to_owned();
71 str.push("#");72 str.push("#");
72 str.push(attr_name);73 str.push(&format!(
74 "fleetConfigurations.default.{}.{}",
75 self.local_system,
76 name
77 ));
73 str78 str
74 }79 }
7580
76 pub async fn list_hosts(&self) -> Result<Vec<String>> {81 pub async fn list_hosts(&self) -> Result<Vec<String>> {
77 Command::new("nix")82 Command::new("nix")
78 .arg("eval")83 .arg("eval")
79 .arg(self.full_attr_name("fleetConfigurations.default.configuredHosts"))84 .arg(self.configuration_attr_name("configuredHosts"))
80 .args(&["--apply", "builtins.attrNames", "--json", "--show-trace"])85 .args(&["--apply", "builtins.attrNames", "--json", "--show-trace"])
81 .run_nix_json()86 .run_nix_json()
82 .await87 .await
83 }88 }
84 pub async fn config_attr<T: DeserializeOwned>(&self, host: &str, attr: &str) -> Result<T> {89 pub async fn config_attr<T: DeserializeOwned>(&self, host: &str, attr: &str) -> Result<T> {
85 Command::new("nix")90 Command::new("nix")
86 .arg("eval")91 .arg("eval")
87 .arg(self.full_attr_name(&format!(92 .arg(self.configuration_attr_name(&format!("configuredSystems.{}.config.{}", host, attr)))
88 "fleetConfigurations.default.configuredSystems.{}.config.{}",
89 host, attr
90 )))
91 .args(&["--json", "--show-trace"])93 .args(&["--json", "--show-trace"])
130 #[structopt(long)]132 #[structopt(long)]
131 pub localhost: Option<String>,133 pub localhost: Option<String>,
134
135 #[structopt(long, default_value = "x86_64-linux")]
136 pub local_system: String,
132}137}
133138
134impl FleetOpts {139impl FleetOpts {
135 pub fn build(mut self) -> Result<Config> {140 pub fn build(mut self) -> Result<Config> {
141 let local_system = self.local_system.clone();
136 if self.localhost.is_none() {142 if self.localhost.is_none() {
137 self.localhost143 self.localhost
138 .replace(hostname::get().unwrap().to_str().unwrap().to_owned());144 .replace(hostname::get().unwrap().to_str().unwrap().to_owned());
148 opts: self,154 opts: self,
149 directory,155 directory,
150 data,156 data,
157 local_system,
151 })))158 })))
152 }159 }
153}160}
modifiedcmds/fleet/src/main.rsdiffbeforeafterboth
1#![feature(try_blocks)]
2
3pub mod command;1pub mod command;
4pub mod host;2pub mod host;
5pub mod keys;3pub mod keys;
6
7pub mod cmds;4pub mod cmds;
8pub mod nix;
95
10mod fleetdata;6mod fleetdata;
117
deletedcmds/fleet/src/nix.rsdiffbeforeafterboth

no changes

modifiedlib/default.nixdiffbeforeafterboth
2 fleetConfiguration = { data, nixpkgs, hosts, ... }@allConfig:2 fleetConfiguration = { data, nixpkgs, hosts, ... }@allConfig:
3 let3 let
4 config = builtins.removeAttrs allConfig [ "nixpkgs" "data" ];4 config = builtins.removeAttrs allConfig [ "nixpkgs" "data" ];
5 fleetLib = import ./fleetLib.nix {
6 inherit nixpkgs hosts;
7 };
5 in8 in
6 flake-utils.lib.eachDefaultSystem (system: rec {9 nixpkgs.lib.genAttrs flake-utils.lib.defaultSystems (system: rec {
7 root = nixpkgs.lib.evalModules {10 root = nixpkgs.lib.evalModules {
8 modules = (import ../modules/fleet/_modules.nix) ++ [ config data ];11 modules = (import ../modules/fleet/_modules.nix) ++ [ config data ];
9 specialArgs = {12 specialArgs = {
10 inherit nixpkgs;13 inherit nixpkgs;
11 fleet = import ./fleetLib.nix {14 fleet = fleetLib;
12 inherit nixpkgs hosts;
13 };
14 };15 };
15 };16 };
16 configuredHosts = root.config.hosts;17 configuredHosts = root.config.hosts;
27 else [ ]28 else [ ]
28 ) ++ [29 ) ++ [
29 ({ ... }: {30 ({ ... }: {
31 nixpkgs.system = system;
30 nixpkgs.localSystem.system = system;32 nixpkgs.localSystem.system = system;
31 nixpkgs.crossSystem = if system == configuredHosts.${name}.system then null else {33 nixpkgs.crossSystem = if system == configuredHosts.${name}.system then null else {
32 system = configuredHosts.${name}.system;34 system = configuredHosts.${name}.system;
33 };35 };
34 })36 })
35 ];37 ];
38 specialArgs = {
39 fleet = fleetLib.hostsToAttrs (host: configuredSystems.${host}.config);
40 };
36 };41 };
37 }42 }
38 )43 )