feat: scrape targets to be able to get snmp alerts from machines to prometheus #171
@ -21,6 +21,7 @@ pub struct AlertingInterpret<S: AlertSender> {
|
|||||||
pub sender: S,
|
pub sender: S,
|
||||||
pub receivers: Vec<Box<dyn AlertReceiver<S>>>,
|
pub receivers: Vec<Box<dyn AlertReceiver<S>>>,
|
||||||
pub rules: Vec<Box<dyn AlertRule<S>>>,
|
pub rules: Vec<Box<dyn AlertRule<S>>>,
|
||||||
|
pub scrape_targets: Option<Vec<Box<dyn ScrapeTarget<S>>>>,
|
||||||
letian marked this conversation as resolved
Outdated
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -38,6 +39,12 @@ impl<S: AlertSender + Installable<T>, T: Topology> Interpret<T> for AlertingInte
|
|||||||
debug!("installing rule: {:#?}", rule);
|
debug!("installing rule: {:#?}", rule);
|
||||||
rule.install(&self.sender).await?;
|
rule.install(&self.sender).await?;
|
||||||
}
|
}
|
||||||
|
if let Some(targets) = &self.scrape_targets {
|
||||||
|
for target in targets.iter() {
|
||||||
|
debug!("installing scrape_target: {:#?}", target);
|
||||||
|
target.install(&self.sender).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
self.sender.ensure_installed(inventory, topology).await?;
|
self.sender.ensure_installed(inventory, topology).await?;
|
||||||
Ok(Outcome::success(format!(
|
Ok(Outcome::success(format!(
|
||||||
"successfully installed alert sender {}",
|
"successfully installed alert sender {}",
|
||||||
@ -77,6 +84,6 @@ pub trait AlertRule<S: AlertSender>: std::fmt::Debug + Send + Sync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait ScrapeTarget<S: AlertSender> {
|
pub trait ScrapeTarget<S: AlertSender>: std::fmt::Debug + Send + Sync {
|
||||||
async fn install(&self, sender: &S) -> Result<(), InterpretError>;
|
async fn install(&self, sender: &S) -> Result<Outcome, InterpretError>;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,187 @@
|
|||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use kube::CustomResource;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
modules::monitoring::kube_prometheus::crd::{
|
||||||
|
crd_alertmanager_config::CRDPrometheus, crd_prometheuses::LabelSelector,
|
||||||
|
},
|
||||||
|
topology::oberservability::monitoring::ScrapeTarget,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(CustomResource, Serialize, Deserialize, Debug, Clone, JsonSchema)]
|
||||||
|
#[kube(
|
||||||
|
group = "monitoring.coreos.com",
|
||||||
|
version = "v1alpha1",
|
||||||
|
kind = "ScrapeConfig",
|
||||||
|
plural = "scrapeconfigs",
|
||||||
|
namespaced
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ScrapeConfigSpec {
|
||||||
|
/// List of static configurations.
|
||||||
|
pub static_configs: Option<Vec<StaticConfig>>,
|
||||||
|
|
||||||
|
/// Kubernetes service discovery.
|
||||||
|
pub kubernetes_sd_configs: Option<Vec<KubernetesSDConfig>>,
|
||||||
|
|
||||||
|
/// HTTP-based service discovery.
|
||||||
|
pub http_sd_configs: Option<Vec<HttpSDConfig>>,
|
||||||
|
|
||||||
|
/// File-based service discovery.
|
||||||
|
pub file_sd_configs: Option<Vec<FileSDConfig>>,
|
||||||
|
|
||||||
|
/// DNS-based service discovery.
|
||||||
|
pub dns_sd_configs: Option<Vec<DnsSDConfig>>,
|
||||||
|
|
||||||
|
/// Consul service discovery.
|
||||||
|
pub consul_sd_configs: Option<Vec<ConsulSDConfig>>,
|
||||||
|
|
||||||
|
/// Relabeling configuration applied to discovered targets.
|
||||||
|
pub relabel_configs: Option<Vec<RelabelConfig>>,
|
||||||
|
|
||||||
|
/// Metric relabeling configuration applied to scraped samples.
|
||||||
|
pub metric_relabel_configs: Option<Vec<RelabelConfig>>,
|
||||||
|
|
||||||
|
/// Path to scrape metrics from (defaults to `/metrics`).
|
||||||
|
pub metrics_path: Option<String>,
|
||||||
|
|
||||||
|
/// Interval at which Prometheus scrapes targets (e.g., "30s").
|
||||||
|
pub scrape_interval: Option<String>,
|
||||||
|
|
||||||
|
/// Timeout for scraping (e.g., "10s").
|
||||||
|
pub scrape_timeout: Option<String>,
|
||||||
|
|
||||||
|
/// Optional job name override.
|
||||||
|
pub job_name: Option<String>,
|
||||||
|
|
||||||
|
/// Optional scheme (http or https).
|
||||||
|
pub scheme: Option<String>,
|
||||||
|
|
||||||
|
/// Authorization paramaters for snmp walk
|
||||||
|
pub params: Option<Params>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Static configuration section of a ScrapeConfig.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct StaticConfig {
|
||||||
|
pub targets: Vec<String>,
|
||||||
|
|
||||||
|
pub labels: Option<LabelSelector>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Relabeling configuration for target or metric relabeling.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RelabelConfig {
|
||||||
|
pub source_labels: Option<Vec<String>>,
|
||||||
|
pub separator: Option<String>,
|
||||||
|
pub target_label: Option<String>,
|
||||||
|
pub regex: Option<String>,
|
||||||
|
pub modulus: Option<u64>,
|
||||||
|
pub replacement: Option<String>,
|
||||||
|
pub action: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Kubernetes service discovery configuration.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct KubernetesSDConfig {
|
||||||
|
///"pod", "service", "endpoints"pub role: String,
|
||||||
|
pub namespaces: Option<NamespaceSelector>,
|
||||||
|
pub selectors: Option<Vec<LabelSelector>>,
|
||||||
|
pub api_server: Option<String>,
|
||||||
|
pub bearer_token_file: Option<String>,
|
||||||
|
pub tls_config: Option<TLSConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Namespace selector for Kubernetes service discovery.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct NamespaceSelector {
|
||||||
|
pub any: Option<bool>,
|
||||||
|
pub match_names: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// HTTP-based service discovery configuration.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct HttpSDConfig {
|
||||||
|
pub url: String,
|
||||||
|
pub refresh_interval: Option<String>,
|
||||||
|
pub basic_auth: Option<BasicAuth>,
|
||||||
|
pub authorization: Option<Authorization>,
|
||||||
|
pub tls_config: Option<TLSConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// File-based service discovery configuration.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct FileSDConfig {
|
||||||
|
pub files: Vec<String>,
|
||||||
|
pub refresh_interval: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// DNS-based service discovery configuration.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DnsSDConfig {
|
||||||
|
pub names: Vec<String>,
|
||||||
|
pub refresh_interval: Option<String>,
|
||||||
|
pub type_: Option<String>, // SRV, A, AAAA
|
||||||
|
pub port: Option<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consul service discovery configuration.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ConsulSDConfig {
|
||||||
|
pub server: String,
|
||||||
|
pub services: Option<Vec<String>>,
|
||||||
|
pub scheme: Option<String>,
|
||||||
|
pub datacenter: Option<String>,
|
||||||
|
pub tag_separator: Option<String>,
|
||||||
|
pub refresh_interval: Option<String>,
|
||||||
|
pub tls_config: Option<TLSConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Basic authentication credentials.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct BasicAuth {
|
||||||
|
pub username: String,
|
||||||
|
pub password: Option<String>,
|
||||||
|
pub password_file: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bearer token or other auth mechanisms.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Authorization {
|
||||||
|
pub credentials: Option<String>,
|
||||||
|
pub credentials_file: Option<String>,
|
||||||
|
pub type_: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TLS configuration for secure scraping.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct TLSConfig {
|
||||||
|
pub ca_file: Option<String>,
|
||||||
|
pub cert_file: Option<String>,
|
||||||
|
pub key_file: Option<String>,
|
||||||
|
pub server_name: Option<String>,
|
||||||
|
pub insecure_skip_verify: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Authorization parameters for SNMP walk.
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Params {
|
||||||
|
pub auth: Option<Vec<String>>,
|
||||||
|
pub module: Option<Vec<String>>,
|
||||||
|
}
|
@ -4,6 +4,7 @@ pub mod crd_default_rules;
|
|||||||
pub mod crd_grafana;
|
pub mod crd_grafana;
|
||||||
pub mod crd_prometheus_rules;
|
pub mod crd_prometheus_rules;
|
||||||
pub mod crd_prometheuses;
|
pub mod crd_prometheuses;
|
||||||
|
pub mod crd_scrape_config;
|
||||||
pub mod grafana_default_dashboard;
|
pub mod grafana_default_dashboard;
|
||||||
pub mod grafana_operator;
|
pub mod grafana_operator;
|
||||||
pub mod prometheus_operator;
|
pub mod prometheus_operator;
|
||||||
|
@ -31,6 +31,7 @@ impl<T: Topology + HelmCommand + TenantManager> Score<T> for HelmPrometheusAlert
|
|||||||
sender: KubePrometheus { config },
|
sender: KubePrometheus { config },
|
||||||
receivers: self.receivers.clone(),
|
receivers: self.receivers.clone(),
|
||||||
rules: self.rules.clone(),
|
rules: self.rules.clone(),
|
||||||
|
scrape_targets: None,
|
||||||
letian marked this conversation as resolved
Outdated
letian
commented
Should we actually configure something here? Because we pass an empty list it doesn't seem used. Should we actually configure something here? Because we pass an empty list it doesn't seem used.
wjro
commented
I will make this an Option<Vec> since it is not used in this score I will make this an Option<Vec<ScrapeTarget>> since it is not used in this score
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
|
@ -6,3 +6,4 @@ pub mod kube_prometheus;
|
|||||||
pub mod ntfy;
|
pub mod ntfy;
|
||||||
pub mod okd;
|
pub mod okd;
|
||||||
pub mod prometheus;
|
pub mod prometheus;
|
||||||
|
pub mod scrape_target;
|
||||||
|
1
harmony/src/modules/monitoring/scrape_target/mod.rs
Normal file
1
harmony/src/modules/monitoring/scrape_target/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod server;
|
76
harmony/src/modules/monitoring/scrape_target/server.rs
Normal file
76
harmony/src/modules/monitoring/scrape_target/server.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use kube::api::ObjectMeta;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
interpret::{InterpretError, Outcome},
|
||||||
|
modules::monitoring::kube_prometheus::crd::{
|
||||||
|
crd_alertmanager_config::CRDPrometheus,
|
||||||
|
crd_scrape_config::{Params, RelabelConfig, ScrapeConfig, ScrapeConfigSpec, StaticConfig},
|
||||||
|
},
|
||||||
|
topology::oberservability::monitoring::ScrapeTarget,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct Server {
|
||||||
|
pub name: String,
|
||||||
|
pub ip: IpAddr,
|
||||||
|
pub auth: String,
|
||||||
|
pub module: String,
|
||||||
|
pub domain: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ScrapeTarget<CRDPrometheus> for Server {
|
||||||
|
async fn install(&self, sender: &CRDPrometheus) -> Result<Outcome, InterpretError> {
|
||||||
|
let scrape_config_spec = ScrapeConfigSpec {
|
||||||
|
static_configs: Some(vec![StaticConfig {
|
||||||
|
targets: vec![self.ip.to_string()],
|
||||||
|
labels: None,
|
||||||
|
}]),
|
||||||
|
scrape_interval: Some("2m".to_string()),
|
||||||
|
kubernetes_sd_configs: None,
|
||||||
|
http_sd_configs: None,
|
||||||
|
file_sd_configs: None,
|
||||||
|
dns_sd_configs: None,
|
||||||
|
params: Some(Params {
|
||||||
|
auth: Some(vec![self.auth.clone()]),
|
||||||
|
module: Some(vec![self.module.clone()]),
|
||||||
|
}),
|
||||||
|
consul_sd_configs: None,
|
||||||
|
relabel_configs: Some(vec![RelabelConfig {
|
||||||
|
action: None,
|
||||||
|
source_labels: Some(vec!["__address__".to_string()]),
|
||||||
|
separator: None,
|
||||||
|
target_label: Some("__param_target".to_string()),
|
||||||
|
regex: None,
|
||||||
|
replacement: Some(format!("snmp.{}:31080", self.domain.clone())),
|
||||||
|
modulus: None,
|
||||||
|
}]),
|
||||||
|
metric_relabel_configs: None,
|
||||||
|
metrics_path: Some("/snmp".to_string()),
|
||||||
|
scrape_timeout: Some("2m".to_string()),
|
||||||
|
job_name: Some(format!("snmp_exporter/cloud/{}", self.name.clone())),
|
||||||
|
scheme: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let scrape_config = ScrapeConfig {
|
||||||
|
metadata: ObjectMeta {
|
||||||
|
name: Some(self.name.clone()),
|
||||||
|
namespace: Some(sender.namespace.clone()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
spec: scrape_config_spec,
|
||||||
|
};
|
||||||
|
sender
|
||||||
|
.client
|
||||||
|
.apply(&scrape_config, Some(&sender.namespace.clone()))
|
||||||
|
.await?;
|
||||||
|
Ok(Outcome::success(format!(
|
||||||
|
"installed scrape target {}",
|
||||||
|
self.name.clone()
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user
Should it be
scrape_targets
? as it's a vector