Skip to content

Commit

Permalink
Support listing analytics clusters
Browse files Browse the repository at this point in the history
  • Loading branch information
Westwooo committed Oct 4, 2024
1 parent 99ebfb5 commit 92c7422
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 17 deletions.
143 changes: 143 additions & 0 deletions src/cli/analytics_clusters.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use crate::cli::client_error_to_shell_error;
use crate::cli::util::{convert_json_value_to_nu_value, find_org_id, find_project_id, NuValueMap};
use crate::state::State;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
Category, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
};
use std::sync::{Arc, Mutex};

#[derive(Clone)]
pub struct AnalyticsClusters {
state: Arc<Mutex<State>>,
}

impl AnalyticsClusters {
pub fn new(state: Arc<Mutex<State>>) -> Self {
Self { state }
}
}

impl Command for AnalyticsClusters {
fn name(&self) -> &str {
"analytics clusters"
}

fn signature(&self) -> Signature {
Signature::build("analytics clusters")
.named(
"organization",
SyntaxShape::String,
"the Capella organization to use",
None,
)
.named(
"project",
SyntaxShape::String,
"the Capella project to use",
None,
)
.switch("details", "return analytics clusters details", None)
.category(Category::Custom("couchbase".to_string()))
}

fn usage(&self) -> &str {
"Lists all analytics clusters in the active Capella project"
}

fn run(
&self,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
analytics_clusters(self.state.clone(), engine_state, stack, call, input)
}
}

fn analytics_clusters(
state: Arc<Mutex<State>>,
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let span = call.head;
let guard = state.lock().unwrap();
let ctrl_c = engine_state.ctrlc.as_ref().unwrap().clone();

let control =
guard.named_or_active_org(call.get_flag(engine_state, stack, "organization")?)?;

let project =
guard.named_or_active_project(call.get_flag(engine_state, stack, "project")?)?;
let client = control.client();

let org_id = find_org_id(ctrl_c.clone(), &client, span)?;
let project_id = find_project_id(ctrl_c.clone(), project, &client, span, org_id.clone())?;

let analytics_clusters = client
.list_analytics_clusters(org_id, project_id, ctrl_c)
.map_err(|e| client_error_to_shell_error(e, span))?;

let detail = call.has_flag(engine_state, stack, "details")?;

let mut results = vec![];
for cluster in analytics_clusters.items() {
let mut collected = NuValueMap::default();
collected.add_string("name", cluster.name(), span);
collected.add_string("id", cluster.id(), span);
collected.add_string("state", cluster.state(), span);
collected.add_i64("number of nodes", cluster.nodes(), span);
collected.add(
"cloud provider",
convert_json_value_to_nu_value(
&serde_json::to_value(cluster.cloud_provider()).unwrap(),
span,
)
.unwrap(),
);

if detail {
if !cluster.description().is_empty() {
collected.add_string("description", cluster.description(), span);
}

collected.add(
"compute",
convert_json_value_to_nu_value(
&serde_json::to_value(cluster.compute()).unwrap(),
span,
)
.unwrap(),
);
collected.add(
"availability",
convert_json_value_to_nu_value(
&serde_json::to_value(cluster.availability()).unwrap(),
span,
)
.unwrap(),
);
collected.add(
"support",
convert_json_value_to_nu_value(
&serde_json::to_value(cluster.support()).unwrap(),
span,
)
.unwrap(),
);
}

results.push(collected.into_value(span))
}

Ok(Value::List {
vals: results,
internal_span: span,
}
.into_pipeline_data())
}
13 changes: 9 additions & 4 deletions src/cli/clusters_get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ use std::sync::{Arc, Mutex};

use crate::cli::error::client_error_to_shell_error;
use crate::cli::util::{convert_json_value_to_nu_value, find_org_id, find_project_id, NuValueMap};
use crate::client::cloud_json::Cluster;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, PipelineData, ShellError, Signature, SyntaxShape};
use nu_protocol::{Category, PipelineData, ShellError, Signature, Span, SyntaxShape};

