use super::VAULT_ENV_NAME;
use crate::credential;
use akv_cli::Result;
use azure_core::http::Url;
use azure_security_keyvault_secrets::{models::SecretClientGetSecretOptions, SecretClient};
use clap::Parser;
use std::{
fs,
io::{self, Write},
path::PathBuf,
};
use tracing::{Level, Span};
#[derive(Debug, Parser)]
pub struct Args {
#[arg(group = "ident", value_name = "URL")]
id: Option<Url>,
#[arg(long, group = "ident", requires = "vault")]
name: Option<String>,
#[arg(long, value_name = "URL", env = VAULT_ENV_NAME)]
vault: Option<Url>,
#[arg(short = 'n', long)]
no_newline: bool,
#[arg(short = 'o', long, value_name = "PATH")]
out_file: Option<PathBuf>,
#[arg(short = 'f', long)]
force: bool,
}
impl Args {
#[tracing::instrument(level = Level::INFO, skip(self), fields(vault, name, version), err)]
pub async fn read(&self) -> Result<()> {
let (vault, name, version) =
super::select(self.id.as_ref(), self.vault.as_ref(), self.name.as_ref())?;
let current = Span::current();
current.record("vault", &*vault);
current.record("name", &*name);
current.record("version", version.as_deref());
let client = SecretClient::new(&vault, credential()?, None)?;
let secret = client
.get_secret(
&name,
Some(SecretClientGetSecretOptions {
secret_version: version.map(Into::into),
..Default::default()
}),
)
.await?
.into_body()?;
tracing::debug!("retrieved {:?}", &secret);
if let Some(value) = secret.value {
match self.out_file.as_ref() {
Some(path) => {
let mut file = fs::OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.create_new(!self.force)
.open(path)?;
file.write_all(value.as_bytes())?;
}
_ if self.no_newline => {
print!("{value}");
io::stdout().flush()?;
}
_ => println!("{value}"),
}
}
Ok(())
}
}