Merge pull request #26 from bartvdbraak/feat/improve-verbosity

Add useful and pretty logging using `paris`
This commit is contained in:
Bart van der Braak 2023-11-14 03:57:22 +01:00 committed by GitHub
commit 63d9aedd75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 12 deletions

7
Cargo.lock generated
View file

@ -860,6 +860,7 @@ dependencies = [
"clap", "clap",
"futures", "futures",
"openssl", "openssl",
"paris",
"tokio", "tokio",
] ]
@ -1063,6 +1064,12 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "paris"
version = "1.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fecab3723493c7851f292cb060f3ee1c42f19b8d749345d0d7eaf3fd19aa62d"
[[package]] [[package]]
name = "parking" name = "parking"
version = "2.2.0" version = "2.2.0"

View file

@ -15,6 +15,7 @@ azure_identity = "0.17.0"
azure_security_keyvault = "0.17.0" azure_security_keyvault = "0.17.0"
clap = { version = "4.4.8", features = ["derive"] } clap = { version = "4.4.8", features = ["derive"] }
futures = "0.3.29" futures = "0.3.29"
paris = { version = "1.5.15", features = ["macros"] }
tokio = {version = "1.34.0", features = ["full"]} tokio = {version = "1.34.0", features = ["full"]}
[target.'cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "arm", target_arch = "aarch64")))'.dependencies] [target.'cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "arm", target_arch = "aarch64")))'.dependencies]

View file

@ -1,9 +1,10 @@
use anyhow::{Context, Result}; use anyhow::Result;
use azure_identity::DefaultAzureCredential; use azure_identity::DefaultAzureCredential;
use azure_security_keyvault::prelude::KeyVaultGetSecretsResponse; use azure_security_keyvault::prelude::KeyVaultGetSecretsResponse;
use azure_security_keyvault::KeyvaultClient; use azure_security_keyvault::KeyvaultClient;
use clap::Parser; use clap::Parser;
use futures::stream::StreamExt; use futures::stream::StreamExt;
use paris::{error, Logger};
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::sync::Arc; use std::sync::Arc;
@ -34,7 +35,13 @@ async fn fetch_secrets_from_key_vault(
let mut secret_pages = client.secret_client().list_secrets().into_stream(); let mut secret_pages = client.secret_client().list_secrets().into_stream();
while let Some(page) = secret_pages.next().await { while let Some(page) = secret_pages.next().await {
let page = page.context("Failed to fetch secrets page")?; let page = match page {
Ok(p) => p,
Err(err) => {
error!("Failed to fetch secrets page: {}", err);
return Err(err.into()); // Convert the error into anyhow::Error
}
};
secret_values secret_values
.extend(fetch_secrets_from_page(&client.secret_client(), &page, filter).await?); .extend(fetch_secrets_from_page(&client.secret_client(), &page, filter).await?);
} }
@ -75,6 +82,8 @@ async fn fetch_secrets_from_page(
for handle in handles { for handle in handles {
if let Ok(result) = handle.await { if let Ok(result) = handle.await {
secrets.push(result); secrets.push(result);
} else {
error!("Error occurred while fetching a secret.");
} }
} }
@ -97,20 +106,30 @@ async fn fetch_and_send_secret(
(secret_id, bundle.value) (secret_id, bundle.value)
} }
Err(err) => { Err(err) => {
eprintln!("Error fetching secret: {}", err); error!("Error fetching secret: {}", err);
(secret_id, String::new()) (secret_id, String::new())
} }
} }
} }
fn create_env_file(secrets: Vec<(String, String)>, output_file: &str) -> Result<()> { fn create_env_file(secrets: Vec<(String, String)>, output_file: &str) -> Result<()> {
let mut file = File::create(output_file).context("Failed to create output file")?; let mut file = match File::create(output_file) {
Ok(f) => f,
Err(err) => {
error!("Failed to create output file: {}", err);
return Err(err.into());
}
};
for (key, value) in secrets { for (key, value) in secrets {
if let Some(secret_name) = key.split('/').last() { if let Some(secret_name) = key.split('/').last() {
writeln!(file, "{}={}", secret_name, value) if let Err(err) = writeln!(file, "{}={}", secret_name, value) {
.with_context(|| format!("Failed to write to output file: {}", output_file))?; error!("Failed to write to output file: {}: {}", output_file, err);
return Err(err.into());
}
} }
} }
Ok(()) Ok(())
} }
@ -147,18 +166,35 @@ mod tests {
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let opts: Opts = Opts::parse(); let opts: Opts = Opts::parse();
let mut log = Logger::new();
let vault_url = format!("https://{}.vault.azure.net", opts.vault_name); let vault_url = format!("https://{}.vault.azure.net", opts.vault_name);
println!("Fetching secrets from Key Vault: {}", opts.vault_name);
log.loading("Detecting credentials.");
let credential = DefaultAzureCredential::default(); let credential = DefaultAzureCredential::default();
let client = KeyvaultClient::new(&vault_url, std::sync::Arc::new(credential)) let client = match KeyvaultClient::new(&vault_url, std::sync::Arc::new(credential)) {
.context("Failed to create KeyvaultClient")?; Ok(c) => c,
Err(err) => {
error!("Failed to create KeyvaultClient: {}", err);
return Err(err.into());
}
};
log.success("Detected credentials.");
log.loading(format!(
"Fetching secrets from Key Vault: <blue>{}</>",
opts.vault_name
));
let secrets = fetch_secrets_from_key_vault(&client, opts.filter.as_deref()).await?; let secrets = fetch_secrets_from_key_vault(&client, opts.filter.as_deref()).await?;
println!("Creating output file: {}", opts.output); log.success(format!(
create_env_file(secrets, &opts.output)?; "Fetched secrets from Key Vault: <blue>{}</>",
opts.vault_name
));
println!("Process completed successfully!"); log.loading(format!("Creating output file: <blue>{}</>", opts.output));
create_env_file(secrets, &opts.output)?;
log.success(format!("Created output file: <blue>{}</>", opts.output));
log.success("Done.");
Ok(()) Ok(())
} }