forked from DGNum/colmena
Convert apply-local arguments to type-safe clap derive
This commit is contained in:
parent
1e38582451
commit
b80b57cb48
2 changed files with 69 additions and 72 deletions
|
@ -1,10 +1,7 @@
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use clap::{
|
use clap::{ArgMatches, Args, Command as ClapCommand, FromArgMatches};
|
||||||
builder::PossibleValuesParser, Arg, ArgMatches, Command as ClapCommand, FromArgMatches,
|
|
||||||
};
|
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
use crate::error::ColmenaError;
|
use crate::error::ColmenaError;
|
||||||
|
@ -14,57 +11,66 @@ use crate::nix::hive::HiveArgs;
|
||||||
use crate::nix::{host::Local as LocalHost, NodeName};
|
use crate::nix::{host::Local as LocalHost, NodeName};
|
||||||
use crate::progress::SimpleProgressOutput;
|
use crate::progress::SimpleProgressOutput;
|
||||||
|
|
||||||
pub fn subcommand() -> ClapCommand {
|
#[derive(Debug, Args)]
|
||||||
ClapCommand::new("apply-local")
|
#[command(
|
||||||
.about("Apply configurations on the local machine")
|
name = "apply-local",
|
||||||
.arg(Arg::new("goal")
|
about = "Apply configurations on the local machine"
|
||||||
.help("Deployment goal")
|
)]
|
||||||
.long_help("Same as the targets for switch-to-configuration.\n\"push\" is noop in apply-local.")
|
pub struct Opts {
|
||||||
.default_value("switch")
|
#[arg(
|
||||||
.index(1)
|
help = "Deployment goal",
|
||||||
.value_parser(PossibleValuesParser::new([
|
value_name = "GOAL",
|
||||||
"push",
|
default_value_t,
|
||||||
"switch",
|
long_help = "Same as the targets for switch-to-configuration.\n\"push\" is noop in apply-local."
|
||||||
"boot",
|
)]
|
||||||
"test",
|
goal: Goal,
|
||||||
"dry-activate",
|
#[arg(long, help = "Attempt to escalate privileges if not run as root")]
|
||||||
"keys",
|
sudo: bool,
|
||||||
])))
|
#[arg(
|
||||||
.arg(Arg::new("sudo")
|
short,
|
||||||
.long("sudo")
|
long,
|
||||||
.help("Attempt to escalate privileges if not run as root")
|
help = "Be verbose",
|
||||||
.num_args(0))
|
long_help = "Deactivates the progress spinner and prints every line of output."
|
||||||
.arg(Arg::new("verbose")
|
)]
|
||||||
.short('v')
|
verbose: bool,
|
||||||
.long("verbose")
|
#[arg(
|
||||||
.help("Be verbose")
|
long,
|
||||||
.long_help("Deactivates the progress spinner and prints every line of output.")
|
help = "Do not deploy keys",
|
||||||
.num_args(0))
|
long_help = r#"Do not deploy secret keys set in `deployment.keys`.
|
||||||
.arg(Arg::new("no-keys")
|
|
||||||
.long("no-keys")
|
|
||||||
.help("Do not deploy keys")
|
|
||||||
.long_help(r#"Do not deploy secret keys set in `deployment.keys`.
|
|
||||||
|
|
||||||
By default, Colmena will deploy keys set in `deployment.keys` before activating the profile on this host.
|
By default, Colmena will deploy keys set in `deployment.keys` before activating the profile on this host.
|
||||||
"#)
|
"#
|
||||||
.num_args(0))
|
)]
|
||||||
.arg(Arg::new("node")
|
no_keys: bool,
|
||||||
.long("node")
|
#[arg(long, help = "Override the node name to use")]
|
||||||
.value_name("NODE")
|
node: Option<String>,
|
||||||
.help("Override the node name to use")
|
#[arg(
|
||||||
.num_args(1))
|
long,
|
||||||
|
value_name = "COMMAND",
|
||||||
|
hide = true,
|
||||||
|
help = "Removed: Configure deployment.privilegeEscalationCommand in node configuration"
|
||||||
|
)]
|
||||||
|
sudo_command: Option<String>,
|
||||||
|
#[command(flatten)]
|
||||||
|
hive_args: HiveArgs,
|
||||||
|
}
|
||||||
|
|
||||||
// Removed
|
pub fn subcommand() -> ClapCommand {
|
||||||
.arg(Arg::new("sudo-command")
|
Opts::augment_args(ClapCommand::new("apply-local"))
|
||||||
.long("sudo-command")
|
|
||||||
.value_name("COMMAND")
|
|
||||||
.help("Removed: Configure deployment.privilegeEscalationCommand in node configuration")
|
|
||||||
.hide(true)
|
|
||||||
.num_args(1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(_global_args: &ArgMatches, local_args: &ArgMatches) -> Result<(), ColmenaError> {
|
pub async fn run(_global_args: &ArgMatches, local_args: &ArgMatches) -> Result<(), ColmenaError> {
|
||||||
if local_args.contains_id("sudo-command") {
|
let Opts {
|
||||||
|
goal,
|
||||||
|
sudo,
|
||||||
|
verbose,
|
||||||
|
no_keys,
|
||||||
|
node,
|
||||||
|
sudo_command,
|
||||||
|
hive_args,
|
||||||
|
} = Opts::from_arg_matches(local_args).expect("Failed to parse `apply-local` options.");
|
||||||
|
|
||||||
|
if sudo_command.is_some() {
|
||||||
log::error!("--sudo-command has been removed. Please configure it in deployment.privilegeEscalationCommand in the node configuration.");
|
log::error!("--sudo-command has been removed. Please configure it in deployment.privilegeEscalationCommand in the node configuration.");
|
||||||
quit::with_code(1);
|
quit::with_code(1);
|
||||||
}
|
}
|
||||||
|
@ -81,35 +87,26 @@ pub async fn run(_global_args: &ArgMatches, local_args: &ArgMatches) -> Result<(
|
||||||
quit::with_code(5);
|
quit::with_code(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
let escalate_privileges = local_args.get_flag("sudo");
|
let verbose = verbose || sudo; // cannot use spinners with interactive sudo
|
||||||
let verbose = local_args.get_flag("verbose") || escalate_privileges; // cannot use spinners with interactive sudo
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let euid: u32 = unsafe { libc::geteuid() };
|
let euid: u32 = unsafe { libc::geteuid() };
|
||||||
if euid != 0 && !escalate_privileges {
|
if euid != 0 && !sudo {
|
||||||
log::warn!("Colmena was not started by root. This is probably not going to work.");
|
log::warn!("Colmena was not started by root. This is probably not going to work.");
|
||||||
log::warn!("Hint: Add the --sudo flag.");
|
log::warn!("Hint: Add the --sudo flag.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let hive = HiveArgs::from_arg_matches(local_args)
|
let hive = hive_args
|
||||||
.unwrap()
|
|
||||||
.into_hive()
|
.into_hive()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.expect("Failed to get hive from arguments");
|
||||||
let hostname = {
|
let hostname = NodeName::new(node.unwrap_or_else(|| {
|
||||||
let s = if local_args.contains_id("node") {
|
hostname::get()
|
||||||
local_args.get_one::<String>("node").unwrap().to_owned()
|
.expect("Could not get hostname")
|
||||||
} else {
|
.to_string_lossy()
|
||||||
hostname::get()
|
.into_owned()
|
||||||
.expect("Could not get hostname")
|
}))?;
|
||||||
.to_string_lossy()
|
|
||||||
.into_owned()
|
|
||||||
};
|
|
||||||
|
|
||||||
NodeName::new(s)?
|
|
||||||
};
|
|
||||||
let goal = Goal::from_str(local_args.get_one::<String>("goal").unwrap()).unwrap();
|
|
||||||
|
|
||||||
let target = {
|
let target = {
|
||||||
if let Some(info) = hive.deployment_info_single(&hostname).await.unwrap() {
|
if let Some(info) = hive.deployment_info_single(&hostname).await.unwrap() {
|
||||||
|
@ -123,7 +120,7 @@ pub async fn run(_global_args: &ArgMatches, local_args: &ArgMatches) -> Result<(
|
||||||
quit::with_code(2);
|
quit::with_code(2);
|
||||||
}
|
}
|
||||||
let mut host = LocalHost::new(nix_options);
|
let mut host = LocalHost::new(nix_options);
|
||||||
if escalate_privileges {
|
if sudo {
|
||||||
let command = info.privilege_escalation_command().to_owned();
|
let command = info.privilege_escalation_command().to_owned();
|
||||||
host.set_privilege_escalation_command(Some(command));
|
host.set_privilege_escalation_command(Some(command));
|
||||||
}
|
}
|
||||||
|
@ -148,13 +145,13 @@ pub async fn run(_global_args: &ArgMatches, local_args: &ArgMatches) -> Result<(
|
||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
let mut options = Options::default();
|
let mut options = Options::default();
|
||||||
options.set_upload_keys(!local_args.get_flag("no-keys"));
|
options.set_upload_keys(!no_keys);
|
||||||
options
|
options
|
||||||
};
|
};
|
||||||
|
|
||||||
deployment.set_options(options);
|
deployment.set_options(options);
|
||||||
|
|
||||||
let (deployment, output) = tokio::join!(deployment.execute(), output.run_until_completion(),);
|
let (deployment, output) = tokio::join!(deployment.execute(), output.run_until_completion());
|
||||||
|
|
||||||
deployment?;
|
deployment?;
|
||||||
output?;
|
output?;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
/// The goal of a deployment.
|
/// The goal of a deployment.
|
||||||
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, clap::ValueEnum)]
|
||||||
pub enum Goal {
|
pub enum Goal {
|
||||||
/// Build the configurations only.
|
/// Build the configurations only.
|
||||||
Build,
|
Build,
|
||||||
|
|
Loading…
Reference in a new issue