forked from DGNum/colmena
Merge pull request #96 from NeverBehave/feat/metaconfig
feat(meta): add disallowApplyAll options
This commit is contained in:
commit
f35e6dfb7f
10 changed files with 111 additions and 24 deletions
19
integration-tests/allow-apply-all/default.nix
Normal file
19
integration-tests/allow-apply-all/default.nix
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{ pkgs ? import ../nixpkgs.nix }:
|
||||||
|
|
||||||
|
let
|
||||||
|
tools = pkgs.callPackage ../tools.nix {
|
||||||
|
targets = [ "alpha" ];
|
||||||
|
};
|
||||||
|
in tools.makeTest {
|
||||||
|
name = "colmena-allow-apply-all";
|
||||||
|
|
||||||
|
bundle = ./.;
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
logs = deployer.fail("cd /tmp/bundle && run-copy-stderr ${tools.colmenaExec} apply")
|
||||||
|
|
||||||
|
assert "no filter supplied" in logs
|
||||||
|
|
||||||
|
deployer.succeed("cd /tmp/bundle && run-copy-stderr ${tools.colmenaExec} apply --on @target")
|
||||||
|
'';
|
||||||
|
}
|
14
integration-tests/allow-apply-all/hive.nix
Normal file
14
integration-tests/allow-apply-all/hive.nix
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
let
|
||||||
|
tools = import ./tools.nix {
|
||||||
|
insideVm = true;
|
||||||
|
targets = ["alpha"];
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
meta = {
|
||||||
|
nixpkgs = tools.pkgs;
|
||||||
|
allowApplyAll = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
deployer = tools.getStandaloneConfigFor "deployer";
|
||||||
|
alpha = tools.getStandaloneConfigFor "alpha";
|
||||||
|
}
|
|
@ -8,6 +8,8 @@
|
||||||
flakes-streaming = import ./flakes { evaluator = "streaming"; };
|
flakes-streaming = import ./flakes { evaluator = "streaming"; };
|
||||||
parallel = import ./parallel {};
|
parallel = import ./parallel {};
|
||||||
|
|
||||||
|
allow-apply-all = import ./allow-apply-all {};
|
||||||
|
|
||||||
apply-stable = let
|
apply-stable = let
|
||||||
test = import ./apply { pkgs = import ./nixpkgs-stable.nix; };
|
test = import ./apply { pkgs = import ./nixpkgs-stable.nix; };
|
||||||
in test.override (old: {
|
in test.override (old: {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
- In `apply-local`, we now only escalate privileges during activation ([#85](https://github.com/zhaofengli/colmena/issues/85)).
|
- In `apply-local`, we now only escalate privileges during activation ([#85](https://github.com/zhaofengli/colmena/issues/85)).
|
||||||
- Impure overlays are no longer imported by default if a path is specified in `meta.nixpkgs` ([#39](https://github.com/zhaofengli/colmena/issues/39))
|
- Impure overlays are no longer imported by default if a path is specified in `meta.nixpkgs` ([#39](https://github.com/zhaofengli/colmena/issues/39))
|
||||||
- GC roots are now created right after the builds are complete, as opposed to after activation.
|
- GC roots are now created right after the builds are complete, as opposed to after activation.
|
||||||
|
- The [`meta.allowApplyAll`](./reference/meta.md#allowapplyall) option has been added. If set to false, deployments without a node filter (`--on`) are disallowed.
|
||||||
|
|
||||||
## [Release 0.3.0](https://github.com/zhaofengli/colmena/releases/tag/v0.3.0) (2022/04/27)
|
## [Release 0.3.0](https://github.com/zhaofengli/colmena/releases/tag/v0.3.0) (2022/04/27)
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,16 @@ pub async fn run(_global_args: &ArgMatches, local_args: &ArgMatches) -> Result<(
|
||||||
.map(NodeFilter::new)
|
.map(NodeFilter::new)
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
|
if !filter.is_some() {
|
||||||
|
// User did not specify node, we should check meta and see rules
|
||||||
|
let meta = hive.get_meta_config().await?;
|
||||||
|
if !meta.allow_apply_all {
|
||||||
|
log::error!("No node filter is specified and meta.allowApplyAll is set to false.");
|
||||||
|
log::error!("Hint: Filter the nodes with --on.");
|
||||||
|
quit::with_code(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let goal_arg = local_args.value_of("goal").unwrap();
|
let goal_arg = local_args.value_of("goal").unwrap();
|
||||||
let goal = Goal::from_str(goal_arg).unwrap();
|
let goal = Goal::from_str(goal_arg).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -202,11 +202,21 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Add required config Key here since we don't want to eval nixpkgs
|
||||||
|
metaConfigKeys = [
|
||||||
|
"name" "description"
|
||||||
|
"machinesFile"
|
||||||
|
"allowApplyAll"
|
||||||
|
];
|
||||||
|
|
||||||
|
metaConfig = lib.filterAttrs (n: v: elem n metaConfigKeys) hive.meta;
|
||||||
in {
|
in {
|
||||||
inherit
|
inherit
|
||||||
nodes toplevel
|
nodes toplevel
|
||||||
deploymentConfig deploymentConfigSelected
|
deploymentConfig deploymentConfigSelected
|
||||||
evalAll evalSelected evalSelectedDrvPaths introspect;
|
evalAll evalSelected evalSelectedDrvPaths introspect
|
||||||
|
metaConfig;
|
||||||
|
|
||||||
meta = hive.meta;
|
meta = hive.meta;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use std::convert::AsRef;
|
||||||
|
|
||||||
use tempfile::{NamedTempFile, TempPath};
|
use tempfile::{NamedTempFile, TempPath};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::OnceCell;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ use super::{
|
||||||
NodeFilter,
|
NodeFilter,
|
||||||
NixExpression,
|
NixExpression,
|
||||||
ProfileDerivation,
|
ProfileDerivation,
|
||||||
StorePath,
|
StorePath, MetaConfig,
|
||||||
};
|
};
|
||||||
use super::deployment::TargetNode;
|
use super::deployment::TargetNode;
|
||||||
use crate::error::ColmenaResult;
|
use crate::error::ColmenaResult;
|
||||||
|
@ -58,8 +58,7 @@ pub struct Hive {
|
||||||
/// Whether to pass --show-trace in Nix commands.
|
/// Whether to pass --show-trace in Nix commands.
|
||||||
show_trace: bool,
|
show_trace: bool,
|
||||||
|
|
||||||
/// The cached machines_file expression.
|
meta_config: OnceCell<MetaConfig>,
|
||||||
machines_file: RwLock<Option<Option<String>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NixInstantiate<'hive> {
|
struct NixInstantiate<'hive> {
|
||||||
|
@ -113,12 +112,12 @@ impl Hive {
|
||||||
pub fn new(path: HivePath) -> ColmenaResult<Self> {
|
pub fn new(path: HivePath) -> ColmenaResult<Self> {
|
||||||
let context_dir = path.context_dir();
|
let context_dir = path.context_dir();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self{
|
||||||
path,
|
path,
|
||||||
context_dir,
|
context_dir,
|
||||||
assets: Assets::new(),
|
assets: Assets::new(),
|
||||||
show_trace: false,
|
show_trace: false,
|
||||||
machines_file: RwLock::new(None),
|
meta_config: OnceCell::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +125,13 @@ impl Hive {
|
||||||
self.context_dir.as_ref().map(|p| p.as_ref())
|
self.context_dir.as_ref().map(|p| p.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_meta_config(&self) -> ColmenaResult<&MetaConfig> {
|
||||||
|
self.meta_config.get_or_try_init(||async {
|
||||||
|
self.nix_instantiate("hive.metaConfig").eval()
|
||||||
|
.capture_json().await
|
||||||
|
}).await
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_show_trace(&mut self, value: bool) {
|
pub fn set_show_trace(&mut self, value: bool) {
|
||||||
self.show_trace = value;
|
self.show_trace = value;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +148,7 @@ impl Hive {
|
||||||
let mut options = NixOptions::default();
|
let mut options = NixOptions::default();
|
||||||
options.set_show_trace(self.show_trace);
|
options.set_show_trace(self.show_trace);
|
||||||
|
|
||||||
if let Some(machines_file) = self.machines_file().await? {
|
if let Some(machines_file) = &self.get_meta_config().await?.machines_file {
|
||||||
options.set_builders(Some(format!("@{}", machines_file)));
|
options.set_builders(Some(format!("@{}", machines_file)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,22 +325,6 @@ impl Hive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the machinesFile setting for the Hive.
|
|
||||||
async fn machines_file(&self) -> ColmenaResult<Option<String>> {
|
|
||||||
if let Some(machines_file) = &*self.machines_file.read().await {
|
|
||||||
return Ok(machines_file.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let expr = "toJSON (hive.meta.machinesFile or null)";
|
|
||||||
let s: String = self.nix_instantiate(expr).eval()
|
|
||||||
.capture_json().await?;
|
|
||||||
|
|
||||||
let parsed: Option<String> = serde_json::from_str(&s).unwrap();
|
|
||||||
self.machines_file.write().await.replace(parsed.clone());
|
|
||||||
|
|
||||||
Ok(parsed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the base expression from which the evaluated Hive can be used.
|
/// Returns the base expression from which the evaluated Hive can be used.
|
||||||
fn get_base_expression(&self) -> String {
|
fn get_base_expression(&self) -> String {
|
||||||
self.assets.get_base_expression(self.path())
|
self.assets.get_base_expression(self.path())
|
||||||
|
|
|
@ -282,6 +282,19 @@ with builtins; rec {
|
||||||
default = {};
|
default = {};
|
||||||
type = types.attrsOf types.unspecified;
|
type = types.attrsOf types.unspecified;
|
||||||
};
|
};
|
||||||
|
allowApplyAll = lib.mkOption {
|
||||||
|
description = ''
|
||||||
|
Whether to allow deployments without a node filter set.
|
||||||
|
|
||||||
|
If set to false, a node filter must be specified with `--on` when
|
||||||
|
deploying.
|
||||||
|
|
||||||
|
It helps prevent accidental deployments to the entire cluster
|
||||||
|
when tags are used (e.g., `@production` and `@staging`).
|
||||||
|
'';
|
||||||
|
default = true;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -542,3 +542,22 @@ fn test_hive_introspect() {
|
||||||
|
|
||||||
assert_eq!("true", eval);
|
assert_eq!("true", eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hive_get_meta() {
|
||||||
|
let hive = TempHive::new(r#"
|
||||||
|
{
|
||||||
|
meta.allowApplyAll = false;
|
||||||
|
meta.specialArgs = {
|
||||||
|
this_is_new = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"#);
|
||||||
|
|
||||||
|
let eval = block_on(hive.get_meta_config())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
eprintln!("{:?}", eval);
|
||||||
|
|
||||||
|
assert!(!eval.allow_apply_all);
|
||||||
|
}
|
||||||
|
|
|
@ -82,6 +82,15 @@ pub struct NodeConfig {
|
||||||
keys: HashMap<String, Key>,
|
keys: HashMap<String, Key>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Validate, Deserialize)]
|
||||||
|
pub struct MetaConfig {
|
||||||
|
#[serde(rename = "allowApplyAll")]
|
||||||
|
pub allow_apply_all: bool,
|
||||||
|
|
||||||
|
#[serde(rename = "machinesFile")]
|
||||||
|
pub machines_file: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Nix options.
|
/// Nix options.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct NixOptions {
|
pub struct NixOptions {
|
||||||
|
|
Loading…
Reference in a new issue