Skip to content
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 openstack_cli/src/identity/v3/credential/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ struct ResponseData {
#[structable(optional)]
id: Option<String>,

/// The links for the `credential` resource.
/// The link to the resources in question.
///
#[serde()]
#[structable(optional, pretty)]
Expand Down
2 changes: 1 addition & 1 deletion openstack_cli/src/identity/v3/credential/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ struct ResponseData {
#[structable(optional)]
id: Option<String>,

/// The links for the `credential` resource.
/// The link to the resources in question.
///
#[serde()]
#[structable(optional, pretty)]
Expand Down
2 changes: 1 addition & 1 deletion openstack_cli/src/identity/v3/credential/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ struct ResponseData {
#[structable(optional)]
id: Option<String>,

/// The links for the `credential` resource.
/// The link to the resources in question.
///
#[serde()]
#[structable(optional, pretty)]
Expand Down
58 changes: 43 additions & 15 deletions openstack_cli/src/identity/v3/project/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,40 +83,64 @@ struct Project {

/// The ID of the domain for the project.
///
/// For projects acting as a domain, the `domain_id` must not be specified,
/// it will be generated by the Identity service implementation.
///
/// For regular projects (i.e. those not acing as a domain), if `domain_id`
/// is not specified, but `parent_id` is specified, then the domain ID of
/// the parent will be used. If neither `domain_id` or `parent_id` is
/// specified, the Identity service implementation will default to the
/// domain to which the client’s token is scoped. If both `domain_id` and
/// `parent_id` are specified, and they do not indicate the same domain, an
/// `Bad Request (400)` will be returned.
///
#[arg(help_heading = "Body parameters", long)]
domain_id: Option<String>,

/// If the user is enabled, this value is `true`. If the user is disabled,
/// this value is `false`.
/// If set to `true`, project is enabled. If set to `false`, project is
/// disabled. The default is `true`.
///
#[arg(action=clap::ArgAction::Set, help_heading = "Body parameters", long)]
enabled: Option<bool>,

/// If the user is enabled, this value is `true`. If the user is disabled,
/// this value is `false`.
/// If set to `true`, project is enabled. If set to `false`, project is
/// disabled. The default is `true`.
///
#[arg(action=clap::ArgAction::Set, help_heading = "Body parameters", long)]
is_domain: Option<bool>,

/// The name of the project.
/// The name of the project, which must be unique within the owning domain.
/// A project can have the same name as its domain.
///
#[arg(help_heading = "Body parameters", long)]
name: Option<String>,
name: String,

/// The resource options for the project. Available resource options are
/// `immutable`.
///
#[command(flatten)]
options: Option<Options>,

/// The ID of the parent for the project.
/// The ID of the parent of the project.
///
/// If specified on project creation, this places the project within a
/// hierarchy and implicitly defines the owning domain, which will be the
/// same domain as the parent specified. If `parent_id` is not specified
/// and `is_domain` is `false`, then the project will use its owning domain
/// as its parent. If `is_domain` is `true` (i.e. the project is acting as
/// a domain), then `parent_id` must not specified (or if it is, it must be
/// `null`) since domains have no parents.
///
/// `parent_id` is immutable, and can’t be updated after the project is
/// created - hence a project cannot be moved within the hierarchy.
///
/// **New in version 3.4**
///
#[arg(help_heading = "Body parameters", long)]
parent_id: Option<String>,

/// A list of simple strings assigned to a project.
/// A list of simple strings assigned to a project. Tags can be used to
/// classify projects into groups.
///
#[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long)]
tags: Option<Vec<String>>,
Expand All @@ -137,8 +161,8 @@ struct ResponseData {
#[structable(optional)]
domain_id: Option<String>,

/// If the user is enabled, this value is `true`. If the user is disabled,
/// this value is `false`.
/// If set to `true`, project is enabled. If set to `false`, project is
/// disabled.
///
#[serde()]
#[structable(optional)]
Expand All @@ -150,13 +174,19 @@ struct ResponseData {
#[structable(optional)]
id: Option<String>,

/// If the user is enabled, this value is `true`. If the user is disabled,
/// this value is `false`.
/// If set to `true`, project is enabled. If set to `false`, project is
/// disabled.
///
#[serde()]
#[structable(optional)]
is_domain: Option<bool>,

/// The link to the resources in question.
///
#[serde()]
#[structable(optional, pretty)]
links: Option<Value>,

/// The name of the project.
///
#[serde()]
Expand Down Expand Up @@ -225,9 +255,7 @@ impl ProjectCommand {
project_builder.parent_id(Some(val.into()));
}

if let Some(val) = &args.name {
project_builder.name(val);
}
project_builder.name(&args.name);

if let Some(val) = &args.tags {
project_builder.tags(val.iter().map(Into::into).collect::<Vec<_>>());
Expand Down
117 changes: 93 additions & 24 deletions openstack_cli/src/identity/v3/project/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@ use crate::OpenStackCliError;
use crate::OutputConfig;
use crate::StructTable;

use eyre::OptionExt;
use openstack_sdk::api::find_by_name;
use openstack_sdk::api::identity::v3::domain::find as find_domain;
use openstack_sdk::api::identity::v3::project::list;
use openstack_sdk::api::QueryAsync;
use serde_json::Value;
use structable_derive::StructTable;
use tracing::warn;

/// Lists projects.
///
Expand All @@ -56,33 +60,48 @@ pub struct ProjectsCommand {
/// Query parameters
#[derive(Args)]
struct QueryParameters {
/// Filters the response by a domain ID.
///
#[arg(help_heading = "Query parameters", long)]
domain_id: Option<String>,
/// Domain resource for which the operation should be performed.
#[command(flatten)]
domain: DomainInput,

/// If set to true, then only enabled projects will be returned. Any value
/// other than 0 (including no value) will be interpreted as true.
///
#[arg(action=clap::ArgAction::Set, help_heading = "Query parameters", long)]
enabled: Option<bool>,

/// If this is specified as true, then only projects acting as a domain are
/// included. Otherwise, only projects that are not acting as a domain are
/// included.
///
#[arg(action=clap::ArgAction::Set, help_heading = "Query parameters", long)]
is_domain: Option<bool>,

/// Filters the response by a resource name.
///
#[arg(help_heading = "Query parameters", long)]
name: Option<String>,

/// Filters the response by a parent ID.
///
#[arg(help_heading = "Query parameters", long)]
not_tags: Option<String>,

#[arg(help_heading = "Query parameters", long)]
not_tags_any: Option<String>,

#[arg(help_heading = "Query parameters", long)]
parent_id: Option<String>,

#[arg(help_heading = "Query parameters", long)]
tags: Option<String>,

#[arg(help_heading = "Query parameters", long)]
tags_any: Option<String>,
}

/// Domain input select group
#[derive(Args)]
#[group(required = false, multiple = false)]
struct DomainInput {
/// Domain Name.
#[arg(long, help_heading = "Path parameters", value_name = "DOMAIN_NAME")]
domain_name: Option<String>,
/// Domain ID.
#[arg(long, help_heading = "Path parameters", value_name = "DOMAIN_ID")]
domain_id: Option<String>,
/// Current domain.
#[arg(long, help_heading = "Path parameters", action = clap::ArgAction::SetTrue)]
current_domain: bool,
}

/// Path parameters
Expand All @@ -103,8 +122,8 @@ struct ResponseData {
#[structable(optional, wide)]
domain_id: Option<String>,

/// If the user is enabled, this value is `true`. If the user is disabled,
/// this value is `false`.
/// If set to `true`, project is enabled. If set to `false`, project is
/// disabled.
///
#[serde()]
#[structable(optional, wide)]
Expand All @@ -116,8 +135,8 @@ struct ResponseData {
#[structable(optional)]
id: Option<String>,

/// If the user is enabled, this value is `true`. If the user is disabled,
/// this value is `false`.
/// If set to `true`, project is enabled. If set to `false`, project is
/// disabled.
///
#[serde()]
#[structable(optional, wide)]
Expand Down Expand Up @@ -167,21 +186,71 @@ impl ProjectsCommand {

// Set path parameters
// Set query parameters
if let Some(val) = &self.query.domain_id {
ep_builder.domain_id(val);
if let Some(id) = &self.query.domain.domain_id {
// domain_id is passed. No need to lookup
ep_builder.domain_id(id);
} else if let Some(name) = &self.query.domain.domain_name {
// domain_name is passed. Need to lookup resource
let mut sub_find_builder = find_domain::Request::builder();
warn!("Querying domain by name (because of `--domain-name` parameter passed) may not be definite. This may fail in which case parameter `--domain-id` should be used instead.");

sub_find_builder.id(name);
let find_ep = sub_find_builder
.build()
.map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
let find_data: serde_json::Value = find_by_name(find_ep).query_async(client).await?;
// Try to extract resource id
match find_data.get("id") {
Some(val) => match val.as_str() {
Some(id_str) => {
ep_builder.domain_id(id_str.to_owned());
}
None => {
return Err(OpenStackCliError::ResourceAttributeNotString(
serde_json::to_string(&val)?,
))
}
},
None => {
return Err(OpenStackCliError::ResourceAttributeMissing(
"id".to_string(),
))
}
};
} else if self.query.domain.current_domain {
ep_builder.domain_id(
client
.get_auth_info()
.ok_or_eyre("Cannot determine current authentication information")?
.token
.user
.id,
);
}
if let Some(val) = &self.query.enabled {
ep_builder.enabled(*val);
}
if let Some(val) = &self.query.is_domain {
ep_builder.is_domain(*val);
}
if let Some(val) = &self.query.name {
ep_builder.name(val);
}
if let Some(val) = &self.query.parent_id {
ep_builder.parent_id(val);
}
if let Some(val) = &self.query.is_domain {
ep_builder.is_domain(*val);
}
if let Some(val) = &self.query.tags {
ep_builder.tags(val);
}
if let Some(val) = &self.query.tags_any {
ep_builder.tags_any(val);
}
if let Some(val) = &self.query.not_tags {
ep_builder.not_tags(val);
}
if let Some(val) = &self.query.not_tags_any {
ep_builder.not_tags_any(val);
}
// Set body parameters

let ep = ep_builder
Expand Down
Loading