From 8129ac7ee9b8673a7876d0e9942c0041893036df Mon Sep 17 00:00:00 2001 From: mayastor-bors Date: Fri, 6 Sep 2024 13:08:40 +0000 Subject: [PATCH] chore(bors): merge pull request #855 855: feat(topology): add show labels in pools r=sinhaashish a=sinhaashish Get pool ``` [nix-shell:~/code/rust/mayastor-extensions]$ ./target/debug/kubectl-mayastor get pool pool-on-node-1 -n openebs --show-labels ID DISKS MANAGED NODE STATUS CAPACITY ALLOCATED AVAILABLE COMMITTED LABELS pool-on-node-1 aio:///dev/sdb?uuid=b324aa79-c8b3-4859-a6e8-1a51fbc5d944 true node-1-237668 Online 10GiB 0 B 10GiB 0 B topology-key=topology-value ``` List pools ``` [nix-shell:~/code/rust/mayastor-extensions]$ ./target/debug/kubectl-mayastor get pools -n openebs --show-labels ID DISKS MANAGED NODE STATUS CAPACITY ALLOCATED AVAILABLE COMMITTED LABELS pool-on-node-2 aio:///dev/sdb?uuid=8045fe61-ae51-429b-9c73-4f8f60c42d44 true node-2-237668 Online 10GiB 0 B 10GiB 0 B pool-on-node-0 aio:///dev/sdb?uuid=4b12de79-fa6c-4bfd-9ed0-4f5f57cfeb4c true node-0-237668 Online 10GiB 0 B 10GiB 0 B zone=us-east-1 pool-on-node-1 aio:///dev/sdb?uuid=b324aa79-c8b3-4859-a6e8-1a51fbc5d944 true node-1-237668 Online 10GiB 0 B 10GiB 0 B topology-key=topology-value ``` List Pools with node filter ``` [nix-shell:~/code/rust/mayastor-extensions]$ ./target/debug/kubectl-mayastor get pools -n openebs --show-labels --node node-2-237668 ID DISKS MANAGED NODE STATUS CAPACITY ALLOCATED AVAILABLE COMMITTED LABELS pool-on-node-2 aio:///dev/sdb?uuid=8045fe61-ae51-429b-9c73-4f8f60c42d44 true node-2-237668 Online 10GiB 0 B 10GiB 0 B [nix-shell:~/code/rust/mayastor-extensions]$ ./target/debug/kubectl-mayastor get pools -n openebs --show-labels --node node-1-237668 ID DISKS MANAGED NODE STATUS CAPACITY ALLOCATED AVAILABLE COMMITTED LABELS pool-on-node-1 aio:///dev/sdb?uuid=b324aa79-c8b3-4859-a6e8-1a51fbc5d944 true node-1-237668 Online 10GiB 0 B 10GiB 0 B topology-key=topology-value [nix-shell:~/code/rust/mayastor-extensions]$ ./target/debug/kubectl-mayastor get pools -n openebs --show-labels --node node-0-237668 ID DISKS MANAGED NODE STATUS CAPACITY ALLOCATED AVAILABLE COMMITTED LABELS pool-on-node-0 aio:///dev/sdb?uuid=4b12de79-fa6c-4bfd-9ed0-4f5f57cfeb4c true node-0-237668 Online 10GiB 0 B 10GiB 0 B zone=us-east-1 ``` Co-authored-by: sinhaashish --- control-plane/plugin/src/lib.rs | 4 +- control-plane/plugin/src/resources/mod.rs | 4 +- control-plane/plugin/src/resources/pool.rs | 149 +++++++++++++++++++-- 3 files changed, 144 insertions(+), 13 deletions(-) diff --git a/control-plane/plugin/src/lib.rs b/control-plane/plugin/src/lib.rs index 89f559ec1..0d37cec31 100644 --- a/control-plane/plugin/src/lib.rs +++ b/control-plane/plugin/src/lib.rs @@ -148,7 +148,9 @@ impl ExecuteOperation for GetResources { volume::Volume::topology(id, &cli_args.output).await } GetResources::Pools(args) => pool::Pools::list(args, &cli_args.output).await, - GetResources::Pool { id } => pool::Pool::get(id, &cli_args.output).await, + GetResources::Pool(args) => { + pool::Pool::get(&args.pool_id(), args, &cli_args.output).await + } GetResources::Nodes(args) => node::Nodes::list(args, &cli_args.output).await, GetResources::Node(args) => { node::Node::get(&args.node_id(), args, &cli_args.output).await diff --git a/control-plane/plugin/src/resources/mod.rs b/control-plane/plugin/src/resources/mod.rs index 6b2185a60..dc4dad110 100644 --- a/control-plane/plugin/src/resources/mod.rs +++ b/control-plane/plugin/src/resources/mod.rs @@ -1,7 +1,7 @@ use crate::resources::{ blockdevice::BlockDeviceArgs, node::{DrainNodeArgs, GetNodeArgs, GetNodesArgs}, - pool::GetPoolsArgs, + pool::{GetPoolArgs, GetPoolsArgs}, snapshot::VolumeSnapshotArgs, volume::VolumesArgs, }; @@ -51,7 +51,7 @@ pub enum GetResources { /// Get all pools. Pools(GetPoolsArgs), /// Get pool with the given ID. - Pool { id: PoolId }, + Pool(GetPoolArgs), /// Get all nodes. Nodes(GetNodesArgs), /// Get node with the given ID. diff --git a/control-plane/plugin/src/resources/pool.rs b/control-plane/plugin/src/resources/pool.rs index d63e57d70..b438604c8 100644 --- a/control-plane/plugin/src/resources/pool.rs +++ b/control-plane/plugin/src/resources/pool.rs @@ -1,19 +1,22 @@ +extern crate utils as external_utils; use crate::{ - operations::{Get, Label, ListWithArgs, PluginResult}, + operations::{GetWithArgs, Label, ListWithArgs, PluginResult}, resources::{ error::{Error, LabelAssignSnafu, OpError, TopologyError}, utils, utils::{ optional_cell, print_table, validate_topology_key, validate_topology_value, CreateRow, - GetHeaderRow, OutputFormat, + CreateRows, GetHeaderRow, OutputFormat, }, NodeId, PoolId, }, rest_wrapper::RestClient, }; + use async_trait::async_trait; use openapi::apis::StatusCode; -use prettytable::Row; +use prettytable::{Cell, Row}; +use serde::Serialize; use snafu::ResultExt; use std::collections::HashMap; @@ -68,6 +71,27 @@ impl GetHeaderRow for openapi::models::Pool { } } +/// Arguments used when getting a pool. +#[derive(Debug, Clone, clap::Args)] +pub struct GetPoolArgs { + /// Id of the pool. + pool_id: PoolId, + /// Show the labels of the pool. + #[clap(long, default_value = "false")] + show_labels: bool, +} + +impl GetPoolArgs { + /// Return the pool ID. + pub fn pool_id(&self) -> PoolId { + self.pool_id.clone() + } + /// Return whether to show the labels of the pool. + pub fn show_labels(&self) -> bool { + self.show_labels + } +} + /// Arguments used when getting pools. #[derive(Debug, Clone, clap::Args)] pub struct GetPoolsArgs { @@ -84,6 +108,10 @@ pub struct GetPoolsArgs { /// Pools must satisfy all of the specified label constraints. #[clap(short = 'l', long)] selector: Option, + + /// Show the labels of the pool. + #[clap(long, default_value = "false")] + show_labels: bool, } impl GetPoolsArgs { @@ -101,6 +129,11 @@ impl GetPoolsArgs { pub fn selector(&self) -> &Option { &self.selector } + + /// Return whether to show the labels of the pool. + pub fn show_labels(&self) -> bool { + self.show_labels + } } #[async_trait(?Send)] @@ -133,7 +166,17 @@ impl ListWithArgs for Pools { }, None => true, }); - utils::print_table(output, pools); + + let pools_display = PoolDisplay::new_pools(pools.clone(), args.show_labels()); + match output { + OutputFormat::Yaml | OutputFormat::Json => { + print_table(output, pools_display.inner); + } + OutputFormat::None => { + print_table(output, pools_display); + } + } + Ok(()) } } @@ -143,14 +186,22 @@ impl ListWithArgs for Pools { pub struct Pool {} #[async_trait(?Send)] -impl Get for Pool { +impl GetWithArgs for Pool { type ID = PoolId; - async fn get(id: &Self::ID, output: &utils::OutputFormat) -> PluginResult { + type Args = GetPoolArgs; + async fn get(id: &Self::ID, args: &Self::Args, output: &utils::OutputFormat) -> PluginResult { match RestClient::client().pools_api().get_pool(id).await { - Ok(pool) => { - // Print table, json or yaml based on output format. - utils::print_table(output, pool.into_body()); - } + Ok(pool) => match output { + OutputFormat::Yaml | OutputFormat::Json => { + print_table(output, pool.clone().into_body()); + } + OutputFormat::None => { + print_table( + output, + PoolDisplay::new(pool.into_body(), args.show_labels()), + ); + } + }, Err(e) => { return Err(Error::GetPoolError { id: id.to_string(), @@ -279,3 +330,81 @@ impl Label for Pool { Ok(()) } } + +/// The PoolDisplay structure is responsible for controlling the display formatting of Pool +/// objects. `#[serde(flatten)]` and `#[serde(skip)]` attributes are used to ensure that when the +/// object is serialised, only the `inner` object is represented. +#[derive(Serialize, Debug)] +pub struct PoolDisplay { + #[serde(flatten)] + pub inner: Vec, + #[serde(skip)] + show_labels: bool, +} + +impl PoolDisplay { + /// Create a new `PoolDisplay` instance. + pub(crate) fn new(pool: openapi::models::Pool, show_labels: bool) -> Self { + let vec: Vec = vec![pool]; + Self { + inner: vec, + show_labels, + } + } + /// Create a new `PoolDisplay` instance from a vector of pools. + pub(crate) fn new_pools(pools: Vec, show_labels: bool) -> Self { + Self { + inner: pools, + show_labels, + } + } + + /// Get a list of pool labels. + pub(crate) fn pool_label_list(pool: &openapi::models::Pool) -> Vec { + let mut pools_labels: Vec = vec![]; + let internal_label = external_utils::dsp_created_by_key(); + + match &pool.spec { + Some(spec) => match &spec.labels { + Some(ds) => { + pools_labels = ds + .iter() + // Dont return the created_by_dsp label for the gets + .filter(|(key, _)| *key != &internal_label) + .map(|(key, value)| format!("{}={}", key, value)) + .collect(); + } + None => {} + }, + None => {} + } + pools_labels + } +} + +// Create the header for a `PoolDisplay` object. +impl GetHeaderRow for PoolDisplay { + fn get_header_row(&self) -> Row { + let mut header = (*utils::POOLS_HEADERS).clone(); + if self.show_labels { + header.extend(vec!["LABELS"]); + } + header + } +} + +impl CreateRows for PoolDisplay { + fn create_rows(&self) -> Vec { + let mut rows = vec![]; + for pool in self.inner.iter() { + let mut row = pool.row(); + if self.show_labels { + let labelstring = PoolDisplay::pool_label_list(pool).join(", "); + // Add the pool labels to each row. + row.add_cell(Cell::new(&labelstring)); + } + rows.push(row); + } + rows + } +}