feat: scrape targets to be able to get snmp alerts from machines to prometheus
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Run Check Script / check (pull_request) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Run Check Script / check (pull_request) Has been cancelled
				
			This commit is contained in:
		
							parent
							
								
									2d891e4463
								
							
						
					
					
						commit
						a815f6ac9c
					
				| @ -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_target: Vec<Box<dyn ScrapeTarget<S>>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[async_trait] | #[async_trait] | ||||||
| @ -38,6 +39,10 @@ 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?; | ||||||
|         } |         } | ||||||
|  |         for target in self.scrape_target.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 +82,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_target: vec![], | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|     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