#[derive(Clone)]
pub struct ClustersGet {
Expand Down Expand Up @@ -85,10 +86,16 @@ fn clusters_get(
let project_id = find_project_id(ctrl_c.clone(), project, &client, span, org_id.clone())?;

let cluster = client
.get_cluster(name, org_id.clone(), project_id.clone(), ctrl_c.clone())
.get_cluster(name, org_id, project_id, ctrl_c)
.map_err(|e| client_error_to_shell_error(e, span))?;

let mut collected = NuValueMap::default();
add_cluster_info(cluster, span, &mut collected);

Ok(collected.into_pipeline_data(span))
}

fn add_cluster_info(cluster: Cluster, span: Span, collected: &mut NuValueMap) {
collected.add_string("name", cluster.name(), span);
collected.add_string("id", cluster.id(), span);
collected.add_string("description", cluster.description(), span);
Expand Down Expand Up @@ -144,6 +151,4 @@ fn clusters_get(
if let Some(cmek_id) = cluster.cmek_id() {
collected.add_string("cmek id", cmek_id, span);
}

Ok(collected.into_pipeline_data(span))
}
2 changes: 2 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod allow_ip;
mod analytics;
mod analytics_buckets;
mod analytics_clusters;
mod analytics_datasets;
mod analytics_dataverses;
mod analytics_indexes;
Expand Down Expand Up @@ -87,6 +88,7 @@ mod version;
pub use allow_ip::AllowIP;
pub use analytics::Analytics;
pub use analytics_buckets::AnalyticsBuckets;
pub use analytics_clusters::AnalyticsClusters;
pub use analytics_datasets::AnalyticsDatasets;
pub use analytics_dataverses::AnalyticsDataverses;
pub use analytics_indexes::AnalyticsIndexes;
Expand Down
47 changes: 34 additions & 13 deletions src/client/cloud.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::cli::CtrlcFuture;
use crate::client::cloud_json::{
Bucket, BucketsResponse, Cluster, ClustersResponse, Collection, CollectionsResponse,
OrganizationsResponse, ProjectsResponse, ScopesResponse,
AnalyticsClusterResponse, Bucket, BucketsResponse, Cluster, ClustersResponse, Collection,
CollectionsResponse, OrganizationsResponse, ProjectsResponse, ScopesResponse,
};
use crate::client::error::ClientError;
use crate::client::http_handler::{HttpResponse, HttpVerb};
Expand Down Expand Up @@ -258,17 +258,7 @@ impl CapellaClient {
project_id: String,
ctrl_c: Arc<AtomicBool>,
) -> Result<Cluster, ClientError> {
let request = CapellaRequest::ClusterList { org_id, project_id };
let response = self.capella_request(request, ctrl_c)?;

if response.status() != 200 {
return Err(ClientError::RequestFailed {
reason: Some(response.content().into()),
key: None,
});
}

let resp: ClustersResponse = serde_json::from_str(response.content())?;
let resp = self.list_clusters(org_id, project_id, ctrl_c)?;

for c in resp.items() {
if c.name() == cluster_name {
Expand Down Expand Up @@ -345,6 +335,26 @@ impl CapellaClient {
Ok(())
}

pub fn list_analytics_clusters(
&self,
org_id: String,
project_id: String,
ctrl_c: Arc<AtomicBool>,
) -> Result<AnalyticsClusterResponse, ClientError> {
let request = CapellaRequest::AnalyticsClusterList { org_id, project_id };
let response = self.capella_request(request, ctrl_c)?;

if response.status() != 200 {
return Err(ClientError::RequestFailed {
reason: Some(response.content().into()),
key: None,
});
}

let resp: AnalyticsClusterResponse = serde_json::from_str(response.content())?;
Ok(resp)
}

pub fn create_credentials(
&self,
org_id: String,
Expand Down Expand Up @@ -754,6 +764,10 @@ pub enum CapellaRequest {
org_id: String,
project_id: String,
},
AnalyticsClusterList {
org_id: String,
project_id: String,
},
BucketCreate {
org_id: String,
project_id: String,
Expand Down Expand Up @@ -899,6 +913,12 @@ impl CapellaRequest {
org_id, project_id
)
}
Self::AnalyticsClusterList { org_id, project_id } => {
format!(
"/v4/organizations/{}/projects/{}/analyticsClusters",
org_id, project_id
)
}
Self::BucketCreate {
org_id,
project_id,
Expand Down Expand Up @@ -1062,6 +1082,7 @@ impl CapellaRequest {
Self::ClusterDelete { .. } => HttpVerb::Delete,
Self::ClusterGet { .. } => HttpVerb::Get,
Self::ClusterList { .. } => HttpVerb::Get,
Self::AnalyticsClusterList { .. } => HttpVerb::Get,
Self::BucketCreate { .. } => HttpVerb::Post,
Self::BucketDelete { .. } => HttpVerb::Delete,
Self::BucketGet { .. } => HttpVerb::Get,
Expand Down
60 changes: 60 additions & 0 deletions src/client/cloud_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,66 @@ impl Cluster {
}
}

#[derive(Debug, Deserialize)]
pub(crate) struct AnalyticsClusterResponse {
data: Vec<AnalyticsCluster>,
}

impl AnalyticsClusterResponse {
pub fn items(&self) -> Vec<AnalyticsCluster> {
self.data.clone()
}
}

#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct AnalyticsCluster {
id: String,
description: String,
name: String,
cloud_provider: String,
region: String,
nodes: i64,
current_state: String,
support: Support,
compute: Compute,
availability: Availability,
}

impl AnalyticsCluster {
pub fn id(&self) -> String {
self.id.clone()
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn state(&self) -> String {
self.current_state.clone()
}
pub fn description(&self) -> String {
self.description.clone()
}
pub fn cloud_provider(&self) -> CloudProvider {
CloudProvider {
provider: self.cloud_provider.to_lowercase().clone(),
region: self.region.clone(),
cidr: None,
}
}
pub fn availability(&self) -> &Availability {
&self.availability
}
pub fn compute(&self) -> Compute {
self.compute.clone()
}
pub fn support(&self) -> &Support {
&self.support
}
pub fn nodes(&self) -> i64 {
self.nodes
}
}

#[derive(Debug, Deserialize)]
pub(crate) struct BucketsResponse {
data: Vec<Bucket>,
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,7 @@ fn merge_couchbase_delta(context: &mut EngineState, state: Arc<Mutex<State>>) {
working_set.add_decl(Box::new(AllowIP::new(state.clone())));
working_set.add_decl(Box::new(Analytics::new(state.clone())));
working_set.add_decl(Box::new(AnalyticsBuckets::new(state.clone())));
working_set.add_decl(Box::new(AnalyticsClusters::new(state.clone())));
working_set.add_decl(Box::new(AnalyticsDatasets::new(state.clone())));
working_set.add_decl(Box::new(AnalyticsDataverses::new(state.clone())));
working_set.add_decl(Box::new(AnalyticsIndexes::new(state.clone())));
Expand Down

0 comments on commit 92c7422

Please sign in to comment.