mod group;
mod heal;
mod info;
mod policy;
mod service_account;
mod user;
use clap::Subcommand;
use crate::exit_code::ExitCode;
use crate::output::{Formatter, OutputConfig};
use rc_core::AliasManager;
use rc_s3::AdminClient;
#[derive(Subcommand, Debug)]
pub enum AdminCommands {
#[command(subcommand)]
Info(info::InfoCommands),
#[command(subcommand)]
Heal(heal::HealCommands),
#[command(subcommand)]
User(user::UserCommands),
#[command(subcommand)]
Policy(policy::PolicyCommands),
#[command(subcommand)]
Group(group::GroupCommands),
#[command(name = "service-account", subcommand)]
ServiceAccount(service_account::ServiceAccountCommands),
}
pub async fn execute(cmd: AdminCommands, output_config: OutputConfig) -> ExitCode {
let formatter = Formatter::new(output_config);
match cmd {
AdminCommands::Info(info_cmd) => info::execute(info_cmd, &formatter).await,
AdminCommands::Heal(heal_cmd) => heal::execute(heal_cmd, &formatter).await,
AdminCommands::User(user_cmd) => user::execute(user_cmd, &formatter).await,
AdminCommands::Policy(policy_cmd) => policy::execute(policy_cmd, &formatter).await,
AdminCommands::Group(group_cmd) => group::execute(group_cmd, &formatter).await,
AdminCommands::ServiceAccount(sa_cmd) => service_account::execute(sa_cmd, &formatter).await,
}
}
fn normalize_admin_alias(alias_name: &str) -> &str {
let normalized_alias = alias_name.trim_end_matches('/');
if normalized_alias.is_empty() {
alias_name
} else {
normalized_alias
}
}
pub fn get_admin_client(alias_name: &str, formatter: &Formatter) -> Result<AdminClient, ExitCode> {
let alias_lookup_name = normalize_admin_alias(alias_name);
let alias_manager = match AliasManager::new() {
Ok(am) => am,
Err(e) => {
formatter.error(&format!("Failed to load aliases: {e}"));
return Err(ExitCode::GeneralError);
}
};
let alias = match alias_manager.get(alias_lookup_name) {
Ok(a) => a,
Err(rc_core::Error::AliasNotFound(_)) => {
formatter.error(&format!("Alias '{}' not found", alias_name));
return Err(ExitCode::NotFound);
}
Err(e) => {
formatter.error(&format!("Failed to get alias: {e}"));
return Err(ExitCode::GeneralError);
}
};
match AdminClient::new(&alias) {
Ok(client) => Ok(client),
Err(e) => {
formatter.error(&format!("Failed to create admin client: {e}"));
Err(ExitCode::GeneralError)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use clap::Parser;
#[derive(Parser)]
struct TestCli {
#[command(subcommand)]
command: AdminCommands,
}
#[test]
fn test_parse_admin_info_disk_options() {
let cli = TestCli::parse_from(["rc", "info", "disk", "local", "--offline", "--healing"]);
match cli.command {
AdminCommands::Info(info::InfoCommands::Disk(args)) => {
assert_eq!(args.alias, "local");
assert!(args.offline);
assert!(args.healing);
}
_ => panic!("Unexpected command parsing result"),
}
}
#[test]
fn test_parse_admin_heal_start_options() {
let cli = TestCli::parse_from([
"rc",
"heal",
"start",
"local",
"--bucket",
"mybucket",
"--prefix",
"logs/",
"--scan-mode",
"deep",
"--remove",
"--recreate",
"--dry-run",
]);
match cli.command {
AdminCommands::Heal(heal::HealCommands::Start(args)) => {
assert_eq!(args.alias, "local");
assert_eq!(args.bucket.as_deref(), Some("mybucket"));
assert_eq!(args.prefix.as_deref(), Some("logs/"));
assert_eq!(args.scan_mode, "deep");
assert!(args.remove);
assert!(args.recreate);
assert!(args.dry_run);
}
_ => panic!("Unexpected command parsing result"),
}
}
#[test]
fn test_normalize_admin_alias_trailing_slash() {
assert_eq!(normalize_admin_alias("local/"), "local");
}
#[test]
fn test_normalize_admin_alias_without_trailing_slash() {
assert_eq!(normalize_admin_alias("local"), "local");
}
#[test]
fn test_normalize_admin_alias_only_slash() {
assert_eq!(normalize_admin_alias("/"), "/");
}
}