From e0465567b2dc836896844ca2bcc7477e716489c6 Mon Sep 17 00:00:00 2001 From: "Jason R. McNeil" Date: Fri, 9 Apr 2021 23:43:31 -0700 Subject: [PATCH] eval.nix: Adds meta.machinesFile option that is passed to Nix as builders argument --- README.md | 9 +++++++++ src/command/apply.rs | 4 +++- src/command/apply_local.rs | 3 ++- src/nix/deployment.rs | 3 ++- src/nix/eval.nix | 20 ++++++++++++++++++++ src/nix/hive.rs | 26 ++++++++++++++++++++++++++ src/nix/host/local.rs | 6 +++++- src/nix/host/mod.rs | 4 ++-- 8 files changed, 69 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ee8355c..a8571c3 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,15 @@ Here is a sample `hive.nix` with two nodes, with some common configurations appl nodeNixpkgs = { node-b = ./another-nixos-checkout; }; + + # If your Colmena host has nix configured to allow for remote builds + # (for nix-daemon, your user being included in trusted-users) + # you can set a machines file that will be passed to the underlying + # nix-store command during derivation realization as a builders option. + # For example, if you support multiple orginizations each with their own + # build machine(s) you can ensure that builds only take place on your + # local machine and/or the machines specified in this file. + # machinesFile = ./machines.client-a; }; defaults = { pkgs, ... }: { diff --git a/src/command/apply.rs b/src/command/apply.rs index 5438326..8665681 100644 --- a/src/command/apply.rs +++ b/src/command/apply.rs @@ -115,6 +115,8 @@ pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) { log::info!("Enumerating nodes..."); let all_nodes = hive.deployment_info().await.unwrap(); + let nix_options = hive.nix_options().await.unwrap(); + let selected_nodes = match local_args.value_of("on") { Some(filter) => { util::filter_nodes(&all_nodes, filter) @@ -159,7 +161,7 @@ pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) { if build_only { targets.insert( node.clone(), - Target::new(localhost(), config.clone()), + Target::new(localhost(nix_options.clone()), config.clone()), ); } } diff --git a/src/command/apply_local.rs b/src/command/apply_local.rs index e6f6f1e..dc1d18d 100644 --- a/src/command/apply_local.rs +++ b/src/command/apply_local.rs @@ -100,13 +100,14 @@ pub async fn run(_global_args: &ArgMatches<'_>, local_args: &ArgMatches<'_>) { let target: Target = { if let Some(info) = hive.deployment_info_for(&hostname).await.unwrap() { + let nix_options = hive.nix_options().await.unwrap(); if !info.allows_local_deployment() { log::error!("Local deployment is not enabled for host {}.", hostname); log::error!("Hint: Set deployment.allowLocalDeployment to true."); quit::with_code(2); } Target::new( - host::local(), + host::local(nix_options), info.clone(), ) } else { diff --git a/src/nix/deployment.rs b/src/nix/deployment.rs index 6ac29c2..4d0d96b 100644 --- a/src/nix/deployment.rs +++ b/src/nix/deployment.rs @@ -460,8 +460,9 @@ impl Deployment { } async fn build_profiles(self: Arc, chunk: &Vec, derivation: StoreDerivation, progress: TaskProgress) -> Option { + let nix_options = self.hive.nix_options().await.unwrap(); // FIXME: Remote build? - let mut builder = host::local(); + let mut builder = host::local(nix_options); builder.set_progress_bar(progress.clone()); diff --git a/src/nix/eval.nix b/src/nix/eval.nix index ffee416..0eb8e18 100644 --- a/src/nix/eval.nix +++ b/src/nix/eval.nix @@ -48,6 +48,25 @@ let type = types.attrsOf types.unspecified; default = {}; }; + machinesFile = lib.mkOption { + description = '' + Use the machines listed in this file when building this hive configuration. + + If your Colmena host has nix configured to allow for remote builds + (for nix-daemon, your user being included in trusted-users) + you can set a machines file that will be passed to the underlying + nix-store command during derivation realization as a builders option. + For example, if you support multiple orginizations each with their own + build machine(s) you can ensure that builds only take place on your + local machine and/or the machines specified in this file. + + See https://nixos.org/manual/nix/stable/#chap-distributed-builds + for the machine specification format. + ''; + default = null; + apply = value: if value == null then null else toString value; + type = types.nullOr types.path; + }; }; }; @@ -311,4 +330,5 @@ let }; in { inherit nodes deploymentConfigJson toplevel buildAll buildSelected introspect; + meta = hive.meta; } diff --git a/src/nix/hive.rs b/src/nix/hive.rs index 514bf43..3774176 100644 --- a/src/nix/hive.rs +++ b/src/nix/hive.rs @@ -42,6 +42,23 @@ impl Hive { self.show_trace = value; } + pub async fn nix_options(&self) -> NixResult> { + let mut options:Vec = Vec::new(); + if let Some(machines_file) = self.machines_file().await.unwrap() { + options.append(&mut vec![ + "--option".to_owned(), + "builders".to_owned(), + format!("@{}", machines_file).to_owned() + ]); + } + + if self.show_trace { + options.push("--show-trace".to_owned()) + } + + Ok(options) + } + pub fn as_path(&self) -> &Path { &self.hive } @@ -62,6 +79,15 @@ impl Hive { Ok(configs) } + /// Retrieve machinesFile setting for the hive. + pub async fn machines_file(&self) -> NixResult> { + let expr = "toJSON (hive.meta.machinesFile or null)"; + let s: String = self.nix_instantiate(&expr).eval() + .capture_json().await?; + + Ok(serde_json::from_str(&s).unwrap()) + } + /// Retrieve deployment info for a single node. pub async fn deployment_info_for(&self, node: &str) -> NixResult> { let expr = format!("toJSON (hive.nodes.\"{}\".config.deployment or null)", node); diff --git a/src/nix/host/local.rs b/src/nix/host/local.rs index 2a092b6..b513f0d 100644 --- a/src/nix/host/local.rs +++ b/src/nix/host/local.rs @@ -18,13 +18,15 @@ use crate::progress::TaskProgress; pub struct Local { progress_bar: TaskProgress, logs: String, + nix_options: Vec, } impl Local { - pub fn new() -> Self { + pub fn new(nix_options: Vec) -> Self { Self { progress_bar: TaskProgress::default(), logs: String::new(), + nix_options, } } } @@ -36,6 +38,8 @@ impl Host for Local { } async fn realize_remote(&mut self, derivation: &StorePath) -> NixResult> { let mut command = Command::new("nix-store"); + + command.args(self.nix_options.clone()); command .arg("--no-gc-warning") .arg("--realise") diff --git a/src/nix/host/mod.rs b/src/nix/host/mod.rs index c3e54ec..6f73179 100644 --- a/src/nix/host/mod.rs +++ b/src/nix/host/mod.rs @@ -13,8 +13,8 @@ pub use local::Local; mod key_uploader; -pub(crate) fn local() -> Box { - Box::new(Local::new()) +pub(crate) fn local(nix_options: Vec) -> Box { + Box::new(Local::new(nix_options)) } #[derive(Copy, Clone, Debug)]