Add a --dry-run argument to plan/task so that you can see what scripts will be run

This commit is contained in:
R Tyler Croy 2020-12-31 15:38:14 -08:00
parent dc1c67cf28
commit 7e3d7fb5ad
3 changed files with 52 additions and 11 deletions

View File

@ -71,7 +71,13 @@ fn handle_plan(opts: PlanOpts, runner: &dyn crate::transport::Transport, invento
info!("Plan located, preparing to execute");
for task in plan.tasks {
info!("Running executable task: {:?}", task);
exit = execute_task_on(opts.targets.clone(), &task, runner, &inventory);
exit = execute_task_on(
opts.targets.clone(),
&task,
runner,
&inventory,
opts.dry_run,
);
}
}
Err(err) => {
@ -86,13 +92,14 @@ fn execute_task_on(
task: &ExecutableTask,
runner: &dyn crate::transport::Transport,
inventory: &Inventory,
dry_run: bool,
) -> i32 {
if let Some(group) = inventory.groups.iter().find(|g| g.name == targets) {
return runner.run_group(task, &group, &inventory);
return runner.run_group(task, &group, &inventory, dry_run);
}
if let Some(target) = inventory.targets.iter().find(|t| t.name == targets) {
return runner.run(task, &target);
return runner.run(task, &target, dry_run);
}
error!("Failed to locate a script to execute for the task!");
return -1;
@ -122,7 +129,13 @@ fn handle_task(opts: TaskOpts, runner: &dyn crate::transport::Transport, invento
let task = ExecutableTask::new(task, parameters);
std::process::exit(execute_task_on(opts.targets, &task, runner, &inventory));
std::process::exit(execute_task_on(
opts.targets,
&task,
runner,
&inventory,
opts.dry_run,
));
}
Err(err) => {
println!("Failed to load task: {:?}", err);
@ -143,7 +156,13 @@ fn handle_task(opts: TaskOpts, runner: &dyn crate::transport::Transport, invento
fn handle_cmd(opts: CmdOpts, runner: &dyn crate::transport::Transport, inventory: Inventory) {
let mut task = ExecutableTask::new(Task::new("Dynamic"), HashMap::new());
task.task.script.inline = Some(opts.command);
std::process::exit(execute_task_on(opts.targets, &task, runner, &inventory));
std::process::exit(execute_task_on(
opts.targets,
&task,
runner,
&inventory,
false,
));
}
#[derive(Debug, Options)]
@ -182,7 +201,7 @@ enum Command {
#[options(help = "Execute a plan on a target(s)")]
Plan(PlanOpts),
#[options(help = "Check that the specified .ztask or .zplan file is valid")]
Check(CheckOpts)
Check(CheckOpts),
}
#[derive(Debug, Options)]
@ -206,6 +225,8 @@ struct TaskOpts {
parameter: Vec<String>,
#[options(help = "Name of a target or group")]
targets: String,
#[options(help = "Run the task in dry-run mode")]
dry_run: bool,
}
#[derive(Debug, Options)]
@ -214,6 +235,8 @@ struct PlanOpts {
plan: PathBuf,
#[options(help = "Name of a target or group")]
targets: String,
#[options(help = "Run the task in dry-run mode")]
dry_run: bool,
}
#[derive(Debug, Options)]

View File

@ -8,6 +8,7 @@ pub mod ssh;
* connecting to targets
*/
pub trait Transport {
fn run_group(&self, cmd: &ExecutableTask, group: &Group, inv: &Inventory) -> i32;
fn run(&self, command: &ExecutableTask, target: &Target) -> i32;
fn run_group(&self, cmd: &ExecutableTask, group: &Group, inv: &Inventory, dry_run: bool)
-> i32;
fn run(&self, command: &ExecutableTask, target: &Target, dry_run: bool) -> i32;
}

View File

@ -1,5 +1,6 @@
use crate::inventory::{Group, Inventory, Target};
use crate::transport::Transport;
use colored::*;
use log::*;
use serde::{Deserialize, Serialize};
@ -22,21 +23,27 @@ impl Default for Ssh {
}
impl Transport for Ssh {
fn run_group(&self, command: &ExecutableTask, group: &Group, inventory: &Inventory) -> i32 {
fn run_group(
&self,
command: &ExecutableTask,
group: &Group,
inventory: &Inventory,
dry_run: bool,
) -> i32 {
let mut status = 1;
for target_name in group.targets.iter() {
// XXX: This is inefficient
for target in inventory.targets.iter() {
if &target.name == target_name {
println!("Running on `{}`", target.name);
status = self.run(command, &target);
status = self.run(command, &target, dry_run);
}
}
}
status
}
fn run(&self, command: &ExecutableTask, target: &Target) -> i32 {
fn run(&self, command: &ExecutableTask, target: &Target, dry_run: bool) -> i32 {
// Connect to the local SSH server
let tcp = TcpStream::connect(format!("{}:22", target.uri)).unwrap();
let mut sess = Session::new().unwrap();
@ -66,6 +73,7 @@ impl Transport for Ssh {
"A `provides` parameter was given, checking to see if {} exists on the remote",
provides
);
if let Err(error) = sess.scp_recv(&Path::new(&provides)) {
if error.code() == ssh2::ErrorCode::Session(-28) {
debug!(
@ -91,6 +99,15 @@ impl Transport for Ssh {
}
if let Some(script) = command.task.script.as_bytes(Some(&command.parameters)) {
if dry_run {
println!("{}", "Dry-run\n----".yellow());
let mut out = std::io::stdout();
out.write(&script)
.expect("Somehow failed to write to stdout");
println!("{}", "\n----".yellow());
return 0;
}
let mut remote_file = sess
.scp_send(
Path::new(remote_script),