Skip to content

Commit

Permalink
refactor: add mod cmd (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
leroyguillaume authored Jul 17, 2024
1 parent 6cf127d commit f696166
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 65 deletions.
37 changes: 37 additions & 0 deletions src/cmd/default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use std::{ffi::OsStr, process::Output};

use tokio::process::Command;
use tracing::{debug, error, instrument, Level};

use super::{CommandRunner, Error, Result};

macro_rules! log_output {
($lvl:ident, $cmd:expr, $output:expr) => {{
let output = String::from_utf8_lossy(&$output);
for line in output.lines() {
$lvl!("{}: {line}", $cmd);
}
}};
}

pub struct DefaultCommandRunner;

impl CommandRunner for DefaultCommandRunner {
#[instrument(skip(self, args))]
async fn run<S: AsRef<OsStr> + Send + Sync>(&self, cmd: &str, args: &[S]) -> Result<Output> {
debug!("running command");
let output = Command::new(cmd).args(args).output().await?;
if tracing::enabled!(Level::DEBUG) {
log_output!(debug, cmd, output.stdout);
}
if output.status.success() {
if tracing::enabled!(Level::DEBUG) {
log_output!(debug, cmd, output.stderr);
}
Ok(output)
} else {
log_output!(error, cmd, output.stderr);
Err(Error::Failure(output))
}
}
}
27 changes: 27 additions & 0 deletions src/cmd/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use std::{ffi::OsStr, process::Output};

use futures::Future;

pub mod default;

pub type Result<T = ()> = std::result::Result<T, Error>;

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("command failed")]
Failure(Output),
#[error("i/o error: {0}")]
Io(
#[from]
#[source]
std::io::Error,
),
}

pub trait CommandRunner: Send + Sync {
fn run<S: AsRef<OsStr> + Send + Sync>(
&self,
cmd: &str,
args: &[S],
) -> impl Future<Output = Result<Output>> + Send;
}
113 changes: 49 additions & 64 deletions src/helm/cli.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,24 @@
use std::{
path::PathBuf,
process::{ExitStatus, Output},
};
use std::path::PathBuf;

use tokio::process::Command;
use tracing::{debug, error, instrument, Level};
use tracing::{debug, error, instrument};

use crate::domain::{App, Chart};
use crate::{
cmd::CommandRunner,
domain::{App, Chart},
};

use super::{HelmClient, Result};

macro_rules! log_output {
($lvl:ident, $output:expr) => {{
let output = String::from_utf8_lossy(&$output);
for line in output.lines() {
$lvl!("helm: {line}");
}
}};
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("helm {0}")]
Command(ExitStatus),
#[error("invalid unicode")]
InvalidUnicode,
#[error("i/o error: {0}")]
Io(
#[error("{0}")]
Command(
#[from]
#[source]
std::io::Error,
crate::cmd::Error,
),
#[error("invalid unicode")]
InvalidUnicode,
}

#[derive(clap::Args, Clone, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -61,61 +49,58 @@ impl Default for CliHelmClientArgs {
}
}

pub struct CliHelmClient(CliHelmClientArgs);

impl CliHelmClient {
pub fn new(args: CliHelmClientArgs) -> Self {
Self(args)
}
pub struct CliHelmClient<R: CommandRunner> {
args: CliHelmClientArgs,
runner: R,
}

fn handle_output(output: Output) -> Result {
if tracing::enabled!(Level::DEBUG) {
log_output!(debug, output.stdout);
}
if output.status.success() {
if tracing::enabled!(Level::DEBUG) {
log_output!(debug, output.stderr);
}
Ok(())
} else {
log_output!(error, output.stderr);
Err(Error::Command(output.status).into())
}
impl<R: CommandRunner> CliHelmClient<R> {
pub fn new(args: CliHelmClientArgs, runner: R) -> Self {
Self { args, runner }
}
}

impl HelmClient for CliHelmClient {
impl<R: CommandRunner> HelmClient for CliHelmClient<R> {
#[instrument("helm_uninstall", skip(self, name, app), fields(app.name = name, app.namespace = app.spec.namespace))]
async fn uninstall(&self, name: &str, app: &App) -> Result {
debug!("running helm uninstall");
let output = Command::new(&self.0.bin)
.arg("uninstall")
.arg("-n")
.arg(&app.spec.namespace)
.arg("--ignore-not-found")
.arg(name)
.output()
self.runner
.run(
"helm",
&[
"uninstall",
"-n",
&app.spec.namespace,
"--ignore-not-found",
name,
],
)
.await?;
Self::handle_output(output)
Ok(())
}

#[instrument("helm_upgrade", skip(self, app, filepaths), fields(app.chart = %app.spec.chart, app.name = name, app.namespace = app.spec.namespace))]
async fn upgrade(&self, name: &str, app: &App, filepaths: &[PathBuf]) -> Result {
let chart = match &app.spec.chart {
Chart::BuiltIn {} => self.0.chart_path.to_str().ok_or(Error::InvalidUnicode)?,
Chart::BuiltIn {} => self.args.chart_path.to_str().ok_or(Error::InvalidUnicode)?,
};
let mut cmd = Command::new(&self.0.bin);
cmd.arg("upgrade")
.arg("-n")
.arg(&app.spec.namespace)
.arg("--create-namespace")
.arg("--install");
let mut args = vec![
"upgrade",
"-n",
&app.spec.namespace,
"--create-namespace",
"--install",
];
for path in filepaths {
cmd.arg("--values").arg(path);
let path = path.to_str().ok_or(Error::InvalidUnicode)?;
args.push("--values");
args.push(path);
}
debug!("running helm upgrade");
let output = cmd.arg(name).arg(chart).output().await?;
Self::handle_output(output)
args.push(name);
args.push(chart);
self.runner.run("helm", &args).await?;
Ok(())
}
}

Expand All @@ -125,8 +110,8 @@ impl From<Error> for super::Error {
}
}

impl From<std::io::Error> for super::Error {
fn from(err: std::io::Error) -> Self {
Error::Io(err).into()
impl From<crate::cmd::Error> for super::Error {
fn from(err: crate::cmd::Error) -> Self {
Error::Command(err).into()
}
}
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{
use ::kube::CustomResourceExt;
use api::{start_api, ApiContext};
use clap::{Parser, Subcommand};
use cmd::default::DefaultCommandRunner;
use deploy::helm::{HelmDeployer, HelmDeployerArgs};
use domain::{App, Invitation, Role, User};
use helm::cli::{CliHelmClient, CliHelmClientArgs};
Expand Down Expand Up @@ -37,6 +38,7 @@ use tracing_subscriber::{
};

mod api;
mod cmd;
mod deploy;
mod domain;
mod helm;
Expand All @@ -63,7 +65,7 @@ async fn main() -> anyhow::Result<()> {
Command::Crd { cmd } => cmd.print(),
Command::Op(args) => {
let kube = ::kube::Client::try_default().await?;
let helm = CliHelmClient::new(args.helm);
let helm = CliHelmClient::new(args.helm, DefaultCommandRunner);
let ctx = OpContext {
deployer: HelmDeployer::new(args.deployer, helm),
kube: ApiKubeClient::new(kube.clone()),
Expand Down

0 comments on commit f696166

Please sign in to comment.