use anyhow::Result as AnyhowResult;
use serde_json::Value;
use crate::cli::OutputFormat;
use crate::connection::ConnectionManager;
use crate::error::RedisCtlError;
pub async fn list_alerts(
conn_mgr: &ConnectionManager,
profile_name: Option<&str>,
filter_type: Option<&str>,
severity: Option<&str>,
output_format: OutputFormat,
query: Option<&str>,
) -> AnyhowResult<()> {
let client = conn_mgr.create_enterprise_client(profile_name).await?;
let mut all_alerts = Vec::new();
if (filter_type.is_none() || filter_type == Some("cluster"))
&& let Ok(cluster_alerts) = client.get::<Value>("/v1/cluster/alerts").await
&& let Some(alerts) = cluster_alerts.as_array()
{
for alert in alerts {
let mut alert = alert.clone();
if let Some(obj) = alert.as_object_mut() {
obj.insert("type".to_string(), Value::String("cluster".to_string()));
}
all_alerts.push(alert);
}
}
if (filter_type.is_none() || filter_type == Some("node"))
&& let Ok(node_alerts) = client.get::<Value>("/v1/nodes/alerts").await
&& let Some(alerts) = node_alerts.as_array()
{
for alert in alerts {
let mut alert = alert.clone();
if let Some(obj) = alert.as_object_mut() {
obj.insert("type".to_string(), Value::String("node".to_string()));
}
all_alerts.push(alert);
}
}
if (filter_type.is_none() || filter_type == Some("bdb"))
&& let Ok(bdb_alerts) = client.get::<Value>("/v1/bdbs/alerts").await
&& let Some(alerts) = bdb_alerts.as_array()
{
for alert in alerts {
let mut alert = alert.clone();
if let Some(obj) = alert.as_object_mut() {
obj.insert("type".to_string(), Value::String("database".to_string()));
}
all_alerts.push(alert);
}
}
if let Some(severity) = severity {
all_alerts.retain(|alert| {
alert
.get("severity")
.and_then(|s| s.as_str())
.map(|s| s.eq_ignore_ascii_case(severity))
.unwrap_or(false)
});
}
let response = Value::Array(all_alerts);
let response = if let Some(q) = query {
super::utils::apply_jmespath(&response, q)?
} else {
response
};
super::utils::print_formatted_output(response, output_format).map_err(|e| anyhow::anyhow!(e))
}
pub async fn get_alert(
conn_mgr: &ConnectionManager,
profile_name: Option<&str>,
uid: u64,
output_format: OutputFormat,
query: Option<&str>,
) -> AnyhowResult<()> {
let client = conn_mgr.create_enterprise_client(profile_name).await?;
if let Ok(alerts) = client
.get::<Value>(&format!("/v1/cluster/alerts/{}", uid))
.await
{
let response = if let Some(q) = query {
super::utils::apply_jmespath(&alerts, q)?
} else {
alerts
};
return super::utils::print_formatted_output(response, output_format)
.map_err(|e| anyhow::anyhow!(e));
}
if let Ok(alerts) = client
.get::<Value>(&format!("/v1/nodes/alerts/{}", uid))
.await
{
let response = if let Some(q) = query {
super::utils::apply_jmespath(&alerts, q)?
} else {
alerts
};
return super::utils::print_formatted_output(response, output_format)
.map_err(|e| anyhow::anyhow!(e));
}
if let Ok(alerts) = client
.get::<Value>(&format!("/v1/bdbs/alerts/{}", uid))
.await
{
let response = if let Some(q) = query {
super::utils::apply_jmespath(&alerts, q)?
} else {
alerts
};
return super::utils::print_formatted_output(response, output_format)
.map_err(|e| anyhow::anyhow!(e));
}
anyhow::bail!("Alert with UID {} not found", uid)
}
pub async fn cluster_alerts(
conn_mgr: &ConnectionManager,
profile_name: Option<&str>,
alert: Option<&str>,
output_format: OutputFormat,
query: Option<&str>,
) -> AnyhowResult<()> {
let client = conn_mgr.create_enterprise_client(profile_name).await?;
let endpoint = if let Some(alert_name) = alert {
format!("/v1/cluster/alerts/{}", alert_name)
} else {
"/v1/cluster/alerts".to_string()
};
let response = client
.get::<Value>(&endpoint)
.await
.map_err(RedisCtlError::from)?;
let response = if let Some(q) = query {
super::utils::apply_jmespath(&response, q)?
} else {
response
};
super::utils::print_formatted_output(response, output_format).map_err(|e| anyhow::anyhow!(e))
}
pub async fn node_alerts(
conn_mgr: &ConnectionManager,
profile_name: Option<&str>,
node_uid: Option<u64>,
alert: Option<&str>,
output_format: OutputFormat,
query: Option<&str>,
) -> AnyhowResult<()> {
let client = conn_mgr.create_enterprise_client(profile_name).await?;
let endpoint = match (node_uid, alert) {
(Some(uid), Some(alert_name)) => format!("/v1/nodes/alerts/{}/{}", uid, alert_name),
(Some(uid), None) => format!("/v1/nodes/alerts/{}", uid),
(None, None) => "/v1/nodes/alerts".to_string(),
(None, Some(_)) => anyhow::bail!("Cannot specify alert without node_uid"),
};
let response = client
.get::<Value>(&endpoint)
.await
.map_err(RedisCtlError::from)?;
let response = if let Some(q) = query {
super::utils::apply_jmespath(&response, q)?
} else {
response
};
super::utils::print_formatted_output(response, output_format).map_err(|e| anyhow::anyhow!(e))
}
pub async fn database_alerts(
conn_mgr: &ConnectionManager,
profile_name: Option<&str>,
bdb_uid: Option<u64>,
alert: Option<&str>,
output_format: OutputFormat,
query: Option<&str>,
) -> AnyhowResult<()> {
let client = conn_mgr.create_enterprise_client(profile_name).await?;
let endpoint = match (bdb_uid, alert) {
(Some(uid), Some(alert_name)) => format!("/v1/bdbs/alerts/{}/{}", uid, alert_name),
(Some(uid), None) => format!("/v1/bdbs/alerts/{}", uid),
(None, None) => "/v1/bdbs/alerts".to_string(),
(None, Some(_)) => anyhow::bail!("Cannot specify alert without bdb_uid"),
};
let response = client
.get::<Value>(&endpoint)
.await
.map_err(RedisCtlError::from)?;
let response = if let Some(q) = query {
super::utils::apply_jmespath(&response, q)?
} else {
response
};
super::utils::print_formatted_output(response, output_format).map_err(|e| anyhow::anyhow!(e))
}
pub async fn get_alert_settings(
conn_mgr: &ConnectionManager,
profile_name: Option<&str>,
output_format: OutputFormat,
query: Option<&str>,
) -> AnyhowResult<()> {
let client = conn_mgr.create_enterprise_client(profile_name).await?;
let response = client
.get::<Value>("/v1/cluster")
.await
.map_err(RedisCtlError::from)?;
let alert_settings = response
.get("alert_settings")
.cloned()
.unwrap_or_else(|| Value::Object(serde_json::Map::new()));
let response = if let Some(q) = query {
super::utils::apply_jmespath(&alert_settings, q)?
} else {
alert_settings
};
super::utils::print_formatted_output(response, output_format).map_err(|e| anyhow::anyhow!(e))
}
#[allow(clippy::too_many_arguments)]
pub async fn update_alert_settings(
conn_mgr: &ConnectionManager,
profile_name: Option<&str>,
cluster_alerts: Option<bool>,
node_alerts: Option<bool>,
bdb_alerts: Option<bool>,
memory_threshold: Option<u32>,
cpu_threshold: Option<u32>,
data: Option<&str>,
output_format: OutputFormat,
query: Option<&str>,
) -> AnyhowResult<()> {
let client = conn_mgr.create_enterprise_client(profile_name).await?;
let mut json_data = if let Some(data_str) = data {
super::utils::read_json_data(data_str)?
} else {
serde_json::json!({})
};
let data_obj = json_data.as_object_mut().unwrap();
if let Some(ca) = cluster_alerts {
data_obj.insert("cluster_alerts_enabled".to_string(), serde_json::json!(ca));
}
if let Some(na) = node_alerts {
data_obj.insert("node_alerts_enabled".to_string(), serde_json::json!(na));
}
if let Some(ba) = bdb_alerts {
data_obj.insert("bdb_alerts_enabled".to_string(), serde_json::json!(ba));
}
if let Some(mt) = memory_threshold {
data_obj.insert("memory_threshold".to_string(), serde_json::json!(mt));
}
if let Some(ct) = cpu_threshold {
data_obj.insert("cpu_threshold".to_string(), serde_json::json!(ct));
}
let update_payload = serde_json::json!({
"alert_settings": json_data
});
let response = client
.put::<_, Value>("/v1/cluster", &update_payload)
.await
.map_err(RedisCtlError::from)?;
let response = if let Some(q) = query {
super::utils::apply_jmespath(&response, q)?
} else {
response
};
super::utils::print_formatted_output(response, output_format).map_err(|e| anyhow::anyhow!(e))
}