Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust: Move vault update prints from library to cli #543

Merged
merged 3 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nitor-vault"
version = "1.3.1"
version = "1.4.0"
edition = "2021"
description = "Encrypted AWS key-value storage utility."
license = "Apache-2.0"
Expand Down
30 changes: 24 additions & 6 deletions rust/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use aws_sdk_cloudformation::types::StackStatus;
use colored::Colorize;
use tokio::time::Duration;

use nitor_vault::{cloudformation, CreateStackResult, Value, Vault};
use nitor_vault::{cloudformation, CreateStackResult, UpdateStackResult, Value, Vault};

static WAIT_ANIMATION_DURATION: Duration = Duration::from_millis(500);
static CLEAR_LINE: &str = "\x1b[2K";
Expand Down Expand Up @@ -44,12 +44,30 @@ pub async fn init_vault_stack(

/// Update existing Cloudformation vault stack and wait for update to finish.
pub async fn update_vault_stack(vault: &Vault) -> Result<()> {
vault
match vault
.update_stack()
.await
.with_context(|| "Failed to update vault stack".red())?;

wait_for_stack_update_to_finish(vault).await
.with_context(|| "Failed to update vault stack".red())?
{
UpdateStackResult::UpToDate { data } => {
println!("{}", "Vault stack is up to date:".bold());
println!("{data}");
Ok(())
}
UpdateStackResult::Update {
stack_id,
previous_version: current_version,
new_version,
} => {
println!(
"{}",
format!("Updating vault stack from version {current_version} to {new_version}")
.bold()
);
println!("{stack_id}");
wait_for_stack_update_to_finish(vault).await
}
}
}

/// Store a key-value pair.
Expand Down Expand Up @@ -225,7 +243,7 @@ async fn wait_for_stack_update_to_finish(vault: &Vault) -> Result<()> {
}
StackStatus::UpdateFailed | StackStatus::RollbackFailed => {
println!("{CLEAR_LINE}{stack_data}");
anyhow::bail!("Stack update failed");
anyhow::bail!("Stack update failed".red());
}
_ => {
// Print status if it has changed
Expand Down
2 changes: 1 addition & 1 deletion rust/src/cloudformation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl fmt::Display for CloudFormationStackData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"status: {}\nbucket: {}\nkey ARN: {}\nversion: {}{}",
"status: {}\nbucket: {}\nkey: {}\nversion: {}{}",
self.status
.as_ref()
.map_or("None".to_string(), std::string::ToString::to_string),
Expand Down
13 changes: 13 additions & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ pub enum CreateStackResult {
},
}

#[derive(Debug, Clone)]
/// Result data for updating the vault stack.
pub enum UpdateStackResult {
/// Vault stack is up to date.
UpToDate { data: CloudFormationStackData },
/// Vault stack was updated.
Update {
stack_id: String,
previous_version: u32,
new_version: u32,
},
}

#[derive(Debug, Clone)]
pub(crate) struct EncryptObject {
data_key: Vec<u8>,
Expand Down
28 changes: 17 additions & 11 deletions rust/src/vault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::cloudformation::{CloudFormationParams, CloudFormationStackData};
use crate::errors::VaultError;
use crate::template::{template, VAULT_STACK_VERSION};
use crate::value::Value;
use crate::{CreateStackResult, EncryptObject, Meta, S3DataKeys};
use crate::{CreateStackResult, EncryptObject, Meta, S3DataKeys, UpdateStackResult};

#[derive(Debug)]
pub struct Vault {
Expand Down Expand Up @@ -99,6 +99,9 @@ impl Vault {
/// Initialize new Vault stack.
/// This will create all required resources in AWS,
/// after which the Vault can be used to store and lookup values.
///
/// Returns a `CreateStackResult` with relevant data whether a new vault stack was initialized,
/// or it already exists.
pub async fn init(
vault_stack: Option<String>,
region: Option<String>,
Expand Down Expand Up @@ -176,10 +179,13 @@ impl Vault {
})
}

pub async fn update_stack(&self) -> Result<(), VaultError> {
/// Update the vault Cloudformation stack with the current template.
///
/// Returns an `UpdateStackResult` enum that indicates if the vault was updated,
/// or is already up to date.
pub async fn update_stack(&self) -> Result<UpdateStackResult, VaultError> {
let stack_name = &self.cloudformation_params.stack_name;
let stack_data = cloudformation::get_stack_data(&self.cf, stack_name).await?;
println!("{stack_data}");
let deployed_version = stack_data
.version
.map_or_else(|| Err(VaultError::StackVersionNotFoundError), Ok)?;
Expand All @@ -201,16 +207,15 @@ impl Vault {
.send()
.await?;

if let Some(stack_id) = response.stack_id {
println!("{stack_id}");
}

println!("Updated vault stack '{stack_name}' version from {deployed_version} to {VAULT_STACK_VERSION}");
let stack_id = response.stack_id.ok_or(VaultError::MissingStackIdError)?;
Ok(UpdateStackResult::Update {
stack_id,
previous_version: deployed_version,
new_version: VAULT_STACK_VERSION,
})
} else {
println!("Current stack version {deployed_version} does not need to be updated to version {VAULT_STACK_VERSION}");
Ok(UpdateStackResult::UpToDate { data: stack_data })
}

Ok(())
}

/// Get Cloudformation stack status.
Expand Down Expand Up @@ -342,6 +347,7 @@ impl Vault {
}
}

/// Return AWS SDK config with optional region name to use.
pub async fn get_aws_config(region: Option<String>) -> SdkConfig {
aws_config::from_env()
.region(get_region_provider(region))
Expand Down