use format_table::format_table; use garage_util::error::*; use garage_api_admin::api::*; use crate::cli::structs::*; use crate::cli_v2::*; impl Cli { pub async fn cmd_key(&self, cmd: KeyOperation) -> Result<(), Error> { match cmd { KeyOperation::List => self.cmd_list_keys().await, KeyOperation::Info(query) => self.cmd_key_info(query).await, KeyOperation::Create(query) => self.cmd_create_key(query).await, KeyOperation::Rename(query) => self.cmd_rename_key(query).await, KeyOperation::Delete(query) => self.cmd_delete_key(query).await, KeyOperation::Allow(query) => self.cmd_allow_key(query).await, KeyOperation::Deny(query) => self.cmd_deny_key(query).await, KeyOperation::Import(query) => self.cmd_import_key(query).await, } } pub async fn cmd_list_keys(&self) -> Result<(), Error> { let keys = self.api_request(ListKeysRequest).await?; println!("List of keys:"); let mut table = vec![]; for key in keys.0.iter() { table.push(format!("\t{}\t{}", key.id, key.name)); } format_table(table); Ok(()) } pub async fn cmd_key_info(&self, opt: KeyInfoOpt) -> Result<(), Error> { let key = self .api_request(GetKeyInfoRequest { id: None, search: Some(opt.key_pattern), show_secret_key: opt.show_secret, }) .await?; print_key_info(&key); Ok(()) } pub async fn cmd_create_key(&self, opt: KeyNewOpt) -> Result<(), Error> { let key = self .api_request(CreateKeyRequest { name: Some(opt.name), }) .await?; print_key_info(&key.0); Ok(()) } pub async fn cmd_rename_key(&self, opt: KeyRenameOpt) -> Result<(), Error> { let key = self .api_request(GetKeyInfoRequest { id: None, search: Some(opt.key_pattern), show_secret_key: false, }) .await?; let new_key = self .api_request(UpdateKeyRequest { id: key.access_key_id, body: UpdateKeyRequestBody { name: Some(opt.new_name), allow: None, deny: None, }, }) .await?; print_key_info(&new_key.0); Ok(()) } pub async fn cmd_delete_key(&self, opt: KeyDeleteOpt) -> Result<(), Error> { let key = self .api_request(GetKeyInfoRequest { id: None, search: Some(opt.key_pattern), show_secret_key: false, }) .await?; if !opt.yes { println!("About to delete key {}...", key.access_key_id); return Err(Error::Message( "Add --yes flag to really perform this operation".to_string(), )); } self.api_request(DeleteKeyRequest { id: key.access_key_id.clone(), }) .await?; println!("Access key {} has been deleted.", key.access_key_id); Ok(()) } pub async fn cmd_allow_key(&self, opt: KeyPermOpt) -> Result<(), Error> { let key = self .api_request(GetKeyInfoRequest { id: None, search: Some(opt.key_pattern), show_secret_key: false, }) .await?; let new_key = self .api_request(UpdateKeyRequest { id: key.access_key_id, body: UpdateKeyRequestBody { name: None, allow: Some(KeyPerm { create_bucket: opt.create_bucket, }), deny: None, }, }) .await?; print_key_info(&new_key.0); Ok(()) } pub async fn cmd_deny_key(&self, opt: KeyPermOpt) -> Result<(), Error> { let key = self .api_request(GetKeyInfoRequest { id: None, search: Some(opt.key_pattern), show_secret_key: false, }) .await?; let new_key = self .api_request(UpdateKeyRequest { id: key.access_key_id, body: UpdateKeyRequestBody { name: None, allow: None, deny: Some(KeyPerm { create_bucket: opt.create_bucket, }), }, }) .await?; print_key_info(&new_key.0); Ok(()) } pub async fn cmd_import_key(&self, opt: KeyImportOpt) -> Result<(), Error> { if !opt.yes { return Err(Error::Message("This command is intended to re-import keys that were previously generated by Garage. If you want to create a new key, use `garage key new` instead. Add the --yes flag if you really want to re-import a key.".to_string())); } let new_key = self .api_request(ImportKeyRequest { name: Some(opt.name), access_key_id: opt.key_id, secret_access_key: opt.secret_key, }) .await?; print_key_info(&new_key.0); Ok(()) } } fn print_key_info(key: &GetKeyInfoResponse) { println!("Key name: {}", key.name); println!("Key ID: {}", key.access_key_id); println!( "Secret key: {}", key.secret_access_key.as_deref().unwrap_or("(redacted)") ); println!("Can create buckets: {}", key.permissions.create_bucket); println!("\nKey-specific bucket aliases:"); let mut table = vec![]; for bucket in key.buckets.iter() { for la in bucket.local_aliases.iter() { table.push(format!( "\t{}\t{}\t{}", la, bucket.global_aliases.join(","), bucket.id )); } } format_table(table); println!("\nAuthorized buckets:"); let mut table = vec![]; for bucket in key.buckets.iter() { let rflag = if bucket.permissions.read { "R" } else { " " }; let wflag = if bucket.permissions.write { "W" } else { " " }; let oflag = if bucket.permissions.owner { "O" } else { " " }; table.push(format!( "\t{}{}{}\t{}\t{}\t{:.16}", rflag, wflag, oflag, bucket.global_aliases.join(","), bucket.local_aliases.join(","), bucket.id )); } format_table(table); }