forked from DGNum/colmena
Merge pull request #9 from justinas/handle-keycommand-errors
Handle and report errors of key source, do not write out key if keyCommand failed
This commit is contained in:
commit
114c344dbb
5 changed files with 50 additions and 11 deletions
|
@ -281,7 +281,7 @@ impl Deployment {
|
||||||
task.log("Uploading keys...");
|
task.log("Uploading keys...");
|
||||||
|
|
||||||
if let Err(e) = target.host.upload_keys(&target.config.keys).await {
|
if let Err(e) = target.host.upload_keys(&target.config.keys).await {
|
||||||
task.failure(&format!("Failed to upload keys: {}", e));
|
task.failure_err(&e);
|
||||||
|
|
||||||
let mut results = arc_self.results.lock().await;
|
let mut results = arc_self.results.lock().await;
|
||||||
let stage = Stage::Apply(node.to_string());
|
let stage = Stage::Apply(node.to_string());
|
||||||
|
@ -481,7 +481,7 @@ impl Deployment {
|
||||||
bar.log("Uploading keys...");
|
bar.log("Uploading keys...");
|
||||||
|
|
||||||
if let Err(e) = target.host.upload_keys(&target.config.keys).await {
|
if let Err(e) = target.host.upload_keys(&target.config.keys).await {
|
||||||
bar.failure(&format!("Failed to upload keys: {}", e));
|
bar.failure_err(&e);
|
||||||
|
|
||||||
let mut results = self.results.lock().await;
|
let mut results = self.results.lock().await;
|
||||||
let stage = Stage::Apply(name.to_string());
|
let stage = Stage::Apply(name.to_string());
|
||||||
|
|
|
@ -211,10 +211,10 @@ impl Ssh {
|
||||||
command.stderr(Stdio::piped());
|
command.stderr(Stdio::piped());
|
||||||
command.stdout(Stdio::piped());
|
command.stdout(Stdio::piped());
|
||||||
|
|
||||||
let mut child = command.spawn()?;
|
|
||||||
|
|
||||||
let mut stdin = child.stdin.take().unwrap();
|
|
||||||
let mut reader = key.reader().await?;
|
let mut reader = key.reader().await?;
|
||||||
|
|
||||||
|
let mut child = command.spawn()?;
|
||||||
|
let mut stdin = child.stdin.take().unwrap();
|
||||||
tokio::io::copy(reader.as_mut(), &mut stdin).await?;
|
tokio::io::copy(reader.as_mut(), &mut stdin).await?;
|
||||||
stdin.flush().await?;
|
stdin.flush().await?;
|
||||||
drop(stdin);
|
drop(stdin);
|
||||||
|
|
|
@ -2,11 +2,12 @@ use std::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
io::{self, Cursor},
|
io::{self, Cursor},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::Stdio,
|
process::{ExitStatus, Stdio},
|
||||||
};
|
};
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use snafu::Snafu;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::AsyncRead,
|
io::AsyncRead,
|
||||||
|
@ -14,6 +15,21 @@ use tokio::{
|
||||||
};
|
};
|
||||||
use validator::{Validate, ValidationError};
|
use validator::{Validate, ValidationError};
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug, Snafu)]
|
||||||
|
pub enum KeyError {
|
||||||
|
#[snafu(display("I/O Error: {}", error))]
|
||||||
|
IoError { error: io::Error },
|
||||||
|
#[snafu(display("Key command failed: {}, stderr: {}", status, stderr))]
|
||||||
|
KeyCommandStatus { status: ExitStatus, stderr: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for KeyError {
|
||||||
|
fn from(error: std::io::Error) -> Self {
|
||||||
|
Self::IoError { error }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(try_from = "KeySources")]
|
#[serde(try_from = "KeySources")]
|
||||||
enum KeySource {
|
enum KeySource {
|
||||||
|
@ -78,7 +94,7 @@ pub struct Key {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Key {
|
impl Key {
|
||||||
pub async fn reader(&'_ self,) -> Result<Box<dyn AsyncRead + Send + Unpin + '_>, io::Error> {
|
pub async fn reader(&'_ self) -> Result<Box<dyn AsyncRead + Send + Unpin + '_>, KeyError> {
|
||||||
match &self.source {
|
match &self.source {
|
||||||
KeySource::Text(content) => {
|
KeySource::Text(content) => {
|
||||||
Ok(Box::new(Cursor::new(content)))
|
Ok(Box::new(Cursor::new(content)))
|
||||||
|
@ -87,15 +103,25 @@ impl Key {
|
||||||
let pathname = &command[0];
|
let pathname = &command[0];
|
||||||
let argv = &command[1..];
|
let argv = &command[1..];
|
||||||
|
|
||||||
let stdout = Command::new(pathname)
|
let output = Command::new(pathname)
|
||||||
.args(argv)
|
.args(argv)
|
||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::null())
|
.stderr(Stdio::piped())
|
||||||
.spawn()?
|
.spawn()?
|
||||||
.stdout.take().unwrap();
|
.wait_with_output().await?;
|
||||||
|
|
||||||
Ok(Box::new(stdout))
|
if output.status.success() {
|
||||||
|
Ok(Box::new(Cursor::new(output.stdout)))
|
||||||
|
} else {
|
||||||
|
Err(KeyError::KeyCommandStatus {
|
||||||
|
status: output.status,
|
||||||
|
stderr: std::str::from_utf8(&output.stderr)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.trim_end()
|
||||||
|
.into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
KeySource::File(path) => {
|
KeySource::File(path) => {
|
||||||
Ok(Box::new(File::open(path).await?))
|
Ok(Box::new(File::open(path).await?))
|
||||||
|
|
|
@ -59,6 +59,9 @@ pub enum NixError {
|
||||||
#[snafu(display("Validation error"))]
|
#[snafu(display("Validation error"))]
|
||||||
ValidationError { errors: ValidationErrors },
|
ValidationError { errors: ValidationErrors },
|
||||||
|
|
||||||
|
#[snafu(display("Failed to upload keys: {}", error))]
|
||||||
|
KeyError { error: key::KeyError },
|
||||||
|
|
||||||
#[snafu(display("Invalid NixOS system profile"))]
|
#[snafu(display("Invalid NixOS system profile"))]
|
||||||
InvalidProfile,
|
InvalidProfile,
|
||||||
|
|
||||||
|
@ -72,6 +75,12 @@ impl From<std::io::Error> for NixError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<key::KeyError> for NixError {
|
||||||
|
fn from(error: key::KeyError) -> Self {
|
||||||
|
Self::KeyError { error }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ValidationErrors> for NixError {
|
impl From<ValidationErrors> for NixError {
|
||||||
fn from(errors: ValidationErrors) -> Self {
|
fn from(errors: ValidationErrors) -> Self {
|
||||||
Self::ValidationError { errors }
|
Self::ValidationError { errors }
|
||||||
|
|
|
@ -224,6 +224,10 @@ impl TaskProgress {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn failure_err<E: std::error::Error>(self, error: &E) {
|
||||||
|
self.failure(&error.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
fn plain_print(&self, style: Style, line: &str) {
|
fn plain_print(&self, style: Style, line: &str) {
|
||||||
eprintln!("{:>width$} | {}", style.apply_to(&self.label), line, width = self.label_width);
|
eprintln!("{:>width$} | {}", style.apply_to(&self.label), line, width = self.label_width);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue