diff --git a/README.md b/README.md index 8df58c4..571f9e4 100644 --- a/README.md +++ b/README.md @@ -11,17 +11,98 @@ This project serves as a learning exercise in [Rust](https://www.rust-lang.org/) **Note**: This project is not suitable for production use. It's designed strictly for educational purposes. -## Setup Instructions +## Installation -To get the project up and running, follow these steps: +The binary executable is `spt`. -1. Clone the repository: `git clone git@github.com:sandeshgrangdan/ssm-tui.git` -2. Start the server: `cargo run` +### Homebrew -## Installation +For both macOS and Linux + +```bash +brew install ssm-tui +``` + +To update, run + +```bash +brew upgrade ssm-tui +``` + +### Snap + +For a system with Snap installed, run + +```bash +snap install spt +``` + +The stable version will be installed for you automatically. + +If you want to install the nightly build, run + +```bash +snap install spt --edge +``` + +### AUR + +For those on Arch Linux you can find the package on AUR [here](https://aur.archlinux.org/packages/ssm-tui/). If however you're using an AUR helper you can install directly from that, for example (in the case of [yay](https://github.com/Jguer/yay)), run + +```bash +yay -S ssm-tui +``` + +### Nix + +Available as the package `ssm-tui`. To install run: + +```bash +nix-env -iA nixpkgs.ssm-tui +``` + +Where `nixpkgs` is the channel name in your configuration. For a more up-to-date installation, use the unstable channel. +It is also possible to add the package to `environment.systemPackages` (for NixOS), or `home.packages` when using [home-manager](https://github.com/rycee/home-manager). + +### Void Linux + +Available on the official repositories. To install, run + +```bash +sudo xbps-install -Su ssm-tui +``` + +### Fedora/CentOS + +Available on the [Copr](https://copr.fedorainfracloud.org/coprs/atim/ssm-tui/) repositories. To install, run + +```bash +sudo dnf copr enable atim/ssm-tui -y && sudo dnf install ssm-tui +``` + +### Cargo + +Use this option if your architecture is not supported by the pre-built binaries found on the [releases page](https://github.com/Rigellute/ssm-tui/releases). + +First, install [Rust](https://www.rust-lang.org/tools/install) (using the recommended `rustup` installation method) and then + +```bash +cargo install ssm-tui +``` + +This method will build the binary from source. + +To update, run the same command again. ``` git clone git@github.com:sandeshgrangdan/ssm-tui.git cargo build --release cd target/release/ ./ssm-tui ``` + +## Setup Instructions (Development) + +To get the project up and running, follow these steps: + +1. Clone the repository: `git clone git@github.com:sandeshgrangdan/ssm-tui.git` +2. Start the tui: `cargo run` diff --git a/src/app.rs b/src/app.rs index 3959947..4bd52cb 100644 --- a/src/app.rs +++ b/src/app.rs @@ -35,7 +35,7 @@ pub struct Args { } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct StatefulList { pub state: ListState, pub items: Vec, @@ -257,32 +257,45 @@ impl App { } pub async fn launch_vim(&mut self) -> io::Result<()> { - let temp_file_path = &self.generate_random_file_name(); - - let mut file = File::create(temp_file_path)?; - file.write_all(self.get_selected_value().as_bytes())?; - drop(file); - - Command::new("vim") - .arg(temp_file_path) // Specify the file you want to edit with Vim - .status()?; - - let edited_value = fs::read_to_string(temp_file_path)?; - - fs::remove_file(temp_file_path)?; - let selected_ps_index = match self.parameter_stores.state.selected() { Some(metadata) => metadata, None => 0 }; - - let ps_name = &self.parameter_stores.display_items[selected_ps_index]; - self.parameter_stores.ps_values.insert((ps_name).to_string(), (&edited_value).to_string()); + let ps_name = &self.parameter_stores.display_items[selected_ps_index]; match &self.ssm_client { SsmClient::Client(client) => { - let _ = aws::parameter_store::edit_ps_value(ps_name, edited_value, client).await; + match aws::parameter_store::get_ps_value(ps_name, client).await { + Ok(ps_value) => { + let temp_file_path = &self.generate_random_file_name(); + + let mut file = File::create(temp_file_path)?; + file.write_all(ps_value.as_bytes())?; + drop(file); + + Command::new("vim") + .arg(temp_file_path) // Specify the file you want to edit with Vim + .status()?; + + let edited_value = fs::read_to_string(temp_file_path)?; + let edited_value = edited_value.trim().to_string(); + + fs::remove_file(temp_file_path)?; + + if edited_value != ps_value.trim() { + self.parameter_stores.ps_values.insert((ps_name).to_string(), (&edited_value).to_string()); + let _ = aws::parameter_store::edit_ps_value(ps_name, edited_value, client).await; + match aws::parameter_store::get_ps_metadata(ps_name, client).await { + aws::parameter_store::PsMetadata::Data(data) => { + self.parameter_stores.ps_metadata.insert((ps_name).to_string(), data); + } + _ => {} + } + } + }, + Err(_) => {} + } } _ => {} } diff --git a/src/app/aws/parameter_store.rs b/src/app/aws/parameter_store.rs index 80d0796..f57d743 100644 --- a/src/app/aws/parameter_store.rs +++ b/src/app/aws/parameter_store.rs @@ -3,10 +3,18 @@ use std::collections::HashMap; use aws_config::meta::region::RegionProviderChain; use aws_config::{BehaviorVersion, Region}; use aws_sdk_ssm::{ - types::ParameterMetadata, Client, Error + types::{ + ParameterMetadata, + ParameterStringFilter + }, Client, Error }; use aws_config::profile::ProfileFileRegionProvider; +#[derive(Debug)] +pub enum PsMetadata { + Data(ParameterMetadata), + None +} pub async fn get_aws_client(profile: String,region: String) -> Client { let default_region = "us-east-1"; @@ -84,7 +92,7 @@ pub async fn fetch_ps(client: &Client) -> Result<(HashMap &String::new() }; items.push(ps_name.clone()); - let ps_value_res = get_ps_value(&ps_name, client.clone()).await; + let ps_value_res = get_ps_value(&ps_name, client).await; match ps_value_res { Ok(ps_value) => { ps_values.insert((&ps_name).to_string(), ps_value); @@ -97,7 +105,7 @@ pub async fn fetch_ps(client: &Client) -> Result<(HashMap Result{ +pub async fn get_ps_value(name: &String, client : &Client) -> Result{ let result = client .get_parameter() @@ -126,3 +134,37 @@ pub async fn edit_ps_value(parameter_name: &str, edited_value: String, client : Ok(()) } + +pub async fn get_ps_metadata(parameter_name: &str, client : &Client) -> PsMetadata { + + let mut result = PsMetadata::None; + + let filter = ParameterStringFilter::builder() + .key("Name") + .values(parameter_name) + .build(); + + let filter= match filter { + Ok(filter_string) => filter_string, + _ => panic!("") + }; + + let response = client + .describe_parameters() + .parameter_filters(filter) + .send() + .await + .unwrap(); + + if let Some(metadatas) = response.parameters { + for data in metadatas{ + if let Some(name) = &data.name { + if name.to_string() == parameter_name.to_string() { + result = PsMetadata::Data(data); + break; + } + } + } + }; + result +}