avina-cli 2.2.0

Rust CLI client for the LRZ-specific features of the Openstack-based LRZ Compute Cloud.
use std::error::Error;

use clap::{Args, Subcommand};

#[cfg(not(feature = "user"))]
use crate::common::find_id as user_find_id;
use crate::common::{
    Execute, Format, ask_for_confirmation, print_object_list,
    print_single_object,
};
#[cfg(not(feature = "resources"))]
use crate::common::{
    find_id as flavor_group_find_id, find_id as flavor_find_id,
};
#[cfg(feature = "resources")]
use crate::resources::{
    flavor::find_id as flavor_find_id,
    flavor_group::find_id as flavor_group_find_id,
};
#[cfg(feature = "user")]
use crate::user::user::find_id as user_find_id;

#[derive(Args, Debug)]
#[group(multiple = false)]
pub(crate) struct FlavorQuotaListFilter {
    #[clap(short, long, help = "Display all flavor quotas", action)]
    all: bool,

    #[clap(
        short,
        long,
        help = "Display flavor quotas of flavor group with given name or ID"
    )]
    group: Option<String>,

    #[clap(
        short,
        long,
        help = "Display flavor quotas of user with given name, ID, or OpenStack UUIDv4"
    )]
    user: Option<String>,
}

#[derive(Subcommand, Debug)]
pub(crate) enum FlavorQuotaCommand {
    #[clap(about = "List flavor quotas")]
    List {
        #[clap(flatten)]
        filter: FlavorQuotaListFilter,
    },

    #[clap(visible_alias = "show", about = "Show flavor quota with given ID")]
    Get { id: u32 },

    #[clap(about = "Create a new flavor quota")]
    Create {
        #[clap(help = "Name or ID of the flavor group")]
        flavor_group: String,

        #[clap(help = "Name, ID, or OpenStack UUIDv4 of the user")]
        user: String,

        #[clap(long, short, help = "Amount of the quota")]
        quota: Option<i64>,
    },

    #[clap(about = "Modify a flavor quota")]
    Modify {
        #[clap(help = "ID of the flavor quota")]
        id: u32,

        #[clap(
            long,
            short,
            help = "Name, ID, or OpenStack UUIDv4 the quota is for"
        )]
        user: Option<String>,

        #[clap(long, short, help = "Quota amount")]
        quota: Option<i64>,

        #[clap(
            long,
            short,
            help = "Name or ID of the flavor group that should be limited"
        )]
        flavor_group: Option<String>,
    },

    #[clap(about = "Delete flavor quota with given ID")]
    Delete { id: u32 },

    #[clap(about = "Check that a user can start the given number of a flavor")]
    Check {
        #[clap(help = "Name, ID, or OpenStack ID of the user")]
        user: String,

        #[clap(help = "Name, ID, or OpenStack UUIDv4 of the flavor")]
        flavor: String,

        #[clap(long, short, help = "Amount of the instances of said flavor")]
        count: Option<u32>,
    },
}
pub(crate) use FlavorQuotaCommand::*;

impl Execute for FlavorQuotaCommand {
    async fn execute(
        &self,
        api: avina::Api,
        format: Format,
    ) -> Result<(), Box<dyn Error>> {
        match self {
            List { filter } => list(api, format, filter).await,
            Get { id } => get(api, format, id).await,
            Create {
                flavor_group,
                user,
                quota,
            } => create(api, format, flavor_group, user, *quota).await,
            Modify {
                id,
                user,
                quota,
                flavor_group,
            } => {
                modify(
                    api,
                    format,
                    *id,
                    user.to_owned(),
                    *quota,
                    flavor_group.to_owned(),
                )
                .await
            }
            Delete { id } => delete(api, id).await,
            Check {
                user,
                flavor,
                count,
            } => check(api, format, user, flavor, *count).await,
        }
    }
}

async fn list(
    api: avina::Api,
    format: Format,
    filter: &FlavorQuotaListFilter,
) -> Result<(), Box<dyn Error>> {
    let mut request = api.flavor_quota.list();
    if filter.all {
        request.all();
    } else if let Some(group) = &filter.group {
        let group_id = flavor_group_find_id(&api, group).await?;
        request.group(group_id);
    } else if let Some(user) = &filter.user {
        let user_id = user_find_id(&api, user).await?;
        request.user(user_id);
    }
    print_object_list(request.send().await?, format)
}

async fn get(
    api: avina::Api,
    format: Format,
    id: &u32,
) -> Result<(), Box<dyn Error>> {
    print_single_object(api.flavor_quota.get(*id).await?, format)
}

async fn create(
    api: avina::Api,
    format: Format,
    flavor_group: &str,
    user: &str,
    quota: Option<i64>,
) -> Result<(), Box<dyn Error>> {
    let flavor_group_id = flavor_group_find_id(&api, flavor_group).await?;
    let user_id = user_find_id(&api, user).await?;
    let mut request = api.flavor_quota.create(flavor_group_id, user_id);
    if let Some(quota) = quota {
        request.quota(quota);
    }
    print_single_object(request.send().await?, format)
}

async fn modify(
    api: avina::Api,
    format: Format,
    id: u32,
    user: Option<String>,
    quota: Option<i64>,
    flavor_group: Option<String>,
) -> Result<(), Box<dyn Error>> {
    let mut request = api.flavor_quota.modify(id);
    if let Some(user) = user {
        let user_id = user_find_id(&api, &user).await?;
        request.user(user_id);
    }
    if let Some(quota) = quota {
        request.quota(quota);
    }
    if let Some(flavor_group) = flavor_group {
        let flavor_group_id = flavor_group_find_id(&api, &flavor_group).await?;
        request.flavor_group(flavor_group_id);
    }
    print_single_object(request.send().await?, format)
}

async fn delete(api: avina::Api, id: &u32) -> Result<(), Box<dyn Error>> {
    ask_for_confirmation()?;
    Ok(api.flavor_quota.delete(*id).await?)
}

async fn check(
    api: avina::Api,
    format: Format,
    user: &str,
    flavor: &str,
    count: Option<u32>,
) -> Result<(), Box<dyn Error>> {
    let user_id = user_find_id(&api, user).await?;
    let flavor_id = flavor_find_id(&api, flavor).await?;
    let mut request = api.flavor_quota.check(user_id, flavor_id);
    if let Some(count) = count {
        request.count(count);
    }
    print_single_object(request.send().await?, format)
}