Compare commits
10 commits
495fc56f6e
...
cd65ef7a25
Author | SHA1 | Date | |
---|---|---|---|
|
cd65ef7a25 | ||
|
bb642e43f9 | ||
|
7997ab7187 | ||
|
afa7439c58 | ||
|
c84ccd0a7a | ||
|
bf690423ea | ||
|
665603956a | ||
|
15a95d6de5 | ||
|
3538f18b30 | ||
|
95ded7fddb |
9 changed files with 58 additions and 18 deletions
21
src/cli.rs
21
src/cli.rs
|
@ -278,6 +278,11 @@ pub async fn run() {
|
||||||
set_color_pref(&opts.color);
|
set_color_pref(&opts.color);
|
||||||
init_logging();
|
init_logging();
|
||||||
|
|
||||||
|
if let Command::GenCompletions { shell } = opts.command {
|
||||||
|
print_completions(shell, &mut Opts::command());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let hive = get_hive(&opts).await.expect("Failed to get flake or hive");
|
let hive = get_hive(&opts).await.expect("Failed to get flake or hive");
|
||||||
|
|
||||||
use crate::troubleshooter::run_wrapped as r;
|
use crate::troubleshooter::run_wrapped as r;
|
||||||
|
@ -296,7 +301,6 @@ pub async fn run() {
|
||||||
let args = command::apply::Opts {
|
let args = command::apply::Opts {
|
||||||
deploy,
|
deploy,
|
||||||
goal: crate::nix::Goal::Build,
|
goal: crate::nix::Goal::Build,
|
||||||
node_filter: Default::default(),
|
|
||||||
};
|
};
|
||||||
r(command::apply::run(hive, args), opts.config).await
|
r(command::apply::run(hive, args), opts.config).await
|
||||||
}
|
}
|
||||||
|
@ -304,21 +308,20 @@ pub async fn run() {
|
||||||
let args = command::apply::Opts {
|
let args = command::apply::Opts {
|
||||||
deploy,
|
deploy,
|
||||||
goal: crate::nix::Goal::UploadKeys,
|
goal: crate::nix::Goal::UploadKeys,
|
||||||
node_filter: Default::default(),
|
|
||||||
};
|
};
|
||||||
r(command::apply::run(hive, args), opts.config).await
|
r(command::apply::run(hive, args), opts.config).await
|
||||||
}
|
}
|
||||||
Command::GenCompletions { shell } => print_completions(shell, &mut Opts::command()),
|
Command::GenCompletions { .. } => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_completions(shell: Shell, cmd: &mut clap::Command) {
|
fn print_completions(shell: Shell, cmd: &mut clap::Command) {
|
||||||
clap_complete::generate(
|
let bin_name = cmd
|
||||||
shell,
|
.get_bin_name()
|
||||||
cmd,
|
.expect("Must have a bin_name")
|
||||||
cmd.get_name().to_string(),
|
.to_string();
|
||||||
&mut std::io::stdout(),
|
|
||||||
);
|
clap_complete::generate(shell, cmd, bin_name, &mut std::io::stdout());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_color_pref(when: &ColorWhen) {
|
fn set_color_pref(when: &ColorWhen) {
|
||||||
|
|
|
@ -113,6 +113,8 @@ will treat deployment.replaceUnknownProfiles as though it was set true and perfo
|
||||||
This is an experimental feature."#
|
This is an experimental feature."#
|
||||||
)]
|
)]
|
||||||
evaluator: EvaluatorType,
|
evaluator: EvaluatorType,
|
||||||
|
#[command(flatten)]
|
||||||
|
node_filter: NodeFilterOpts,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
|
@ -136,8 +138,6 @@ Same as the targets for switch-to-configuration, with the following extra pseudo
|
||||||
pub goal: Goal,
|
pub goal: Goal,
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub deploy: DeployOpts,
|
pub deploy: DeployOpts,
|
||||||
#[command(flatten)]
|
|
||||||
pub node_filter: NodeFilterOpts,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(hive: Hive, opts: Opts) -> Result<(), ColmenaError> {
|
pub async fn run(hive: Hive, opts: Opts) -> Result<(), ColmenaError> {
|
||||||
|
@ -159,8 +159,8 @@ pub async fn run(hive: Hive, opts: Opts) -> Result<(), ColmenaError> {
|
||||||
no_build_on_target,
|
no_build_on_target,
|
||||||
force_replace_unknown_profiles,
|
force_replace_unknown_profiles,
|
||||||
evaluator,
|
evaluator,
|
||||||
|
node_filter,
|
||||||
},
|
},
|
||||||
node_filter,
|
|
||||||
} = opts;
|
} = opts;
|
||||||
|
|
||||||
if node_filter.on.is_none() && goal != Goal::Build {
|
if node_filter.on.is_none() && goal != Goal::Build {
|
||||||
|
|
|
@ -110,9 +110,18 @@ pub async fn run(
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
join_all(futures).await;
|
let results: Vec<Result<(), ColmenaError>> = join_all(futures).await;
|
||||||
|
|
||||||
Ok(())
|
let mut failed: usize = 0;
|
||||||
|
|
||||||
|
for x in results {
|
||||||
|
match x {
|
||||||
|
Err(_) => failed += 1,
|
||||||
|
Ok(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(failed)
|
||||||
});
|
});
|
||||||
|
|
||||||
let (meta, monitor, output) = tokio::join!(
|
let (meta, monitor, output) = tokio::join!(
|
||||||
|
@ -121,9 +130,13 @@ pub async fn run(
|
||||||
output.run_until_completion(),
|
output.run_until_completion(),
|
||||||
);
|
);
|
||||||
|
|
||||||
meta?;
|
let failed = meta?;
|
||||||
monitor?;
|
monitor?;
|
||||||
output?;
|
output?;
|
||||||
|
|
||||||
Ok(())
|
if failed > 0 {
|
||||||
|
Err(ColmenaError::ExecError { n_hosts: failed })
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,9 @@ pub enum ColmenaError {
|
||||||
|
|
||||||
#[snafu(display("Unknown error: {}", message))]
|
#[snafu(display("Unknown error: {}", message))]
|
||||||
Unknown { message: String },
|
Unknown { message: String },
|
||||||
|
|
||||||
|
#[snafu(display("Exec failed on {} hosts", n_hosts))]
|
||||||
|
ExecError { n_hosts: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::io::Error> for ColmenaError {
|
impl From<std::io::Error> for ColmenaError {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{ rawHive ? null # Colmena Hive attrset
|
{ rawHive ? null # Colmena Hive attrset
|
||||||
, rawFlake ? null # Nix Flake attrset with `outputs.colmena`
|
, rawFlake ? null # Nix Flake attrset with `outputs.colmena`
|
||||||
, hermetic ? rawFlake != null # Whether we are allowed to use <nixpkgs>
|
, hermetic ? rawFlake != null # Whether we are allowed to use <nixpkgs>
|
||||||
, colmenaOptions
|
, colmenaOptions ? import ./options.nix
|
||||||
, colmenaModules
|
, colmenaModules ? import ./modules.nix
|
||||||
}:
|
}:
|
||||||
with builtins;
|
with builtins;
|
||||||
let
|
let
|
||||||
|
|
|
@ -208,6 +208,13 @@ with builtins; rec {
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = [ "sudo" "-H" "--" ];
|
default = [ "sudo" "-H" "--" ];
|
||||||
};
|
};
|
||||||
|
sshOptions = lib.mkOption {
|
||||||
|
description = mdDoc ''
|
||||||
|
Extra SSH options to pass to the SSH command.
|
||||||
|
'';
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,6 +33,9 @@ pub struct Ssh {
|
||||||
/// Command to elevate privileges with.
|
/// Command to elevate privileges with.
|
||||||
privilege_escalation_command: Vec<String>,
|
privilege_escalation_command: Vec<String>,
|
||||||
|
|
||||||
|
/// extra SSH options
|
||||||
|
extra_ssh_options: Vec<String>,
|
||||||
|
|
||||||
/// Whether to use the experimental `nix copy` command.
|
/// Whether to use the experimental `nix copy` command.
|
||||||
use_nix3_copy: bool,
|
use_nix3_copy: bool,
|
||||||
|
|
||||||
|
@ -189,6 +192,7 @@ impl Ssh {
|
||||||
port: None,
|
port: None,
|
||||||
ssh_config: None,
|
ssh_config: None,
|
||||||
privilege_escalation_command: Vec::new(),
|
privilege_escalation_command: Vec::new(),
|
||||||
|
extra_ssh_options: Vec::new(),
|
||||||
use_nix3_copy: false,
|
use_nix3_copy: false,
|
||||||
job: None,
|
job: None,
|
||||||
}
|
}
|
||||||
|
@ -206,6 +210,10 @@ impl Ssh {
|
||||||
self.privilege_escalation_command = command;
|
self.privilege_escalation_command = command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_extra_ssh_options(&mut self, options: Vec<String>) {
|
||||||
|
self.extra_ssh_options = options;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_use_nix3_copy(&mut self, enable: bool) {
|
pub fn set_use_nix3_copy(&mut self, enable: bool) {
|
||||||
self.use_nix3_copy = enable;
|
self.use_nix3_copy = enable;
|
||||||
}
|
}
|
||||||
|
@ -346,6 +354,7 @@ impl Ssh {
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
|
.chain(self.extra_ssh_options.clone())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if let Some(port) = self.port {
|
if let Some(port) = self.port {
|
||||||
|
|
|
@ -78,6 +78,9 @@ pub struct NodeConfig {
|
||||||
#[serde(rename = "privilegeEscalationCommand")]
|
#[serde(rename = "privilegeEscalationCommand")]
|
||||||
privilege_escalation_command: Vec<String>,
|
privilege_escalation_command: Vec<String>,
|
||||||
|
|
||||||
|
#[serde(rename = "sshOptions")]
|
||||||
|
extra_ssh_options: Vec<String>,
|
||||||
|
|
||||||
#[validate(custom = "validate_keys")]
|
#[validate(custom = "validate_keys")]
|
||||||
keys: HashMap<String, Key>,
|
keys: HashMap<String, Key>,
|
||||||
}
|
}
|
||||||
|
@ -181,6 +184,7 @@ impl NodeConfig {
|
||||||
self.target_host.as_ref().map(|target_host| {
|
self.target_host.as_ref().map(|target_host| {
|
||||||
let mut host = Ssh::new(self.target_user.clone(), target_host.clone());
|
let mut host = Ssh::new(self.target_user.clone(), target_host.clone());
|
||||||
host.set_privilege_escalation_command(self.privilege_escalation_command.clone());
|
host.set_privilege_escalation_command(self.privilege_escalation_command.clone());
|
||||||
|
host.set_extra_ssh_options(self.extra_ssh_options.clone());
|
||||||
|
|
||||||
if let Some(target_port) = self.target_port {
|
if let Some(target_port) = self.target_port {
|
||||||
host.set_port(target_port);
|
host.set_port(target_port);
|
||||||
|
|
|
@ -248,6 +248,7 @@ mod tests {
|
||||||
build_on_target: false,
|
build_on_target: false,
|
||||||
replace_unknown_profiles: false,
|
replace_unknown_profiles: false,
|
||||||
privilege_escalation_command: vec![],
|
privilege_escalation_command: vec![],
|
||||||
|
extra_ssh_options: vec![],
|
||||||
keys: HashMap::new(),
|
keys: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue